MagickCore 7.1.2
Convert, Edit, Or Compose Bitmap Images
Loading...
Searching...
No Matches
image.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% IIIII M M AAA GGGG EEEEE %
7% I MM MM A A G E %
8% I M M M AAAAA G GG EEE %
9% I M M A A G G E %
10% IIIII M M A A GGGG EEEEE %
11% %
12% %
13% MagickCore Image Methods %
14% %
15% Software Design %
16% Cristy %
17% July 1992 %
18% %
19% %
20% Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21% 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% https://imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "MagickCore/studio.h"
44#include "MagickCore/animate.h"
45#include "MagickCore/artifact.h"
46#include "MagickCore/attribute.h"
47#include "MagickCore/blob.h"
48#include "MagickCore/blob-private.h"
49#include "MagickCore/cache.h"
50#include "MagickCore/cache-private.h"
51#include "MagickCore/cache-view.h"
52#include "MagickCore/channel.h"
53#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"
63#include "MagickCore/delegate.h"
64#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"
76#include "MagickCore/magick-private.h"
77#include "MagickCore/memory_.h"
78#include "MagickCore/memory-private.h"
79#include "MagickCore/module.h"
80#include "MagickCore/monitor.h"
81#include "MagickCore/monitor-private.h"
82#include "MagickCore/option.h"
83#include "MagickCore/paint.h"
84#include "MagickCore/pixel-accessor.h"
85#include "MagickCore/profile.h"
86#include "MagickCore/property.h"
87#include "MagickCore/quantize.h"
88#include "MagickCore/random_.h"
89#include "MagickCore/resource_.h"
90#include "MagickCore/segment.h"
91#include "MagickCore/semaphore.h"
92#include "MagickCore/signature-private.h"
93#include "MagickCore/statistic.h"
94#include "MagickCore/string_.h"
95#include "MagickCore/string-private.h"
96#include "MagickCore/thread-private.h"
97#include "MagickCore/threshold.h"
98#include "MagickCore/timer.h"
99#include "MagickCore/timer-private.h"
100#include "MagickCore/token.h"
101#include "MagickCore/token-private.h"
102#include "MagickCore/utility.h"
103#include "MagickCore/utility-private.h"
104#include "MagickCore/version.h"
105#include "MagickCore/xwindow-private.h"
106
107/*
108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109% %
110% %
111% %
112% A c q u i r e I m a g e %
113% %
114% %
115% %
116%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117%
118% AcquireImage() returns a pointer to an image structure initialized to
119% default values.
120%
121% The format of the AcquireImage method is:
122%
123% Image *AcquireImage(const ImageInfo *image_info,ExceptionInfo *exception)
124%
125% A description of each parameter follows:
126%
127% o image_info: Many of the image default values are set from this
128% structure. For example, filename, compression, depth, background color,
129% and others.
130%
131% o exception: return any errors or warnings in this structure.
132%
133*/
134MagickExport Image *AcquireImage(const ImageInfo *image_info,
135 ExceptionInfo *exception)
136{
137 const char
138 *option;
139
140 Image
141 *image;
142
143 MagickSizeType
144 time_limit;
145
146 MagickStatusType
147 flags;
148
149 /*
150 Allocate image structure.
151 */
152 if (IsEventLogging() != MagickFalse)
153 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
154 image=(Image *) AcquireCriticalMemory(sizeof(*image));
155 (void) memset(image,0,sizeof(*image));
156 /*
157 Initialize Image structure.
158 */
159 (void) CopyMagickString(image->magick,"MIFF",MagickPathExtent);
160 image->storage_class=DirectClass;
161 image->depth=MAGICKCORE_QUANTUM_DEPTH;
162 image->colorspace=sRGBColorspace;
163 image->rendering_intent=PerceptualIntent;
164 image->gamma=1.000/2.200;
165 image->chromaticity.red_primary.x=0.6400;
166 image->chromaticity.red_primary.y=0.3300;
167 image->chromaticity.red_primary.z=0.0300;
168 image->chromaticity.green_primary.x=0.3000;
169 image->chromaticity.green_primary.y=0.6000;
170 image->chromaticity.green_primary.z=0.1000;
171 image->chromaticity.blue_primary.x=0.1500;
172 image->chromaticity.blue_primary.y=0.0600;
173 image->chromaticity.blue_primary.z=0.7900;
174 image->chromaticity.white_point.x=0.3127;
175 image->chromaticity.white_point.y=0.3290;
176 image->chromaticity.white_point.z=0.3583;
177 image->interlace=NoInterlace;
178 image->ticks_per_second=UndefinedTicksPerSecond;
179 image->compose=OverCompositeOp;
180 GetPixelInfoRGBA(BackgroundColorRGBA,&image->background_color);
181 GetPixelInfoRGBA(BorderColorRGBA,&image->border_color);
182 GetPixelInfoRGBA(MatteColorRGBA,&image->matte_color);
183 GetPixelInfoRGBA(TransparentColorRGBA,&image->transparent_color);
184 GetTimerInfo(&image->timer);
185 image->cache=AcquirePixelCache(0);
186 image->channel_mask=AllChannels;
187 image->channel_map=AcquirePixelChannelMap();
188 image->blob=CloneBlobInfo((BlobInfo *) NULL);
189 image->timestamp=GetMagickTime();
190 time_limit=GetMagickResourceLimit(TimeResource);
191 if (time_limit != MagickResourceInfinity)
192 image->ttl=image->timestamp+(time_t) time_limit;
193 image->debug=(GetLogEventMask() & (ImageEvent | TransformEvent | CoderEvent))
194 != 0 ? MagickTrue : MagickFalse;
195 image->reference_count=1;
196 image->semaphore=AcquireSemaphoreInfo();
197 image->signature=MagickCoreSignature;
198 if (image_info == (ImageInfo *) NULL)
199 return(image);
200 /*
201 Transfer image info.
202 */
203 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
204 MagickFalse);
205 (void) CopyMagickString(image->filename,image_info->filename,
206 MagickPathExtent);
207 (void) CopyMagickString(image->magick_filename,image_info->filename,
208 MagickPathExtent);
209 (void) CopyMagickString(image->magick,image_info->magick,MagickPathExtent);
210 if (image_info->size != (char *) NULL)
211 {
212 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
213 image->columns=image->extract_info.width;
214 image->rows=image->extract_info.height;
215 image->offset=image->extract_info.x;
216 image->extract_info.x=0;
217 image->extract_info.y=0;
218 }
219 if (image_info->extract != (char *) NULL)
220 {
221 RectangleInfo
222 geometry;
223
224 (void) memset(&geometry,0,sizeof(geometry));
225 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
226 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
227 {
228 image->extract_info=geometry;
229 Swap(image->columns,image->extract_info.width);
230 Swap(image->rows,image->extract_info.height);
231 }
232 }
233 image->compression=image_info->compression;
234 image->quality=image_info->quality;
235 image->endian=image_info->endian;
236 image->interlace=image_info->interlace;
237 image->units=image_info->units;
238 if (image_info->density != (char *) NULL)
239 {
240 GeometryInfo
241 geometry_info;
242
243 flags=ParseGeometry(image_info->density,&geometry_info);
244 if ((flags & RhoValue) != 0)
245 image->resolution.x=geometry_info.rho;
246 image->resolution.y=image->resolution.x;
247 if ((flags & SigmaValue) != 0)
248 image->resolution.y=geometry_info.sigma;
249 }
250 if (image_info->page != (char *) NULL)
251 {
252 char
253 *geometry;
254
255 image->page=image->extract_info;
256 geometry=GetPageGeometry(image_info->page);
257 (void) ParseAbsoluteGeometry(geometry,&image->page);
258 geometry=DestroyString(geometry);
259 }
260 if (image_info->depth != 0)
261 image->depth=image_info->depth;
262 image->dither=image_info->dither;
263 image->matte_color=image_info->matte_color;
264 image->background_color=image_info->background_color;
265 image->border_color=image_info->border_color;
266 image->transparent_color=image_info->transparent_color;
267 image->ping=image_info->ping;
268 image->progress_monitor=image_info->progress_monitor;
269 image->client_data=image_info->client_data;
270 if (image_info->cache != (void *) NULL)
271 ClonePixelCacheMethods(image->cache,image_info->cache);
272 /*
273 Set all global options that map to per-image settings.
274 */
275 (void) SyncImageSettings(image_info,image,exception);
276 /*
277 Global options that are only set for new images.
278 */
279 option=GetImageOption(image_info,"delay");
280 if (option != (const char *) NULL)
281 {
282 GeometryInfo
283 geometry_info;
284
285 flags=ParseGeometry(option,&geometry_info);
286 if ((flags & GreaterValue) != 0)
287 {
288 if ((double) image->delay > floor(geometry_info.rho+0.5))
289 image->delay=(size_t) CastDoubleToSsizeT(floor(geometry_info.rho+0.5));
290 }
291 else
292 if ((flags & LessValue) != 0)
293 {
294 if ((double) image->delay < floor(geometry_info.rho+0.5))
295 image->ticks_per_second=CastDoubleToSsizeT(floor(
296 geometry_info.sigma+0.5));
297 }
298 else
299 image->delay=(size_t) CastDoubleToSsizeT(floor(geometry_info.rho+0.5));
300 if ((flags & SigmaValue) != 0)
301 image->ticks_per_second=CastDoubleToSsizeT(floor(geometry_info.sigma+0.5));
302 }
303 option=GetImageOption(image_info,"dispose");
304 if (option != (const char *) NULL)
305 image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
306 MagickFalse,option);
307 return(image);
308}
309
310/*
311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
312% %
313% %
314% %
315% A c q u i r e I m a g e I n f o %
316% %
317% %
318% %
319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320%
321% AcquireImageInfo() allocates the ImageInfo structure.
322%
323% The format of the AcquireImageInfo method is:
324%
325% ImageInfo *AcquireImageInfo(void)
326%
327*/
328MagickExport ImageInfo *AcquireImageInfo(void)
329{
330 ImageInfo
331 *image_info;
332
333 image_info=(ImageInfo *) AcquireCriticalMemory(sizeof(*image_info));
334 GetImageInfo(image_info);
335 return(image_info);
336}
337
338/*
339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340% %
341% %
342% %
343% A c q u i r e N e x t I m a g e %
344% %
345% %
346% %
347%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348%
349% AcquireNextImage() initializes the next image in a sequence to
350% default values. The next member of image points to the newly allocated
351% image. If there is a memory shortage, next is assigned NULL.
352%
353% The format of the AcquireNextImage method is:
354%
355% void AcquireNextImage(const ImageInfo *image_info,Image *image,
356% ExceptionInfo *exception)
357%
358% A description of each parameter follows:
359%
360% o image_info: Many of the image default values are set from this
361% structure. For example, filename, compression, depth, background color,
362% and others.
363%
364% o image: the image.
365%
366% o exception: return any errors or warnings in this structure.
367%
368*/
369MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image,
370 ExceptionInfo *exception)
371{
372 /*
373 Allocate image structure.
374 */
375 assert(image != (Image *) NULL);
376 assert(image->signature == MagickCoreSignature);
377 if (IsEventLogging() != MagickFalse)
378 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
379 image->next=AcquireImage(image_info,exception);
380 if (GetNextImageInList(image) == (Image *) NULL)
381 return;
382 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
383 MagickPathExtent);
384 if (image_info != (ImageInfo *) NULL)
385 (void) CopyMagickString(GetNextImageInList(image)->filename,
386 image_info->filename,MagickPathExtent);
387 DestroyBlob(GetNextImageInList(image));
388 image->next->blob=ReferenceBlob(image->blob);
389 image->next->endian=image->endian;
390 image->next->scene=image->scene+1;
391 image->next->previous=image;
392}
393
394/*
395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396% %
397% %
398% %
399% A p p e n d I m a g e s %
400% %
401% %
402% %
403%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404%
405% AppendImages() takes all images from the current image pointer to the end
406% of the image list and appends them to each other top-to-bottom if the
407% stack parameter is true, otherwise left-to-right.
408%
409% The current gravity setting effects how the image is justified in the
410% final image.
411%
412% The format of the AppendImages method is:
413%
414% Image *AppendImages(const Image *images,const MagickBooleanType stack,
415% ExceptionInfo *exception)
416%
417% A description of each parameter follows:
418%
419% o images: the image sequence.
420%
421% o stack: A value other than 0 stacks the images top-to-bottom.
422%
423% o exception: return any errors or warnings in this structure.
424%
425*/
426MagickExport Image *AppendImages(const Image *images,
427 const MagickBooleanType stack,ExceptionInfo *exception)
428{
429#define AppendImageTag "Append/Image"
430
431 CacheView
432 *append_view;
433
434 Image
435 *append_image;
436
437 ImageType
438 image_type;
439
440 MagickBooleanType
441 homogeneous_colorspace,
442 status;
443
444 MagickOffsetType
445 n;
446
447 PixelTrait
448 alpha_trait;
449
450 RectangleInfo
451 geometry;
452
453 const Image
454 *next;
455
456 size_t
457 depth,
458 height,
459 number_images,
460 width;
461
462 ssize_t
463 x_offset,
464 y,
465 y_offset;
466
467 /*
468 Compute maximum area of appended area.
469 */
470 assert(images != (Image *) NULL);
471 assert(images->signature == MagickCoreSignature);
472 assert(exception != (ExceptionInfo *) NULL);
473 assert(exception->signature == MagickCoreSignature);
474 if (IsEventLogging() != MagickFalse)
475 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
476 alpha_trait=images->alpha_trait;
477 number_images=1;
478 width=images->columns;
479 height=images->rows;
480 depth=images->depth;
481 image_type=images->type;
482 homogeneous_colorspace=MagickTrue;
483 next=GetNextImageInList(images);
484 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
485 {
486 if (next->depth > depth)
487 depth=next->depth;
488 if (next->type != images->type)
489 image_type=UndefinedType;
490 if (next->colorspace != images->colorspace)
491 homogeneous_colorspace=MagickFalse;
492 if (next->alpha_trait != UndefinedPixelTrait)
493 alpha_trait=BlendPixelTrait;
494 number_images++;
495 if (stack != MagickFalse)
496 {
497 if (next->columns > width)
498 width=next->columns;
499 height+=next->rows;
500 continue;
501 }
502 width+=next->columns;
503 if (next->rows > height)
504 height=next->rows;
505 }
506 /*
507 Append images.
508 */
509 append_image=CloneImage(images,width,height,MagickTrue,exception);
510 if (append_image == (Image *) NULL)
511 return((Image *) NULL);
512 if (image_type != BilevelType)
513 {
514 if (SetImageStorageClass(append_image,DirectClass,exception) == MagickFalse)
515 {
516 append_image=DestroyImage(append_image);
517 return((Image *) NULL);
518 }
519 if (homogeneous_colorspace == MagickFalse)
520 (void) SetImageColorspace(append_image,sRGBColorspace,exception);
521 }
522 append_image->depth=depth;
523 append_image->alpha_trait=alpha_trait;
524 append_image->page=images->page;
525 (void) SetImageBackgroundColor(append_image,exception);
526 status=MagickTrue;
527 x_offset=0;
528 y_offset=0;
529 next=images;
530 append_view=AcquireAuthenticCacheView(append_image,exception);
531 for (n=0; n < (MagickOffsetType) number_images; n++)
532 {
533 CacheView
534 *image_view;
535
536 MagickBooleanType
537 proceed;
538
539 SetGeometry(append_image,&geometry);
540 GravityAdjustGeometry(next->columns,next->rows,next->gravity,&geometry);
541 if (stack != MagickFalse)
542 x_offset-=geometry.x;
543 else
544 y_offset-=geometry.y;
545 image_view=AcquireVirtualCacheView(next,exception);
546#if defined(MAGICKCORE_OPENMP_SUPPORT)
547 #pragma omp parallel for schedule(static) shared(status) \
548 magick_number_threads(next,next,next->rows,2)
549#endif
550 for (y=0; y < (ssize_t) next->rows; y++)
551 {
552 MagickBooleanType
553 sync;
554
555 PixelInfo
556 pixel;
557
558 const Quantum
559 *magick_restrict p;
560
561 Quantum
562 *magick_restrict q;
563
564 ssize_t
565 x;
566
567 if (status == MagickFalse)
568 continue;
569 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
570 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
571 next->columns,1,exception);
572 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
573 {
574 status=MagickFalse;
575 continue;
576 }
577 GetPixelInfo(next,&pixel);
578 for (x=0; x < (ssize_t) next->columns; x++)
579 {
580 GetPixelInfoPixel(next,p,&pixel);
581 SetPixelViaPixelInfo(append_image,&pixel,q);
582 p+=(ptrdiff_t) GetPixelChannels(next);
583 q+=(ptrdiff_t) GetPixelChannels(append_image);
584 }
585 sync=SyncCacheViewAuthenticPixels(append_view,exception);
586 if (sync == MagickFalse)
587 status=MagickFalse;
588 }
589 image_view=DestroyCacheView(image_view);
590 if (stack == MagickFalse)
591 {
592 x_offset+=(ssize_t) next->columns;
593 y_offset=0;
594 }
595 else
596 {
597 x_offset=0;
598 y_offset+=(ssize_t) next->rows;
599 }
600 proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
601 if (proceed == MagickFalse)
602 break;
603 next=GetNextImageInList(next);
604 }
605 append_view=DestroyCacheView(append_view);
606 if (status == MagickFalse)
607 append_image=DestroyImage(append_image);
608 return(append_image);
609}
610
611/*
612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
613% %
614% %
615% %
616% C a t c h I m a g e E x c e p t i o n %
617% %
618% %
619% %
620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621%
622% CatchImageException() returns if no exceptions are found in the image
623% sequence, otherwise it determines the most severe exception and reports
624% it as a warning or error depending on the severity.
625%
626% The format of the CatchImageException method is:
627%
628% ExceptionType CatchImageException(Image *image)
629%
630% A description of each parameter follows:
631%
632% o image: An image sequence.
633%
634*/
635MagickExport ExceptionType CatchImageException(Image *image)
636{
637 ExceptionInfo
638 *exception;
639
640 ExceptionType
641 severity;
642
643 assert(image != (const Image *) NULL);
644 assert(image->signature == MagickCoreSignature);
645 if (IsEventLogging() != MagickFalse)
646 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
647 exception=AcquireExceptionInfo();
648 CatchException(exception);
649 severity=exception->severity;
650 exception=DestroyExceptionInfo(exception);
651 return(severity);
652}
653
654/*
655%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
656% %
657% %
658% %
659% C l i p I m a g e P a t h %
660% %
661% %
662% %
663%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664%
665% ClipImagePath() sets the image clip mask based any clipping path information
666% if it exists.
667%
668% The format of the ClipImagePath method is:
669%
670% MagickBooleanType ClipImagePath(Image *image,const char *pathname,
671% const MagickBooleanType inside,ExceptionInfo *exception)
672%
673% A description of each parameter follows:
674%
675% o image: the image.
676%
677% o pathname: name of clipping path resource. If name is preceded by #, use
678% clipping path numbered by name.
679%
680% o inside: if non-zero, later operations take effect inside clipping path.
681% Otherwise later operations take effect outside clipping path.
682%
683% o exception: return any errors or warnings in this structure.
684%
685*/
686
687MagickExport MagickBooleanType ClipImage(Image *image,ExceptionInfo *exception)
688{
689 return(ClipImagePath(image,"#1",MagickTrue,exception));
690}
691
692MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
693 const MagickBooleanType inside,ExceptionInfo *exception)
694{
695#define ClipImagePathTag "ClipPath/Image"
696
697 char
698 *property;
699
700 const char
701 *value;
702
703 Image
704 *clip_mask;
705
706 ImageInfo
707 *image_info;
708
709 assert(image != (const Image *) NULL);
710 assert(image->signature == MagickCoreSignature);
711 assert(pathname != NULL);
712 if (IsEventLogging() != MagickFalse)
713 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
714 property=AcquireString(pathname);
715 (void) FormatLocaleString(property,MagickPathExtent,"8BIM:1999,2998:%s",
716 pathname);
717 value=GetImageProperty(image,property,exception);
718 property=DestroyString(property);
719 if (value == (const char *) NULL)
720 {
721 ThrowFileException(exception,OptionError,"NoClipPathDefined",
722 image->filename);
723 return(MagickFalse);
724 }
725 image_info=AcquireImageInfo();
726 (void) CopyMagickString(image_info->filename,image->filename,
727 MagickPathExtent);
728 (void) ConcatenateMagickString(image_info->filename,pathname,
729 MagickPathExtent);
730 clip_mask=BlobToImage(image_info,value,strlen(value),exception);
731 image_info=DestroyImageInfo(image_info);
732 if (clip_mask == (Image *) NULL)
733 return(MagickFalse);
734 if (clip_mask->storage_class == PseudoClass)
735 {
736 (void) SyncImage(clip_mask,exception);
737 if (SetImageStorageClass(clip_mask,DirectClass,exception) == MagickFalse)
738 return(MagickFalse);
739 }
740 if (inside != MagickFalse)
741 (void) NegateImage(clip_mask,MagickFalse,exception);
742 (void) FormatLocaleString(clip_mask->magick_filename,MagickPathExtent,
743 "8BIM:1999,2998:%s\nPS",pathname);
744 (void) SetImageMask(image,WritePixelMask,clip_mask,exception);
745 image->mask_trait=UpdatePixelTrait;
746 clip_mask=DestroyImage(clip_mask);
747 return(MagickTrue);
748}
749
750/*
751%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
752% %
753% %
754% %
755% C l o n e I m a g e %
756% %
757% %
758% %
759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760%
761% CloneImage() copies an image and returns the copy as a new image object.
762%
763% If the specified columns and rows is 0, an exact copy of the image is
764% returned, otherwise the pixel data is undefined and must be initialized
765% with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
766% failure, a NULL image is returned and exception describes the reason for the
767% failure.
768%
769% The format of the CloneImage method is:
770%
771% Image *CloneImage(const Image *image,const size_t columns,
772% const size_t rows,const MagickBooleanType orphan,
773% ExceptionInfo *exception)
774%
775% A description of each parameter follows:
776%
777% o image: the image.
778%
779% o columns: the number of columns in the cloned image.
780%
781% o rows: the number of rows in the cloned image.
782%
783% o detach: With a value other than 0, the cloned image is detached from
784% its parent I/O stream.
785%
786% o exception: return any errors or warnings in this structure.
787%
788*/
789MagickExport Image *CloneImage(const Image *image,const size_t columns,
790 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
791{
792 double
793 scale_x,
794 scale_y;
795
796 Image
797 *clone_image;
798
799 size_t
800 length;
801
802 /*
803 Clone the image.
804 */
805 assert(image != (const Image *) NULL);
806 assert(image->signature == MagickCoreSignature);
807 assert(exception != (ExceptionInfo *) NULL);
808 assert(exception->signature == MagickCoreSignature);
809 if (IsEventLogging() != MagickFalse)
810 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
811 if ((image->columns == 0) || (image->rows == 0))
812 {
813 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
814 "NegativeOrZeroImageSize","`%s'",image->filename);
815 return((Image *) NULL);
816 }
817 clone_image=(Image *) AcquireCriticalMemory(sizeof(*clone_image));
818 (void) memset(clone_image,0,sizeof(*clone_image));
819 clone_image->signature=MagickCoreSignature;
820 clone_image->storage_class=image->storage_class;
821 clone_image->number_channels=image->number_channels;
822 clone_image->number_meta_channels=image->number_meta_channels;
823 clone_image->metacontent_extent=image->metacontent_extent;
824 clone_image->colorspace=image->colorspace;
825 clone_image->alpha_trait=image->alpha_trait;
826 clone_image->channels=image->channels;
827 clone_image->mask_trait=image->mask_trait;
828 clone_image->columns=image->columns;
829 clone_image->rows=image->rows;
830 clone_image->dither=image->dither;
831 clone_image->image_info=CloneImageInfo(image->image_info);
832 (void) CloneImageProfiles(clone_image,image);
833 (void) CloneImageProperties(clone_image,image);
834 (void) CloneImageArtifacts(clone_image,image);
835 GetTimerInfo(&clone_image->timer);
836 if (image->ascii85 != (void *) NULL)
837 Ascii85Initialize(clone_image);
838 clone_image->extent=image->extent;
839 clone_image->magick_columns=image->magick_columns;
840 clone_image->magick_rows=image->magick_rows;
841 clone_image->type=image->type;
842 clone_image->channel_mask=image->channel_mask;
843 clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
844 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
845 MagickPathExtent);
846 (void) CopyMagickString(clone_image->magick,image->magick,MagickPathExtent);
847 (void) CopyMagickString(clone_image->filename,image->filename,
848 MagickPathExtent);
849 clone_image->progress_monitor=image->progress_monitor;
850 clone_image->client_data=image->client_data;
851 clone_image->reference_count=1;
852 clone_image->next=image->next;
853 clone_image->previous=image->previous;
854 clone_image->list=NewImageList();
855 if (detach == MagickFalse)
856 clone_image->blob=ReferenceBlob(image->blob);
857 else
858 {
859 clone_image->next=NewImageList();
860 clone_image->previous=NewImageList();
861 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
862 }
863 clone_image->ping=image->ping;
864 clone_image->timestamp=image->timestamp;
865 clone_image->ttl=image->ttl;
866 clone_image->debug=image->debug;
867 clone_image->semaphore=AcquireSemaphoreInfo();
868 if (image->colormap != (PixelInfo *) NULL)
869 {
870 /*
871 Allocate and copy the image colormap.
872 */
873 clone_image->colors=image->colors;
874 length=(size_t) image->colors;
875 clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length+1,
876 sizeof(*clone_image->colormap));
877 if (clone_image->colormap == (PixelInfo *) NULL)
878 {
879 clone_image=DestroyImage(clone_image);
880 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
881 }
882 (void) memcpy(clone_image->colormap,image->colormap,length*
883 sizeof(*clone_image->colormap));
884 }
885 if ((columns == 0) || (rows == 0))
886 {
887 if (image->montage != (char *) NULL)
888 (void) CloneString(&clone_image->montage,image->montage);
889 if (image->directory != (char *) NULL)
890 (void) CloneString(&clone_image->directory,image->directory);
891 clone_image->cache=ReferencePixelCache(image->cache);
892 return(clone_image);
893 }
894 scale_x=1.0;
895 scale_y=1.0;
896 if (image->columns != 0)
897 scale_x=(double) columns/(double) image->columns;
898 if (image->rows != 0)
899 scale_y=(double) rows/(double) image->rows;
900 clone_image->page.width=(size_t) CastDoubleToSsizeT(floor(scale_x*
901 image->page.width+0.5));
902 clone_image->page.height=(size_t) CastDoubleToSsizeT(floor(scale_y*
903 image->page.height+0.5));
904 if (MagickAbsoluteValue(scale_x-scale_y) < 2.0)
905 scale_x=scale_y=MagickMin(scale_x,scale_y);
906 clone_image->page.x=CastDoubleToSsizeT(ceil(scale_x*image->page.x-0.5));
907 clone_image->tile_offset.x=CastDoubleToSsizeT(ceil(scale_x*
908 image->tile_offset.x-0.5));
909 clone_image->page.y=CastDoubleToSsizeT(ceil(scale_y*image->page.y-0.5));
910 clone_image->tile_offset.y=CastDoubleToSsizeT(ceil(scale_y*
911 image->tile_offset.y-0.5));
912 clone_image->cache=ClonePixelCache(image->cache);
913 if (SetImageExtent(clone_image,columns,rows,exception) == MagickFalse)
914 clone_image=DestroyImage(clone_image);
915 return(clone_image);
916}
917
918/*
919%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920% %
921% %
922% %
923% C l o n e I m a g e I n f o %
924% %
925% %
926% %
927%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928%
929% CloneImageInfo() makes a copy of the given image info structure. If
930% NULL is specified, a new image info structure is created initialized to
931% default values.
932%
933% The format of the CloneImageInfo method is:
934%
935% ImageInfo *CloneImageInfo(const ImageInfo *image_info)
936%
937% A description of each parameter follows:
938%
939% o image_info: the image info.
940%
941*/
942MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
943{
944 ImageInfo
945 *clone_info;
946
947 clone_info=AcquireImageInfo();
948 if (image_info == (ImageInfo *) NULL)
949 return(clone_info);
950 clone_info->compression=image_info->compression;
951 clone_info->temporary=image_info->temporary;
952 clone_info->adjoin=image_info->adjoin;
953 clone_info->antialias=image_info->antialias;
954 clone_info->scene=image_info->scene;
955 clone_info->number_scenes=image_info->number_scenes;
956 clone_info->depth=image_info->depth;
957 if (image_info->size != (char *) NULL)
958 (void) CloneString(&clone_info->size,image_info->size);
959 if (image_info->extract != (char *) NULL)
960 (void) CloneString(&clone_info->extract,image_info->extract);
961 if (image_info->scenes != (char *) NULL)
962 (void) CloneString(&clone_info->scenes,image_info->scenes);
963 if (image_info->page != (char *) NULL)
964 (void) CloneString(&clone_info->page,image_info->page);
965 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;
969 if (image_info->sampling_factor != (char *) NULL)
970 (void) CloneString(&clone_info->sampling_factor,
971 image_info->sampling_factor);
972 if (image_info->server_name != (char *) NULL)
973 (void) CloneString(&clone_info->server_name,image_info->server_name);
974 if (image_info->font != (char *) NULL)
975 (void) CloneString(&clone_info->font,image_info->font);
976 if (image_info->texture != (char *) NULL)
977 (void) CloneString(&clone_info->texture,image_info->texture);
978 if (image_info->density != (char *) NULL)
979 (void) CloneString(&clone_info->density,image_info->density);
980 clone_info->pointsize=image_info->pointsize;
981 clone_info->fuzz=image_info->fuzz;
982 clone_info->matte_color=image_info->matte_color;
983 clone_info->background_color=image_info->background_color;
984 clone_info->border_color=image_info->border_color;
985 clone_info->transparent_color=image_info->transparent_color;
986 clone_info->dither=image_info->dither;
987 clone_info->monochrome=image_info->monochrome;
988 clone_info->colorspace=image_info->colorspace;
989 clone_info->type=image_info->type;
990 clone_info->orientation=image_info->orientation;
991 clone_info->ping=image_info->ping;
992 clone_info->verbose=image_info->verbose;
993 clone_info->progress_monitor=image_info->progress_monitor;
994 clone_info->client_data=image_info->client_data;
995 clone_info->cache=image_info->cache;
996 if (image_info->cache != (void *) NULL)
997 clone_info->cache=ReferencePixelCache(image_info->cache);
998 if (image_info->profile != (void *) NULL)
999 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
1000 image_info->profile);
1001 SetImageInfoFile(clone_info,image_info->file);
1002 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
1003 clone_info->stream=image_info->stream;
1004 clone_info->custom_stream=image_info->custom_stream;
1005 (void) CopyMagickString(clone_info->magick,image_info->magick,
1006 MagickPathExtent);
1007 (void) CopyMagickString(clone_info->unique,image_info->unique,
1008 MagickPathExtent);
1009 (void) CopyMagickString(clone_info->filename,image_info->filename,
1010 MagickPathExtent);
1011 clone_info->channel=image_info->channel;
1012 (void) CloneImageOptions(clone_info,image_info);
1013 clone_info->debug=image_info->debug;
1014 clone_info->signature=image_info->signature;
1015 return(clone_info);
1016}
1017
1018/*
1019%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020% %
1021% %
1022% %
1023% C o p y I m a g e P i x e l s %
1024% %
1025% %
1026% %
1027%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028%
1029% CopyImagePixels() copies pixels from the source image as defined by the
1030% geometry the destination image at the specified offset.
1031%
1032% The format of the CopyImagePixels method is:
1033%
1034% MagickBooleanType CopyImagePixels(Image *image,const Image *source_image,
1035% const RectangleInfo *geometry,const OffsetInfo *offset,
1036% ExceptionInfo *exception);
1037%
1038% A description of each parameter follows:
1039%
1040% o image: the destination image.
1041%
1042% o source_image: the source image.
1043%
1044% o geometry: define the dimensions of the source pixel rectangle.
1045%
1046% o offset: define the offset in the destination image.
1047%
1048% o exception: return any errors or warnings in this structure.
1049%
1050*/
1051MagickExport MagickBooleanType CopyImagePixels(Image *image,
1052 const Image *source_image,const RectangleInfo *geometry,
1053 const OffsetInfo *offset,ExceptionInfo *exception)
1054{
1055#define CopyImageTag "Copy/Image"
1056
1057 CacheView
1058 *image_view,
1059 *source_view;
1060
1061 MagickBooleanType
1062 status;
1063
1064 MagickOffsetType
1065 progress;
1066
1067 ssize_t
1068 y;
1069
1070 assert(image != (Image *) NULL);
1071 assert(source_image != (Image *) NULL);
1072 assert(geometry != (RectangleInfo *) NULL);
1073 assert(offset != (OffsetInfo *) NULL);
1074 if (IsEventLogging() != MagickFalse)
1075 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1076 if ((offset->x < 0) || (offset->y < 0) ||
1077 ((offset->x+(ssize_t) geometry->width) > (ssize_t) image->columns) ||
1078 ((offset->y+(ssize_t) geometry->height) > (ssize_t) image->rows))
1079 ThrowBinaryException(OptionError,"GeometryDoesNotContainImage",
1080 image->filename);
1081 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1082 return(MagickFalse);
1083 /*
1084 Copy image pixels.
1085 */
1086 status=MagickTrue;
1087 progress=0;
1088 source_view=AcquireVirtualCacheView(source_image,exception);
1089 image_view=AcquireAuthenticCacheView(image,exception);
1090#if defined(MAGICKCORE_OPENMP_SUPPORT)
1091 #pragma omp parallel for schedule(static) shared(progress,status) \
1092 magick_number_threads(image,source_image,geometry->height,2)
1093#endif
1094 for (y=0; y < (ssize_t) geometry->height; y++)
1095 {
1096 MagickBooleanType
1097 sync;
1098
1099 const Quantum
1100 *magick_restrict p;
1101
1102 ssize_t
1103 x;
1104
1105 Quantum
1106 *magick_restrict q;
1107
1108 if (status == MagickFalse)
1109 continue;
1110 p=GetCacheViewVirtualPixels(source_view,geometry->x,y+geometry->y,
1111 geometry->width,1,exception);
1112 q=QueueCacheViewAuthenticPixels(image_view,offset->x,y+offset->y,
1113 geometry->width,1,exception);
1114 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1115 {
1116 status=MagickFalse;
1117 continue;
1118 }
1119 for (x=0; x < (ssize_t) geometry->width; x++)
1120 {
1121 ssize_t
1122 i;
1123
1124 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1125 {
1126 PixelChannel channel = GetPixelChannelChannel(image,i);
1127 PixelTrait traits = GetPixelChannelTraits(image,channel);
1128 PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1129 if ((traits == UndefinedPixelTrait) ||
1130 ((traits & UpdatePixelTrait) == 0) ||
1131 (source_traits == UndefinedPixelTrait))
1132 continue;
1133 SetPixelChannel(image,channel,p[i],q);
1134 }
1135 p+=(ptrdiff_t) GetPixelChannels(source_image);
1136 q+=(ptrdiff_t) GetPixelChannels(image);
1137 }
1138 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1139 if (sync == MagickFalse)
1140 status=MagickFalse;
1141 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1142 {
1143 MagickBooleanType
1144 proceed;
1145
1146#if defined(MAGICKCORE_OPENMP_SUPPORT)
1147 #pragma omp atomic
1148#endif
1149 progress++;
1150 proceed=SetImageProgress(image,CopyImageTag,progress,image->rows);
1151 if (proceed == MagickFalse)
1152 status=MagickFalse;
1153 }
1154 }
1155 source_view=DestroyCacheView(source_view);
1156 image_view=DestroyCacheView(image_view);
1157 return(status);
1158}
1159
1160/*
1161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162% %
1163% %
1164% %
1165% D e s t r o y I m a g e %
1166% %
1167% %
1168% %
1169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1170%
1171% DestroyImage() dereferences an image, deallocating memory associated with
1172% the image if the reference count becomes zero.
1173%
1174% The format of the DestroyImage method is:
1175%
1176% Image *DestroyImage(Image *image)
1177%
1178% A description of each parameter follows:
1179%
1180% o image: the image.
1181%
1182*/
1183MagickExport Image *DestroyImage(Image *image)
1184{
1185 MagickBooleanType
1186 destroy;
1187
1188 /*
1189 Dereference image.
1190 */
1191 assert(image != (Image *) NULL);
1192 assert(image->signature == MagickCoreSignature);
1193 if (IsEventLogging() != MagickFalse)
1194 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1195 destroy=MagickFalse;
1196 LockSemaphoreInfo(image->semaphore);
1197 image->reference_count--;
1198 if (image->reference_count == 0)
1199 destroy=MagickTrue;
1200 UnlockSemaphoreInfo(image->semaphore);
1201 if (destroy == MagickFalse)
1202 return((Image *) NULL);
1203 /*
1204 Destroy image.
1205 */
1206 DestroyImagePixels(image);
1207 image->channel_map=DestroyPixelChannelMap(image->channel_map);
1208 if (image->montage != (char *) NULL)
1209 image->montage=DestroyString(image->montage);
1210 if (image->directory != (char *) NULL)
1211 image->directory=DestroyString(image->directory);
1212 if (image->colormap != (PixelInfo *) NULL)
1213 image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
1214 if (image->geometry != (char *) NULL)
1215 image->geometry=DestroyString(image->geometry);
1216 DestroyImageProfiles(image);
1217 DestroyImageProperties(image);
1218 DestroyImageArtifacts(image);
1219 if (image->ascii85 != (Ascii85Info *) NULL)
1220 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1221 if (image->image_info != (ImageInfo *) NULL)
1222 image->image_info=DestroyImageInfo(image->image_info);
1223 DestroyBlob(image);
1224 if (image->semaphore != (SemaphoreInfo *) NULL)
1225 RelinquishSemaphoreInfo(&image->semaphore);
1226 image->signature=(~MagickCoreSignature);
1227 image=(Image *) RelinquishMagickMemory(image);
1228 return(image);
1229}
1230
1231/*
1232%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1233% %
1234% %
1235% %
1236% D e s t r o y I m a g e I n f o %
1237% %
1238% %
1239% %
1240%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1241%
1242% DestroyImageInfo() deallocates memory associated with an ImageInfo
1243% structure.
1244%
1245% The format of the DestroyImageInfo method is:
1246%
1247% ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1248%
1249% A description of each parameter follows:
1250%
1251% o image_info: the image info.
1252%
1253*/
1254MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1255{
1256 assert(image_info != (ImageInfo *) NULL);
1257 assert(image_info->signature == MagickCoreSignature);
1258 if (IsEventLogging() != MagickFalse)
1259 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1260 image_info->filename);
1261 if (image_info->size != (char *) NULL)
1262 image_info->size=DestroyString(image_info->size);
1263 if (image_info->extract != (char *) NULL)
1264 image_info->extract=DestroyString(image_info->extract);
1265 if (image_info->scenes != (char *) NULL)
1266 image_info->scenes=DestroyString(image_info->scenes);
1267 if (image_info->page != (char *) NULL)
1268 image_info->page=DestroyString(image_info->page);
1269 if (image_info->sampling_factor != (char *) NULL)
1270 image_info->sampling_factor=DestroyString(
1271 image_info->sampling_factor);
1272 if (image_info->server_name != (char *) NULL)
1273 image_info->server_name=DestroyString(
1274 image_info->server_name);
1275 if (image_info->font != (char *) NULL)
1276 image_info->font=DestroyString(image_info->font);
1277 if (image_info->texture != (char *) NULL)
1278 image_info->texture=DestroyString(image_info->texture);
1279 if (image_info->density != (char *) NULL)
1280 image_info->density=DestroyString(image_info->density);
1281 if (image_info->cache != (void *) NULL)
1282 image_info->cache=DestroyPixelCache(image_info->cache);
1283 if (image_info->profile != (StringInfo *) NULL)
1284 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1285 image_info->profile);
1286 DestroyImageOptions(image_info);
1287 image_info->signature=(~MagickCoreSignature);
1288 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1289 return(image_info);
1290}
1291
1292/*
1293%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1294% %
1295% %
1296% %
1297+ D i s a s s o c i a t e I m a g e S t r e a m %
1298% %
1299% %
1300% %
1301%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1302%
1303% DisassociateImageStream() disassociates the image stream. It checks if the
1304% blob of the specified image is referenced by other images. If the reference
1305% count is higher then 1 a new blob is assigned to the specified image.
1306%
1307% The format of the DisassociateImageStream method is:
1308%
1309% void DisassociateImageStream(const Image *image)
1310%
1311% A description of each parameter follows:
1312%
1313% o image: the image.
1314%
1315*/
1316MagickExport void DisassociateImageStream(Image *image)
1317{
1318 assert(image != (Image *) NULL);
1319 assert(image->signature == MagickCoreSignature);
1320 if (IsEventLogging() != MagickFalse)
1321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1322 DisassociateBlob(image);
1323}
1324
1325/*
1326%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1327% %
1328% %
1329% %
1330% G e t I m a g e I n f o %
1331% %
1332% %
1333% %
1334%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1335%
1336% GetImageInfo() initializes image_info to default values.
1337%
1338% The format of the GetImageInfo method is:
1339%
1340% void GetImageInfo(ImageInfo *image_info)
1341%
1342% A description of each parameter follows:
1343%
1344% o image_info: the image info.
1345%
1346*/
1347MagickExport void GetImageInfo(ImageInfo *image_info)
1348{
1349 char
1350 *synchronize;
1351
1352 /*
1353 File and image dimension members.
1354 */
1355 assert(image_info != (ImageInfo *) NULL);
1356 if (IsEventLogging() != MagickFalse)
1357 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1358 (void) memset(image_info,0,sizeof(*image_info));
1359 image_info->adjoin=MagickTrue;
1360 image_info->interlace=NoInterlace;
1361 image_info->channel=AllChannels;
1362 image_info->quality=UndefinedCompressionQuality;
1363 image_info->antialias=MagickTrue;
1364 image_info->dither=MagickTrue;
1365 image_info->depth=0;
1366 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1367 if (synchronize != (const char *) NULL)
1368 {
1369 image_info->synchronize=IsStringTrue(synchronize);
1370 synchronize=DestroyString(synchronize);
1371 }
1372 GetPixelInfoRGBA(BackgroundColorRGBA,&image_info->background_color);
1373 GetPixelInfoRGBA(BorderColorRGBA,&image_info->border_color);
1374 GetPixelInfoRGBA(MatteColorRGBA,&image_info->matte_color);
1375 GetPixelInfoRGBA(TransparentColorRGBA,&image_info->transparent_color);
1376 image_info->debug=(GetLogEventMask() & ImageEvent) != 0 ? MagickTrue :
1377 MagickFalse;
1378 image_info->signature=MagickCoreSignature;
1379}
1380
1381/*
1382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383% %
1384% %
1385% %
1386% G e t I m a g e I n f o F i l e %
1387% %
1388% %
1389% %
1390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391%
1392% GetImageInfoFile() returns the image info file member.
1393%
1394% The format of the GetImageInfoFile method is:
1395%
1396% FILE *GetImageInfoFile(const ImageInfo *image_info)
1397%
1398% A description of each parameter follows:
1399%
1400% o image_info: the image info.
1401%
1402*/
1403MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1404{
1405 return(image_info->file);
1406}
1407
1408/*
1409%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1410% %
1411% %
1412% %
1413% G e t I m a g e M a s k %
1414% %
1415% %
1416% %
1417%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1418%
1419% GetImageMask() returns the mask associated with the image.
1420%
1421% The format of the GetImageMask method is:
1422%
1423% Image *GetImageMask(const Image *image,const PixelMask type,
1424% ExceptionInfo *exception)
1425%
1426% A description of each parameter follows:
1427%
1428% o image: the image.
1429%
1430% o type: the mask type, ReadPixelMask or WritePixelMask.
1431%
1432*/
1433MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
1434 ExceptionInfo *exception)
1435{
1436 CacheView
1437 *mask_view,
1438 *image_view;
1439
1440 Image
1441 *mask_image;
1442
1443 MagickBooleanType
1444 status;
1445
1446 ssize_t
1447 y;
1448
1449 /*
1450 Get image mask.
1451 */
1452 assert(image != (Image *) NULL);
1453 assert(image->signature == MagickCoreSignature);
1454 if (IsEventLogging() != MagickFalse)
1455 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1456 switch (type)
1457 {
1458 case ReadPixelMask:
1459 {
1460 if ((image->channels & ReadMaskChannel) == 0)
1461 return((Image *) NULL);
1462 break;
1463 }
1464 case WritePixelMask:
1465 {
1466 if ((image->channels & WriteMaskChannel) == 0)
1467 return((Image *) NULL);
1468 break;
1469 }
1470 default:
1471 {
1472 if ((image->channels & CompositeMaskChannel) == 0)
1473 return((Image *) NULL);
1474 break;
1475 }
1476 }
1477 mask_image=AcquireImage((ImageInfo *) NULL,exception);
1478 status=SetImageExtent(mask_image,image->columns,image->rows,exception);
1479 if (status == MagickFalse)
1480 return(DestroyImage(mask_image));
1481 status=MagickTrue;
1482 mask_image->alpha_trait=UndefinedPixelTrait;
1483 (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
1484 image_view=AcquireVirtualCacheView(image,exception);
1485 mask_view=AcquireAuthenticCacheView(mask_image,exception);
1486#if defined(MAGICKCORE_OPENMP_SUPPORT)
1487 #pragma omp parallel for schedule(static) shared(status) \
1488 magick_number_threads(image,image,image->rows,2)
1489#endif
1490 for (y=0; y < (ssize_t) image->rows; y++)
1491 {
1492 const Quantum
1493 *magick_restrict p;
1494
1495 Quantum
1496 *magick_restrict q;
1497
1498 ssize_t
1499 x;
1500
1501 if (status == MagickFalse)
1502 continue;
1503 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1504 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1505 exception);
1506 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1507 {
1508 status=MagickFalse;
1509 continue;
1510 }
1511 for (x=0; x < (ssize_t) image->columns; x++)
1512 {
1513 switch (type)
1514 {
1515 case ReadPixelMask:
1516 {
1517 SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
1518 break;
1519 }
1520 case WritePixelMask:
1521 {
1522 SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
1523 break;
1524 }
1525 default:
1526 {
1527 SetPixelGray(mask_image,GetPixelCompositeMask(image,p),q);
1528 break;
1529 }
1530 }
1531 p+=(ptrdiff_t) GetPixelChannels(image);
1532 q+=(ptrdiff_t) GetPixelChannels(mask_image);
1533 }
1534 if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1535 status=MagickFalse;
1536 }
1537 mask_view=DestroyCacheView(mask_view);
1538 image_view=DestroyCacheView(image_view);
1539 if (status == MagickFalse)
1540 mask_image=DestroyImage(mask_image);
1541 return(mask_image);
1542}
1543
1544/*
1545%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546% %
1547% %
1548% %
1549+ G e t I m a g e R e f e r e n c e C o u n t %
1550% %
1551% %
1552% %
1553%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1554%
1555% GetImageReferenceCount() returns the image reference count.
1556%
1557% The format of the GetReferenceCount method is:
1558%
1559% ssize_t GetImageReferenceCount(Image *image)
1560%
1561% A description of each parameter follows:
1562%
1563% o image: the image.
1564%
1565*/
1566MagickExport ssize_t GetImageReferenceCount(Image *image)
1567{
1568 ssize_t
1569 reference_count;
1570
1571 assert(image != (Image *) NULL);
1572 assert(image->signature == MagickCoreSignature);
1573 if (IsEventLogging() != MagickFalse)
1574 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1575 LockSemaphoreInfo(image->semaphore);
1576 reference_count=image->reference_count;
1577 UnlockSemaphoreInfo(image->semaphore);
1578 return(reference_count);
1579}
1580
1581/*
1582%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583% %
1584% %
1585% %
1586% 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 %
1587% %
1588% %
1589% %
1590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1591%
1592% GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1593% image. A virtual pixel is any pixel access that is outside the boundaries
1594% of the image cache.
1595%
1596% The format of the GetImageVirtualPixelMethod() method is:
1597%
1598% VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1599%
1600% A description of each parameter follows:
1601%
1602% o image: the image.
1603%
1604*/
1605MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1606{
1607 assert(image != (Image *) NULL);
1608 assert(image->signature == MagickCoreSignature);
1609 if (IsEventLogging() != MagickFalse)
1610 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1611 return(GetPixelCacheVirtualMethod(image));
1612}
1613
1614/*
1615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616% %
1617% %
1618% %
1619% I n t e r p r e t I m a g e F i l e n a m e %
1620% %
1621% %
1622% %
1623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624%
1625% InterpretImageFilename() interprets embedded characters in an image filename.
1626% The filename length is returned.
1627%
1628% The format of the InterpretImageFilename method is:
1629%
1630% size_t InterpretImageFilename(const ImageInfo *image_info,Image *image,
1631% const char *format,int value,char *filename,ExceptionInfo *exception)
1632%
1633% A description of each parameter follows.
1634%
1635% o image_info: the image info..
1636%
1637% o image: the image.
1638%
1639% o format: A filename describing the format to use to write the numeric
1640% argument. Only the first numeric format identifier is replaced.
1641%
1642% o value: Numeric value to substitute into format filename.
1643%
1644% o filename: return the formatted filename in this character buffer.
1645%
1646% o exception: return any errors or warnings in this structure.
1647%
1648*/
1649MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1650 Image *image,const char *format,int value,char *filename,
1651 ExceptionInfo *exception)
1652{
1653 char
1654 *p = filename,
1655 pattern[MagickPathExtent];
1656
1657 const char
1658 *cursor = format;
1659
1660 /*
1661 Start with a copy of the format string.
1662 */
1663 assert(format != (const char *) NULL);
1664 assert(filename != (char *) NULL);
1665 (void) CopyMagickString(filename,format,MagickPathExtent);
1666 if (IsStringTrue(GetImageOption(image_info,"filename:literal")) != MagickFalse)
1667 return(strlen(filename));
1668 while ((cursor=strchr(cursor,'%')) != (const char *) NULL)
1669 {
1670 const char
1671 *q = cursor;
1672
1673 ssize_t
1674 offset = (ssize_t) (cursor-format);
1675
1676 cursor++; /* move past '%' */
1677 if (*cursor == '%')
1678 {
1679 /*
1680 Escaped %%.
1681 */
1682 cursor++;
1683 continue;
1684 }
1685 /*
1686 Skip padding digits like %03d.
1687 */
1688 if (isdigit((int) ((unsigned char) *cursor)) != 0)
1689 (void) strtol(cursor,(char **) &cursor,10);
1690 switch (*cursor)
1691 {
1692 case 'd':
1693 case 'o':
1694 case 'x':
1695 {
1696 ssize_t
1697 count;
1698
1699 count=FormatLocaleString(pattern,sizeof(pattern),q,value);
1700 if ((count <= 0) || (count >= MagickPathExtent) ||
1701 ((offset+count) >= MagickPathExtent))
1702 return(0);
1703 (void) CopyMagickString(p+offset,pattern,(size_t) (MagickPathExtent-
1704 offset));
1705 cursor++;
1706 break;
1707 }
1708 case '[':
1709 {
1710 const char
1711 *end = strchr(cursor,']'),
1712 *option = (const char *) NULL;
1713
1714 size_t
1715 extent = (size_t) (end-cursor-1),
1716 option_length,
1717 tail_length;
1718
1719 /*
1720 Handle %[key:value];
1721 */
1722 if (end == (const char *) NULL)
1723 break;
1724 if (extent >= sizeof(pattern))
1725 break;
1726 (void) CopyMagickString(pattern,cursor+1,extent+1);
1727 pattern[extent]='\0';
1728 if (image != (Image *) NULL)
1729 {
1730 option=GetImageProperty(image,pattern,exception);
1731 if (option == (const char *) NULL)
1732 option=GetImageArtifact(image,pattern);
1733 }
1734 if ((option == (const char *) NULL) &&
1735 (image_info != (ImageInfo *) NULL))
1736 option=GetImageOption(image_info,pattern);
1737 if (option == (const char *) NULL)
1738 break;
1739 option_length=strlen(option);
1740 tail_length=strlen(end+1);
1741 if ((offset+option_length+tail_length+1) > MagickPathExtent)
1742 return(0);
1743 (void) CopyMagickString(p+offset,option,(size_t) (MagickPathExtent-
1744 offset));
1745 (void) ConcatenateMagickString(p+offset+option_length,end+1,(size_t) (
1746 MagickPathExtent-offset-option_length-tail_length-1));
1747 cursor=end+1;
1748 break;
1749 }
1750 default:
1751 break;
1752 }
1753 }
1754 for (p=filename; *p != '\0'; )
1755 {
1756 /*
1757 Replace "%%" with "%".
1758 */
1759 if ((*p == '%') && (*(p+1) == '%'))
1760 (void) memmove(p,p+1,strlen(p+1)+1); /* shift left */
1761 else
1762 p++;
1763 }
1764 return(strlen(filename));
1765}
1766
1767/*
1768%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769% %
1770% %
1771% %
1772% I s H i g h D y n a m i c R a n g e I m a g e %
1773% %
1774% %
1775% %
1776%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1777%
1778% IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1779% non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1780% 0..65535.
1781%
1782% The format of the IsHighDynamicRangeImage method is:
1783%
1784% MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1785% ExceptionInfo *exception)
1786%
1787% A description of each parameter follows:
1788%
1789% o image: the image.
1790%
1791% o exception: return any errors or warnings in this structure.
1792%
1793*/
1794MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1795 ExceptionInfo *exception)
1796{
1797#if !defined(MAGICKCORE_HDRI_SUPPORT)
1798 (void) image;
1799 (void) exception;
1800 return(MagickFalse);
1801#else
1802 CacheView
1803 *image_view;
1804
1805 MagickBooleanType
1806 hdri = MagickFalse;
1807
1808 ssize_t
1809 y;
1810
1811 assert(image != (Image *) NULL);
1812 assert(image->signature == MagickCoreSignature);
1813 if (IsEventLogging() != MagickFalse)
1814 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1815 image_view=AcquireVirtualCacheView(image,exception);
1816#if defined(MAGICKCORE_OPENMP_SUPPORT)
1817 #pragma omp parallel for schedule(static) shared(hdri) \
1818 magick_number_threads(image,image,image->rows,2)
1819#endif
1820 for (y=0; y < (ssize_t) image->rows; y++)
1821 {
1822 const Quantum
1823 *p;
1824
1825 ssize_t
1826 x;
1827
1828 if (hdri != MagickFalse)
1829 continue;
1830 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1831 if (p == (const Quantum *) NULL)
1832 continue;
1833 for (x=0; x < (ssize_t) image->columns; x++)
1834 {
1835 ssize_t
1836 i;
1837
1838 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1839 {
1840 double
1841 pixel;
1842
1843 PixelTrait
1844 traits;
1845
1846 traits=GetPixelChannelTraits(image,(PixelChannel) i);
1847 if (traits == UndefinedPixelTrait)
1848 continue;
1849 pixel=(double) p[i];
1850 if ((pixel < 0.0) || (pixel > (double) QuantumRange) ||
1851 (pixel != (double) ((QuantumAny) pixel)))
1852 {
1853 hdri=MagickTrue;
1854 break;
1855 }
1856 }
1857 if (hdri != MagickFalse)
1858 break;
1859 p+=(ptrdiff_t) GetPixelChannels(image);
1860 }
1861 }
1862 image_view=DestroyCacheView(image_view);
1863 return(hdri);
1864#endif
1865}
1866
1867/*
1868%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1869% %
1870% %
1871% %
1872% I s I m a g e O b j e c t %
1873% %
1874% %
1875% %
1876%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1877%
1878% IsImageObject() returns MagickTrue if the image sequence contains a valid
1879% set of image objects.
1880%
1881% The format of the IsImageObject method is:
1882%
1883% MagickBooleanType IsImageObject(const Image *image)
1884%
1885% A description of each parameter follows:
1886%
1887% o image: the image.
1888%
1889*/
1890MagickExport MagickBooleanType IsImageObject(const Image *image)
1891{
1892 const Image
1893 *p;
1894
1895 assert(image != (Image *) NULL);
1896 if (IsEventLogging() != MagickFalse)
1897 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1898 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1899 if (p->signature != MagickCoreSignature)
1900 return(MagickFalse);
1901 return(MagickTrue);
1902}
1903
1904/*
1905%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1906% %
1907% %
1908% %
1909% I s T a i n t I m a g e %
1910% %
1911% %
1912% %
1913%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1914%
1915% IsTaintImage() returns MagickTrue any pixel in the image has been altered
1916% since it was first constituted.
1917%
1918% The format of the IsTaintImage method is:
1919%
1920% MagickBooleanType IsTaintImage(const Image *image)
1921%
1922% A description of each parameter follows:
1923%
1924% o image: the image.
1925%
1926*/
1927MagickExport MagickBooleanType IsTaintImage(const Image *image)
1928{
1929 char
1930 magick[MagickPathExtent],
1931 filename[MagickPathExtent];
1932
1933 const Image
1934 *p;
1935
1936 assert(image != (Image *) NULL);
1937 assert(image->signature == MagickCoreSignature);
1938 if (IsEventLogging() != MagickFalse)
1939 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1940 (void) CopyMagickString(magick,image->magick,MagickPathExtent);
1941 (void) CopyMagickString(filename,image->filename,MagickPathExtent);
1942 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1943 {
1944 if (p->taint != MagickFalse)
1945 return(MagickTrue);
1946 if (LocaleCompare(p->magick,magick) != 0)
1947 return(MagickTrue);
1948 if (LocaleCompare(p->filename,filename) != 0)
1949 return(MagickTrue);
1950 }
1951 return(MagickFalse);
1952}
1953
1954/*
1955%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1956% %
1957% %
1958% %
1959% M o d i f y I m a g e %
1960% %
1961% %
1962% %
1963%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1964%
1965% ModifyImage() ensures that there is only a single reference to the image
1966% to be modified, updating the provided image pointer to point to a clone of
1967% the original image if necessary.
1968%
1969% The format of the ModifyImage method is:
1970%
1971% MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
1972%
1973% A description of each parameter follows:
1974%
1975% o image: the image.
1976%
1977% o exception: return any errors or warnings in this structure.
1978%
1979*/
1980MagickExport MagickBooleanType ModifyImage(Image **image,
1981 ExceptionInfo *exception)
1982{
1983 Image
1984 *clone_image;
1985
1986 assert(image != (Image **) NULL);
1987 assert(*image != (Image *) NULL);
1988 assert((*image)->signature == MagickCoreSignature);
1989 if (IsEventLogging() != MagickFalse)
1990 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1991 if (GetImageReferenceCount(*image) <= 1)
1992 return(MagickTrue);
1993 clone_image=CloneImage(*image,0,0,MagickTrue,exception);
1994 LockSemaphoreInfo((*image)->semaphore);
1995 (*image)->reference_count--;
1996 UnlockSemaphoreInfo((*image)->semaphore);
1997 *image=clone_image;
1998 return(MagickTrue);
1999}
2000
2001/*
2002%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2003% %
2004% %
2005% %
2006% N e w M a g i c k I m a g e %
2007% %
2008% %
2009% %
2010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011%
2012% NewMagickImage() creates a blank image canvas of the specified size and
2013% background color.
2014%
2015% The format of the NewMagickImage method is:
2016%
2017% Image *NewMagickImage(const ImageInfo *image_info,const size_t width,
2018% const size_t height,const PixelInfo *background,
2019% ExceptionInfo *exception)
2020%
2021% A description of each parameter follows:
2022%
2023% o image: the image.
2024%
2025% o width: the image width.
2026%
2027% o height: the image height.
2028%
2029% o background: the image color.
2030%
2031% o exception: return any errors or warnings in this structure.
2032%
2033*/
2034MagickExport Image *NewMagickImage(const ImageInfo *image_info,
2035 const size_t width,const size_t height,const PixelInfo *background,
2036 ExceptionInfo *exception)
2037{
2038 CacheView
2039 *image_view;
2040
2041 Image
2042 *image;
2043
2044 MagickBooleanType
2045 status;
2046
2047 ssize_t
2048 y;
2049
2050 assert(image_info != (const ImageInfo *) NULL);
2051 assert(image_info->signature == MagickCoreSignature);
2052 assert(background != (const PixelInfo *) NULL);
2053 if (IsEventLogging() != MagickFalse)
2054 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2055 image=AcquireImage(image_info,exception);
2056 image->columns=width;
2057 image->rows=height;
2058 image->colorspace=background->colorspace;
2059 image->alpha_trait=background->alpha_trait;
2060 image->fuzz=background->fuzz;
2061 image->depth=background->depth;
2062 status=MagickTrue;
2063 image_view=AcquireAuthenticCacheView(image,exception);
2064#if defined(MAGICKCORE_OPENMP_SUPPORT)
2065 #pragma omp parallel for schedule(static) shared(status) \
2066 magick_number_threads(image,image,image->rows,2)
2067#endif
2068 for (y=0; y < (ssize_t) image->rows; y++)
2069 {
2070 Quantum
2071 *magick_restrict q;
2072
2073 ssize_t
2074 x;
2075
2076 if (status == MagickFalse)
2077 continue;
2078 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2079 if (q == (Quantum *) NULL)
2080 {
2081 status=MagickFalse;
2082 continue;
2083 }
2084 for (x=0; x < (ssize_t) image->columns; x++)
2085 {
2086 SetPixelViaPixelInfo(image,background,q);
2087 q+=(ptrdiff_t) GetPixelChannels(image);
2088 }
2089 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2090 status=MagickFalse;
2091 }
2092 image_view=DestroyCacheView(image_view);
2093 if (status == MagickFalse)
2094 image=DestroyImage(image);
2095 return(image);
2096}
2097
2098/*
2099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2100% %
2101% %
2102% %
2103% R e f e r e n c e I m a g e %
2104% %
2105% %
2106% %
2107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2108%
2109% ReferenceImage() increments the reference count associated with an image
2110% returning a pointer to the image.
2111%
2112% The format of the ReferenceImage method is:
2113%
2114% Image *ReferenceImage(Image *image)
2115%
2116% A description of each parameter follows:
2117%
2118% o image: the image.
2119%
2120*/
2121MagickExport Image *ReferenceImage(Image *image)
2122{
2123 assert(image != (Image *) NULL);
2124 assert(image->signature == MagickCoreSignature);
2125 if (IsEventLogging() != MagickFalse)
2126 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2127 LockSemaphoreInfo(image->semaphore);
2128 image->reference_count++;
2129 UnlockSemaphoreInfo(image->semaphore);
2130 return(image);
2131}
2132
2133/*
2134%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2135% %
2136% %
2137% %
2138% R e s e t I m a g e P a g e %
2139% %
2140% %
2141% %
2142%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2143%
2144% ResetImagePage() resets the image page canvas and position.
2145%
2146% The format of the ResetImagePage method is:
2147%
2148% MagickBooleanType ResetImagePage(Image *image,const char *page)
2149%
2150% A description of each parameter follows:
2151%
2152% o image: the image.
2153%
2154% o page: the relative page specification.
2155%
2156*/
2157MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2158{
2159 MagickStatusType
2160 flags;
2161
2162 RectangleInfo
2163 geometry;
2164
2165 assert(image != (Image *) NULL);
2166 assert(image->signature == MagickCoreSignature);
2167 if (IsEventLogging() != MagickFalse)
2168 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2169 flags=ParseAbsoluteGeometry(page,&geometry);
2170 if ((flags & WidthValue) != 0)
2171 {
2172 if ((flags & HeightValue) == 0)
2173 geometry.height=geometry.width;
2174 image->page.width=geometry.width;
2175 image->page.height=geometry.height;
2176 }
2177 if ((flags & AspectValue) != 0)
2178 {
2179 if ((flags & XValue) != 0)
2180 image->page.x+=geometry.x;
2181 if ((flags & YValue) != 0)
2182 image->page.y+=geometry.y;
2183 }
2184 else
2185 {
2186 if ((flags & XValue) != 0)
2187 {
2188 image->page.x=geometry.x;
2189 if ((image->page.width == 0) && (geometry.x > 0))
2190 image->page.width=(size_t) ((ssize_t) image->columns+geometry.x);
2191 }
2192 if ((flags & YValue) != 0)
2193 {
2194 image->page.y=geometry.y;
2195 if ((image->page.height == 0) && (geometry.y > 0))
2196 image->page.height=(size_t) ((ssize_t) image->rows+geometry.y);
2197 }
2198 }
2199 return(MagickTrue);
2200}
2201
2202/*
2203%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204% %
2205% %
2206% %
2207% R e s e t I m a g e P i x e l s %
2208% %
2209% %
2210% %
2211%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2212%
2213% ResetImagePixels() reset the image pixels, that is, all the pixel components
2214% are zeroed.
2215%
2216% The format of the SetImage method is:
2217%
2218% MagickBooleanType ResetImagePixels(Image *image,
2219% ExceptionInfo *exception)
2220%
2221% A description of each parameter follows:
2222%
2223% o image: the image.
2224%
2225% o exception: return any errors or warnings in this structure.
2226%
2227*/
2228MagickExport MagickBooleanType ResetImagePixels(Image *image,
2229 ExceptionInfo *exception)
2230{
2231 CacheView
2232 *image_view;
2233
2234 MagickBooleanType
2235 status;
2236
2237 size_t
2238 length;
2239
2240 ssize_t
2241 y;
2242
2243 void
2244 *pixels;
2245
2246 assert(image != (Image *) NULL);
2247 assert(image->signature == MagickCoreSignature);
2248 if (IsEventLogging() != MagickFalse)
2249 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2250 pixels=AcquirePixelCachePixels(image,&length,exception);
2251 if (pixels != (void *) NULL)
2252 {
2253 /*
2254 Reset in-core image pixels.
2255 */
2256 (void) memset(pixels,0,length);
2257 return(MagickTrue);
2258 }
2259 /*
2260 Reset image pixels.
2261 */
2262 status=MagickTrue;
2263 image_view=AcquireAuthenticCacheView(image,exception);
2264#if defined(MAGICKCORE_OPENMP_SUPPORT)
2265 #pragma omp parallel for schedule(static) shared(status) \
2266 magick_number_threads(image,image,image->rows,2)
2267#endif
2268 for (y=0; y < (ssize_t) image->rows; y++)
2269 {
2270 Quantum
2271 *magick_restrict q;
2272
2273 ssize_t
2274 x;
2275
2276 if (status == MagickFalse)
2277 continue;
2278 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2279 if (q == (Quantum *) NULL)
2280 {
2281 status=MagickFalse;
2282 continue;
2283 }
2284 for (x=0; x < (ssize_t) image->columns; x++)
2285 {
2286 (void) memset(q,0,GetPixelChannels(image)*sizeof(Quantum));
2287 q+=(ptrdiff_t) GetPixelChannels(image);
2288 }
2289 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2290 status=MagickFalse;
2291 }
2292 image_view=DestroyCacheView(image_view);
2293 return(status);
2294}
2295
2296/*
2297%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2298% %
2299% %
2300% %
2301% S e t I m a g e A l p h a %
2302% %
2303% %
2304% %
2305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2306%
2307% SetImageAlpha() sets the alpha levels of the image.
2308%
2309% The format of the SetImageAlpha method is:
2310%
2311% MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2312% ExceptionInfo *exception)
2313%
2314% A description of each parameter follows:
2315%
2316% o image: the image.
2317%
2318% o alpha: the level of transparency: 0 is fully transparent and QuantumRange
2319% is fully opaque.
2320%
2321% o exception: return any errors or warnings in this structure.
2322%
2323*/
2324MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2325 ExceptionInfo *exception)
2326{
2327 CacheView
2328 *image_view;
2329
2330 MagickBooleanType
2331 status;
2332
2333 ssize_t
2334 y;
2335
2336 assert(image != (Image *) NULL);
2337 assert(image->signature == MagickCoreSignature);
2338 if (IsEventLogging() != MagickFalse)
2339 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2340 image->alpha_trait=BlendPixelTrait;
2341 status=MagickTrue;
2342 image_view=AcquireAuthenticCacheView(image,exception);
2343#if defined(MAGICKCORE_OPENMP_SUPPORT)
2344 #pragma omp parallel for schedule(static) shared(status) \
2345 magick_number_threads(image,image,image->rows,2)
2346#endif
2347 for (y=0; y < (ssize_t) image->rows; y++)
2348 {
2349 Quantum
2350 *magick_restrict q;
2351
2352 ssize_t
2353 x;
2354
2355 if (status == MagickFalse)
2356 continue;
2357 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2358 if (q == (Quantum *) NULL)
2359 {
2360 status=MagickFalse;
2361 continue;
2362 }
2363 for (x=0; x < (ssize_t) image->columns; x++)
2364 {
2365 if (GetPixelWriteMask(image,q) > (QuantumRange/2))
2366 SetPixelAlpha(image,alpha,q);
2367 q+=(ptrdiff_t) GetPixelChannels(image);
2368 }
2369 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2370 status=MagickFalse;
2371 }
2372 image_view=DestroyCacheView(image_view);
2373 return(status);
2374}
2375
2376/*
2377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2378% %
2379% %
2380% %
2381% S e t I m a g e B a c k g r o u n d C o l o r %
2382% %
2383% %
2384% %
2385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2386%
2387% SetImageBackgroundColor() initializes the image pixels to the image
2388% background color. The background color is defined by the background_color
2389% member of the image structure.
2390%
2391% The format of the SetImage method is:
2392%
2393% MagickBooleanType SetImageBackgroundColor(Image *image,
2394% ExceptionInfo *exception)
2395%
2396% A description of each parameter follows:
2397%
2398% o image: the image.
2399%
2400% o exception: return any errors or warnings in this structure.
2401%
2402*/
2403MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
2404 ExceptionInfo *exception)
2405{
2406 CacheView
2407 *image_view;
2408
2409 MagickBooleanType
2410 status;
2411
2412 PixelInfo
2413 background;
2414
2415 ssize_t
2416 y;
2417
2418 assert(image != (Image *) NULL);
2419 assert(image->signature == MagickCoreSignature);
2420 if (IsEventLogging() != MagickFalse)
2421 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2422 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2423 return(MagickFalse);
2424 if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
2425 ((image->alpha_trait & BlendPixelTrait) == 0))
2426 (void) SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2427 ConformPixelInfo(image,&image->background_color,&background,exception);
2428 /*
2429 Set image background color.
2430 */
2431 status=MagickTrue;
2432 image_view=AcquireAuthenticCacheView(image,exception);
2433#if defined(MAGICKCORE_OPENMP_SUPPORT)
2434 #pragma omp parallel for schedule(static) shared(status) \
2435 magick_number_threads(image,image,image->rows,2)
2436#endif
2437 for (y=0; y < (ssize_t) image->rows; y++)
2438 {
2439 Quantum
2440 *magick_restrict q;
2441
2442 ssize_t
2443 x;
2444
2445 if (status == MagickFalse)
2446 continue;
2447 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2448 if (q == (Quantum *) NULL)
2449 {
2450 status=MagickFalse;
2451 continue;
2452 }
2453 for (x=0; x < (ssize_t) image->columns; x++)
2454 {
2455 SetPixelViaPixelInfo(image,&background,q);
2456 q+=(ptrdiff_t) GetPixelChannels(image);
2457 }
2458 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2459 status=MagickFalse;
2460 }
2461 image_view=DestroyCacheView(image_view);
2462 return(status);
2463}
2464
2465/*
2466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2467% %
2468% %
2469% %
2470% S e t I m a g e C h a n n e l M a s k %
2471% %
2472% %
2473% %
2474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2475%
2476% SetImageChannelMask() sets the image channel mask from the specified channel
2477% mask.
2478%
2479% The format of the SetImageChannelMask method is:
2480%
2481% ChannelType SetImageChannelMask(Image *image,
2482% const ChannelType channel_mask)
2483%
2484% A description of each parameter follows:
2485%
2486% o image: the image.
2487%
2488% o channel_mask: the channel mask.
2489%
2490*/
2491MagickExport ChannelType SetImageChannelMask(Image *image,
2492 const ChannelType channel_mask)
2493{
2494 return(SetPixelChannelMask(image,channel_mask));
2495}
2496
2497/*
2498%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2499% %
2500% %
2501% %
2502% S e t I m a g e C o l o r %
2503% %
2504% %
2505% %
2506%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2507%
2508% SetImageColor() set the entire image canvas to the specified color.
2509%
2510% The format of the SetImageColor method is:
2511%
2512% MagickBooleanType SetImageColor(Image *image,const PixelInfo *color,
2513% ExceptionInfo *exception)
2514%
2515% A description of each parameter follows:
2516%
2517% o image: the image.
2518%
2519% o background: the image color.
2520%
2521% o exception: return any errors or warnings in this structure.
2522%
2523*/
2524MagickExport MagickBooleanType SetImageColor(Image *image,
2525 const PixelInfo *color,ExceptionInfo *exception)
2526{
2527 CacheView
2528 *image_view;
2529
2530 MagickBooleanType
2531 status;
2532
2533 ssize_t
2534 y;
2535
2536 assert(image != (Image *) NULL);
2537 assert(image->signature == MagickCoreSignature);
2538 assert(color != (const PixelInfo *) NULL);
2539 if (IsEventLogging() != MagickFalse)
2540 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2541 image->colorspace=color->colorspace;
2542 image->alpha_trait=color->alpha_trait;
2543 image->fuzz=color->fuzz;
2544 image->depth=color->depth;
2545 status=MagickTrue;
2546 image_view=AcquireAuthenticCacheView(image,exception);
2547#if defined(MAGICKCORE_OPENMP_SUPPORT)
2548 #pragma omp parallel for schedule(static) shared(status) \
2549 magick_number_threads(image,image,image->rows,2)
2550#endif
2551 for (y=0; y < (ssize_t) image->rows; y++)
2552 {
2553 Quantum
2554 *magick_restrict q;
2555
2556 ssize_t
2557 x;
2558
2559 if (status == MagickFalse)
2560 continue;
2561 q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2562 if (q == (Quantum *) NULL)
2563 {
2564 status=MagickFalse;
2565 continue;
2566 }
2567 for (x=0; x < (ssize_t) image->columns; x++)
2568 {
2569 SetPixelViaPixelInfo(image,color,q);
2570 q+=(ptrdiff_t) GetPixelChannels(image);
2571 }
2572 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2573 status=MagickFalse;
2574 }
2575 image_view=DestroyCacheView(image_view);
2576 return(status);
2577}
2578
2579/*
2580%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2581% %
2582% %
2583% %
2584% S e t I m a g e S t o r a g e C l a s s %
2585% %
2586% %
2587% %
2588%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2589%
2590% SetImageStorageClass() sets the image class: DirectClass for true color
2591% images or PseudoClass for colormapped images.
2592%
2593% The format of the SetImageStorageClass method is:
2594%
2595% MagickBooleanType SetImageStorageClass(Image *image,
2596% const ClassType storage_class,ExceptionInfo *exception)
2597%
2598% A description of each parameter follows:
2599%
2600% o image: the image.
2601%
2602% o storage_class: The image class.
2603%
2604% o exception: return any errors or warnings in this structure.
2605%
2606*/
2607MagickExport MagickBooleanType SetImageStorageClass(Image *image,
2608 const ClassType storage_class,ExceptionInfo *exception)
2609{
2610 assert(image != (Image *) NULL);
2611 assert(image->signature == MagickCoreSignature);
2612 assert(exception != (ExceptionInfo *) NULL);
2613 assert(exception->signature == MagickCoreSignature);
2614 if (IsEventLogging() != MagickFalse)
2615 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2616 image->storage_class=storage_class;
2617 return(SyncImagePixelCache(image,exception));
2618}
2619
2620/*
2621%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2622% %
2623% %
2624% %
2625% S e t I m a g e E x t e n t %
2626% %
2627% %
2628% %
2629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2630%
2631% SetImageExtent() sets the image size (i.e. columns & rows).
2632%
2633% The format of the SetImageExtent method is:
2634%
2635% MagickBooleanType SetImageExtent(Image *image,const size_t columns,
2636% const size_t rows,ExceptionInfo *exception)
2637%
2638% A description of each parameter follows:
2639%
2640% o image: the image.
2641%
2642% o columns: The image width in pixels.
2643%
2644% o rows: The image height in pixels.
2645%
2646% o exception: return any errors or warnings in this structure.
2647%
2648*/
2649MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
2650 const size_t rows,ExceptionInfo *exception)
2651{
2652 if ((columns == 0) || (rows == 0))
2653 ThrowBinaryException(ImageError,"NegativeOrZeroImageSize",image->filename);
2654 image->columns=columns;
2655 image->rows=rows;
2656 if (image->depth == 0)
2657 {
2658 image->depth=8;
2659 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
2660 "ImageDepthNotSupported","`%s'",image->filename);
2661 }
2662 if (image->depth > (8*sizeof(MagickSizeType)))
2663 {
2664 image->depth=8*sizeof(MagickSizeType);
2665 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
2666 "ImageDepthNotSupported","`%s'",image->filename);
2667 }
2668 return(SyncImagePixelCache(image,exception));
2669}
2670
2671/*
2672%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2673% %
2674% %
2675% %
2676+ S e t I m a g e I n f o %
2677% %
2678% %
2679% %
2680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2681%
2682% SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
2683% It is set to a type of image format based on the prefix or suffix of the
2684% filename. For example, 'ps:image' returns PS indicating a Postscript image.
2685% JPEG is returned for this filename: 'image.jpg'. The filename prefix has
2686% precedence over the suffix. Use an optional index enclosed in brackets
2687% after a file name to specify a desired scene of a multi-resolution image
2688% format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2689% indicates success.
2690%
2691% The format of the SetImageInfo method is:
2692%
2693% MagickBooleanType SetImageInfo(ImageInfo *image_info,
2694% const unsigned int frames,ExceptionInfo *exception)
2695%
2696% A description of each parameter follows:
2697%
2698% o image_info: the image info.
2699%
2700% o frames: the number of images you intend to write.
2701%
2702% o exception: return any errors or warnings in this structure.
2703%
2704*/
2705
2706static const MagickInfo *SetImageInfoFromExtension(ImageInfo *image_info,
2707 const char *component,char *magic,ExceptionInfo *exception)
2708{
2709 const MagickInfo
2710 *magick_info;
2711
2712 MagickFormatType
2713 format_type;
2714
2715 ssize_t
2716 i;
2717
2718 static const char
2719 *format_type_formats[] =
2720 {
2721 "AUTOTRACE",
2722 "BROWSE",
2723 "DCRAW",
2724 "EDIT",
2725 "LAUNCH",
2726 "MPEG:DECODE",
2727 "MPEG:ENCODE",
2728 "PRINT",
2729 "PS:ALPHA",
2730 "PS:CMYK",
2731 "PS:COLOR",
2732 "PS:GRAY",
2733 "PS:MONO",
2734 "SCAN",
2735 "SHOW",
2736 "WIN",
2737 (char *) NULL
2738 };
2739
2740 /*
2741 User specified image format.
2742 */
2743 (void) CopyMagickString(magic,component,MagickPathExtent);
2744 LocaleUpper(magic);
2745 /*
2746 Look for explicit image formats.
2747 */
2748 format_type=UndefinedFormatType;
2749 magick_info=GetMagickInfo(magic,exception);
2750 if ((magick_info != (const MagickInfo *) NULL) &&
2751 (magick_info->format_type != UndefinedFormatType))
2752 format_type=magick_info->format_type;
2753 i=0;
2754 while ((format_type == UndefinedFormatType) &&
2755 (format_type_formats[i] != (char *) NULL))
2756 {
2757 if ((*magic == *format_type_formats[i]) &&
2758 (LocaleCompare(magic,format_type_formats[i]) == 0))
2759 format_type=ExplicitFormatType;
2760 i++;
2761 }
2762 if (format_type == UndefinedFormatType)
2763 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2764 else
2765 if (format_type == ExplicitFormatType)
2766 {
2767 image_info->affirm=MagickTrue;
2768 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2769 }
2770 if (LocaleCompare(magic,"RGB") == 0)
2771 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
2772 return(magick_info);
2773}
2774
2775MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
2776 const unsigned int frames,ExceptionInfo *exception)
2777{
2778 char
2779 component[MagickPathExtent],
2780 magic[MagickPathExtent],
2781 path[MagickPathExtent],
2782 *q;
2783
2784 const char
2785 *p;
2786
2787 const MagicInfo
2788 *magic_info;
2789
2790 const MagickInfo
2791 *magick_info;
2792
2793 ExceptionInfo
2794 *sans_exception;
2795
2796 Image
2797 *image;
2798
2799 MagickBooleanType
2800 status;
2801
2802 ssize_t
2803 count;
2804
2805 /*
2806 Look for 'image.format' in filename.
2807 */
2808 assert(image_info != (ImageInfo *) NULL);
2809 assert(image_info->signature == MagickCoreSignature);
2810 if (IsEventLogging() != MagickFalse)
2811 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2812 image_info->filename);
2813 *component='\0';
2814 GetPathComponent(image_info->filename,SubimagePath,component);
2815 if (*component != '\0')
2816 {
2817 /*
2818 Look for scene specification (e.g. img0001.pcd[4]).
2819 */
2820 if (IsSceneGeometry(component,MagickFalse) == MagickFalse)
2821 {
2822 if (IsGeometry(component) != MagickFalse)
2823 (void) CloneString(&image_info->extract,component);
2824 }
2825 else
2826 {
2827 size_t
2828 first,
2829 last;
2830
2831 (void) CloneString(&image_info->scenes,component);
2832 image_info->scene=StringToUnsignedLong(image_info->scenes);
2833 image_info->number_scenes=image_info->scene;
2834 p=image_info->scenes;
2835 for (q=(char *) image_info->scenes; *q != '\0'; p++)
2836 {
2837 while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2838 p++;
2839 first=(size_t) strtol(p,&q,10);
2840 last=first;
2841 while (isspace((int) ((unsigned char) *q)) != 0)
2842 q++;
2843 if (*q == '-')
2844 last=(size_t) strtol(q+1,&q,10);
2845 if (first > last)
2846 Swap(first,last);
2847 if (first < image_info->scene)
2848 image_info->scene=first;
2849 if (last > image_info->number_scenes)
2850 image_info->number_scenes=last;
2851 p=q;
2852 }
2853 image_info->number_scenes-=image_info->scene-1;
2854 }
2855 }
2856 *component='\0';
2857 if (*image_info->magick == '\0')
2858 GetPathComponent(image_info->filename,ExtensionPath,component);
2859 if (*component != '\0')
2860 {
2861 /*
2862 Base path sans any compression extension.
2863 */
2864 GetPathComponent(image_info->filename,BasePathSansCompressExtension,path);
2865 GetPathComponent(path,ExtensionPath,component);
2866 }
2867 image_info->affirm=MagickFalse;
2868 sans_exception=AcquireExceptionInfo();
2869 if ((*component != '\0') && (IsGlob(component) == MagickFalse))
2870 magick_info=SetImageInfoFromExtension(image_info,component,magic,
2871 sans_exception);
2872 /*
2873 Look for explicit 'format:image' in filename.
2874 */
2875 *magic='\0';
2876 GetPathComponent(image_info->filename,MagickPath,magic);
2877 if (*magic == '\0')
2878 {
2879 (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
2880 magick_info=GetMagickInfo(magic,sans_exception);
2881 if ((magick_info != (const MagickInfo *) NULL) &&
2882 (magick_info->format_type == ExplicitFormatType))
2883 image_info->affirm=MagickTrue;
2884 if (frames == 0)
2885 GetPathComponent(image_info->filename,CanonicalPath,component);
2886 else
2887 GetPathComponent(image_info->filename,SubcanonicalPath,component);
2888 (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
2889 }
2890 else
2891 {
2892 const DelegateInfo
2893 *delegate_info;
2894
2895 /*
2896 User specified image format.
2897 */
2898 LocaleUpper(magic);
2899 magick_info=GetMagickInfo(magic,sans_exception);
2900 delegate_info=(const DelegateInfo *) NULL;
2901 if (magick_info == (const MagickInfo *) NULL)
2902 {
2903 delegate_info=GetDelegateInfo(magic,"*",sans_exception);
2904 if (delegate_info == (const DelegateInfo *) NULL)
2905 delegate_info=GetDelegateInfo("*",magic,sans_exception);
2906 if ((delegate_info == (const DelegateInfo *) NULL) &&
2907 ((*component != '\0') && (IsGlob(component) == MagickFalse)))
2908 {
2909 /*
2910 Retry in case GetMagickInfo loaded a custom module.
2911 */
2912 magick_info=SetImageInfoFromExtension(image_info,component,magic,
2913 sans_exception);
2914 }
2915 }
2916 if (((magick_info != (const MagickInfo *) NULL) ||
2917 (delegate_info != (const DelegateInfo *) NULL)) &&
2918 (IsMagickConflict(magic) == MagickFalse))
2919 {
2920 image_info->affirm=MagickTrue;
2921 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2922 GetPathComponent(image_info->filename,CanonicalPath,component);
2923 (void) CopyMagickString(image_info->filename,component,
2924 MagickPathExtent);
2925 }
2926 }
2927 sans_exception=DestroyExceptionInfo(sans_exception);
2928 if ((magick_info == (const MagickInfo *) NULL) ||
2929 (GetMagickEndianSupport(magick_info) == MagickFalse))
2930 image_info->endian=UndefinedEndian;
2931 if ((image_info->adjoin != MagickFalse) && (frames > 1))
2932 {
2933 /*
2934 Test for multiple image support (e.g. image%02d.png).
2935 */
2936 (void) InterpretImageFilename(image_info,(Image *) NULL,
2937 image_info->filename,(int) image_info->scene,component,exception);
2938 if ((LocaleCompare(component,image_info->filename) != 0) &&
2939 (strchr(component,'%') == (char *) NULL))
2940 image_info->adjoin=MagickFalse;
2941 }
2942 if ((image_info->adjoin != MagickFalse) && (frames > 0))
2943 {
2944 /*
2945 Some image formats do not support multiple frames per file.
2946 */
2947 magick_info=GetMagickInfo(magic,exception);
2948 if (magick_info != (const MagickInfo *) NULL)
2949 if (GetMagickAdjoin(magick_info) == MagickFalse)
2950 image_info->adjoin=MagickFalse;
2951 }
2952 if (image_info->affirm != MagickFalse)
2953 return(MagickTrue);
2954 if (frames == 0)
2955 {
2956 unsigned char
2957 *magick;
2958
2959 size_t
2960 magick_size;
2961
2962 /*
2963 Determine the image format from the first few bytes of the file.
2964 */
2965 magick_size=GetMagicPatternExtent(exception);
2966 if (magick_size == 0)
2967 return(MagickFalse);
2968 image=AcquireImage(image_info,exception);
2969 (void) CopyMagickString(image->filename,image_info->filename,
2970 MagickPathExtent);
2971 sans_exception=AcquireExceptionInfo();
2972 status=OpenBlob(image_info,image,ReadBinaryBlobMode,sans_exception);
2973 sans_exception=DestroyExceptionInfo(sans_exception);
2974 if (status == MagickFalse)
2975 {
2976 image=DestroyImage(image);
2977 return(MagickFalse);
2978 }
2979 if ((IsBlobSeekable(image) == MagickFalse) ||
2980 (IsBlobExempt(image) != MagickFalse))
2981 {
2982 /*
2983 Copy image to seekable temporary file.
2984 */
2985 *component='\0';
2986 status=ImageToFile(image,component,exception);
2987 if (CloseBlob(image) == MagickFalse)
2988 status=MagickFalse;
2989 if (status == MagickFalse)
2990 {
2991 (void) RelinquishUniqueFileResource(component);
2992 image=DestroyImage(image);
2993 return(MagickFalse);
2994 }
2995 SetImageInfoFile(image_info,(FILE *) NULL);
2996 (void) CopyMagickString(image->filename,component,MagickPathExtent);
2997 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2998 if (status == MagickFalse)
2999 {
3000 (void) RelinquishUniqueFileResource(component);
3001 image=DestroyImage(image);
3002 return(MagickFalse);
3003 }
3004 (void) CopyMagickString(image_info->filename,component,
3005 MagickPathExtent);
3006 image_info->temporary=MagickTrue;
3007 }
3008 magick=(unsigned char *) AcquireQuantumMemory(1,magick_size);
3009 if (magick == (unsigned char *) NULL)
3010 {
3011 (void) CloseBlob(image);
3012 image=DestroyImage(image);
3013 return(MagickFalse);
3014 }
3015 (void) memset(magick,0,magick_size);
3016 count=ReadBlob(image,magick_size,magick);
3017 (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
3018 (void) CloseBlob(image);
3019 image=DestroyImage(image);
3020 /*
3021 Check magic cache.
3022 */
3023 sans_exception=AcquireExceptionInfo();
3024 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3025 magick=(unsigned char *) RelinquishMagickMemory(magick);
3026 if ((magic_info != (const MagicInfo *) NULL) &&
3027 (GetMagicName(magic_info) != (char *) NULL))
3028 {
3029 /*
3030 Try to use magick_info that was determined earlier by the extension
3031 */
3032 if ((magick_info != (const MagickInfo *) NULL) &&
3033 (GetMagickUseExtension(magick_info) != MagickFalse) &&
3034 (LocaleCompare(magick_info->magick_module,GetMagicName(
3035 magic_info)) == 0))
3036 (void) CopyMagickString(image_info->magick,magick_info->name,
3037 MagickPathExtent);
3038 else
3039 {
3040 (void) CopyMagickString(image_info->magick,GetMagicName(
3041 magic_info),MagickPathExtent);
3042 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3043 }
3044 if ((magick_info == (const MagickInfo *) NULL) ||
3045 (GetMagickEndianSupport(magick_info) == MagickFalse))
3046 image_info->endian=UndefinedEndian;
3047 sans_exception=DestroyExceptionInfo(sans_exception);
3048 return(MagickTrue);
3049 }
3050 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3051 if ((magick_info == (const MagickInfo *) NULL) ||
3052 (GetMagickEndianSupport(magick_info) == MagickFalse))
3053 image_info->endian=UndefinedEndian;
3054 sans_exception=DestroyExceptionInfo(sans_exception);
3055 }
3056 return(MagickTrue);
3057}
3058
3059/*
3060%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3061% %
3062% %
3063% %
3064% S e t I m a g e I n f o B l o b %
3065% %
3066% %
3067% %
3068%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3069%
3070% SetImageInfoBlob() sets the image info blob member.
3071%
3072% The format of the SetImageInfoBlob method is:
3073%
3074% void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3075% const size_t length)
3076%
3077% A description of each parameter follows:
3078%
3079% o image_info: the image info.
3080%
3081% o blob: the blob.
3082%
3083% o length: the blob length.
3084%
3085*/
3086MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3087 const size_t length)
3088{
3089 assert(image_info != (ImageInfo *) NULL);
3090 assert(image_info->signature == MagickCoreSignature);
3091 if (IsEventLogging() != MagickFalse)
3092 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3093 image_info->filename);
3094 image_info->blob=(void *) blob;
3095 image_info->length=length;
3096}
3097
3098/*
3099%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3100% %
3101% %
3102% %
3103% S e t I m a g e I n f o C u s t o m S t r e a m %
3104% %
3105% %
3106% %
3107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3108%
3109% SetImageInfoCustomStream() sets the image info custom stream handlers.
3110%
3111% The format of the SetImageInfoCustomStream method is:
3112%
3113% void SetImageInfoCustomStream(ImageInfo *image_info,
3114% CustomStreamInfo *custom_stream)
3115%
3116% A description of each parameter follows:
3117%
3118% o image_info: the image info.
3119%
3120% o custom_stream: your custom stream methods.
3121%
3122*/
3123MagickExport void SetImageInfoCustomStream(ImageInfo *image_info,
3124 CustomStreamInfo *custom_stream)
3125{
3126 assert(image_info != (ImageInfo *) NULL);
3127 assert(image_info->signature == MagickCoreSignature);
3128 if (IsEventLogging() != MagickFalse)
3129 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3130 image_info->filename);
3131 image_info->custom_stream=(CustomStreamInfo *) custom_stream;
3132}
3133
3134/*
3135%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3136% %
3137% %
3138% %
3139% S e t I m a g e I n f o F i l e %
3140% %
3141% %
3142% %
3143%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3144%
3145% SetImageInfoFile() sets the image info file member.
3146%
3147% The format of the SetImageInfoFile method is:
3148%
3149% void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3150%
3151% A description of each parameter follows:
3152%
3153% o image_info: the image info.
3154%
3155% o file: the file.
3156%
3157*/
3158MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3159{
3160 assert(image_info != (ImageInfo *) NULL);
3161 assert(image_info->signature == MagickCoreSignature);
3162 if (IsEventLogging() != MagickFalse)
3163 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3164 image_info->filename);
3165 image_info->file=file;
3166}
3167
3168/*
3169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3170% %
3171% %
3172% %
3173% S e t I m a g e M a s k %
3174% %
3175% %
3176% %
3177%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3178%
3179% SetImageMask() associates a mask with the image. The mask must be the same
3180% dimensions as the image.
3181%
3182% The format of the SetImageMask method is:
3183%
3184% MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3185% const Image *mask,ExceptionInfo *exception)
3186%
3187% A description of each parameter follows:
3188%
3189% o image: the image.
3190%
3191% o type: the mask type, ReadPixelMask or WritePixelMask.
3192%
3193% o mask: the image mask.
3194%
3195% o exception: return any errors or warnings in this structure.
3196%
3197*/
3198MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3199 const Image *mask,ExceptionInfo *exception)
3200{
3201 CacheView
3202 *mask_view,
3203 *image_view;
3204
3205 MagickBooleanType
3206 status;
3207
3208 ssize_t
3209 y;
3210
3211 /*
3212 Set image mask.
3213 */
3214 assert(image != (Image *) NULL);
3215 if (IsEventLogging() != MagickFalse)
3216 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3217 assert(image->signature == MagickCoreSignature);
3218 if (mask == (const Image *) NULL)
3219 {
3220 switch (type)
3221 {
3222 case ReadPixelMask:
3223 {
3224 image->channels=(ChannelType) ((unsigned int) image->channels &
3225 (unsigned int) ~ReadMaskChannel);
3226 break;
3227 }
3228 case WritePixelMask:
3229 {
3230 image->channels=(ChannelType) ((unsigned int) image->channels &
3231 (unsigned int) ~WriteMaskChannel);
3232 magick_fallthrough;
3233 }
3234 default:
3235 {
3236 image->channels=(ChannelType) ((unsigned int) image->channels &
3237 (unsigned int) ~CompositeMaskChannel);
3238 break;
3239 }
3240 }
3241 return(SyncImagePixelCache(image,exception));
3242 }
3243 switch (type)
3244 {
3245 case ReadPixelMask:
3246 {
3247 image->channels=(ChannelType) (image->channels | ReadMaskChannel);
3248 break;
3249 }
3250 case WritePixelMask:
3251 {
3252 image->channels=(ChannelType) (image->channels | WriteMaskChannel);
3253 break;
3254 }
3255 default:
3256 {
3257 image->channels=(ChannelType) (image->channels | CompositeMaskChannel);
3258 break;
3259 }
3260 }
3261 if (SyncImagePixelCache(image,exception) == MagickFalse)
3262 return(MagickFalse);
3263 status=MagickTrue;
3264 image->mask_trait=UpdatePixelTrait;
3265 mask_view=AcquireVirtualCacheView(mask,exception);
3266 image_view=AcquireAuthenticCacheView(image,exception);
3267#if defined(MAGICKCORE_OPENMP_SUPPORT)
3268 #pragma omp parallel for schedule(static) shared(status) \
3269 magick_number_threads(mask,image,image->rows,2)
3270#endif
3271 for (y=0; y < (ssize_t) image->rows; y++)
3272 {
3273 const Quantum
3274 *magick_restrict p;
3275
3276 Quantum
3277 *magick_restrict q;
3278
3279 ssize_t
3280 x;
3281
3282 if (status == MagickFalse)
3283 continue;
3284 p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
3285 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3286 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3287 {
3288 status=MagickFalse;
3289 continue;
3290 }
3291 for (x=0; x < (ssize_t) image->columns; x++)
3292 {
3293 MagickRealType
3294 intensity;
3295
3296 intensity=0.0;
3297 if ((x < (ssize_t) mask->columns) && (y < (ssize_t) mask->rows))
3298 intensity=GetPixelIntensity(mask,p);
3299 switch (type)
3300 {
3301 case ReadPixelMask:
3302 {
3303 SetPixelReadMask(image,ClampToQuantum(intensity),q);
3304 break;
3305 }
3306 case WritePixelMask:
3307 {
3308 SetPixelWriteMask(image,ClampToQuantum(intensity),q);
3309 break;
3310 }
3311 default:
3312 {
3313 SetPixelCompositeMask(image,ClampToQuantum(intensity),q);
3314 break;
3315 }
3316 }
3317 p+=(ptrdiff_t) GetPixelChannels(mask);
3318 q+=(ptrdiff_t) GetPixelChannels(image);
3319 }
3320 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3321 status=MagickFalse;
3322 }
3323 image->mask_trait=UndefinedPixelTrait;
3324 mask_view=DestroyCacheView(mask_view);
3325 image_view=DestroyCacheView(image_view);
3326 return(status);
3327}
3328
3329/*
3330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3331% %
3332% %
3333% %
3334% S e t I m a g e R e g i o n M a s k %
3335% %
3336% %
3337% %
3338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3339%
3340% SetImageRegionMask() associates a mask with the image as defined by the
3341% specified region.
3342%
3343% The format of the SetImageRegionMask method is:
3344%
3345% MagickBooleanType SetImageRegionMask(Image *image,const PixelMask type,
3346% const RectangleInfo *region,ExceptionInfo *exception)
3347%
3348% A description of each parameter follows:
3349%
3350% o image: the image.
3351%
3352% o type: the mask type, ReadPixelMask or WritePixelMask.
3353%
3354% o geometry: the mask region.
3355%
3356% o exception: return any errors or warnings in this structure.
3357%
3358*/
3359MagickExport MagickBooleanType SetImageRegionMask(Image *image,
3360 const PixelMask type,const RectangleInfo *region,ExceptionInfo *exception)
3361{
3362 CacheView
3363 *image_view;
3364
3365 MagickBooleanType
3366 status;
3367
3368 ssize_t
3369 y;
3370
3371 /*
3372 Set image mask as defined by the region.
3373 */
3374 assert(image != (Image *) NULL);
3375 assert(image->signature == MagickCoreSignature);
3376 if (IsEventLogging() != MagickFalse)
3377 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3378 if (region == (const RectangleInfo *) NULL)
3379 {
3380 switch (type)
3381 {
3382 case ReadPixelMask:
3383 {
3384 image->channels=(ChannelType) ((unsigned int) image->channels &
3385 (unsigned int) ~ReadMaskChannel);
3386 break;
3387 }
3388 case WritePixelMask:
3389 {
3390 image->channels=(ChannelType) ((unsigned int) image->channels &
3391 (unsigned int) ~WriteMaskChannel);
3392 break;
3393 }
3394 default:
3395 {
3396 image->channels=(ChannelType) ((unsigned int) image->channels &
3397 (unsigned int) ~CompositeMaskChannel);
3398 break;
3399 }
3400 }
3401 return(SyncImagePixelCache(image,exception));
3402 }
3403 switch (type)
3404 {
3405 case ReadPixelMask:
3406 {
3407 image->channels=(ChannelType) (image->channels | ReadMaskChannel);
3408 break;
3409 }
3410 case WritePixelMask:
3411 {
3412 image->channels=(ChannelType) (image->channels | WriteMaskChannel);
3413 break;
3414 }
3415 default:
3416 {
3417 image->channels=(ChannelType) (image->channels | CompositeMaskChannel);
3418 break;
3419 }
3420 }
3421 if (SyncImagePixelCache(image,exception) == MagickFalse)
3422 return(MagickFalse);
3423 status=MagickTrue;
3424 image->mask_trait=UpdatePixelTrait;
3425 image_view=AcquireAuthenticCacheView(image,exception);
3426#if defined(MAGICKCORE_OPENMP_SUPPORT)
3427 #pragma omp parallel for schedule(static) shared(status) \
3428 magick_number_threads(image,image,image->rows,2)
3429#endif
3430 for (y=0; y < (ssize_t) image->rows; y++)
3431 {
3432 Quantum
3433 *magick_restrict q;
3434
3435 ssize_t
3436 x;
3437
3438 if (status == MagickFalse)
3439 continue;
3440 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3441 if (q == (Quantum *) NULL)
3442 {
3443 status=MagickFalse;
3444 continue;
3445 }
3446 for (x=0; x < (ssize_t) image->columns; x++)
3447 {
3448 Quantum
3449 pixel;
3450
3451 pixel=QuantumRange;
3452 if (((x >= region->x) && (x < (region->x+(ssize_t) region->width))) &&
3453 ((y >= region->y) && (y < (region->y+(ssize_t) region->height))))
3454 pixel=(Quantum) 0;
3455 switch (type)
3456 {
3457 case ReadPixelMask:
3458 {
3459 SetPixelReadMask(image,pixel,q);
3460 break;
3461 }
3462 case WritePixelMask:
3463 {
3464 SetPixelWriteMask(image,pixel,q);
3465 break;
3466 }
3467 default:
3468 {
3469 SetPixelCompositeMask(image,pixel,q);
3470 break;
3471 }
3472 }
3473 q+=(ptrdiff_t) GetPixelChannels(image);
3474 }
3475 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3476 status=MagickFalse;
3477 }
3478 image->mask_trait=UndefinedPixelTrait;
3479 image_view=DestroyCacheView(image_view);
3480 return(status);
3481}
3482
3483/*
3484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3485% %
3486% %
3487% %
3488% 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 %
3489% %
3490% %
3491% %
3492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3493%
3494% SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3495% image and returns the previous setting. A virtual pixel is any pixel access
3496% that is outside the boundaries of the image cache.
3497%
3498% The format of the SetImageVirtualPixelMethod() method is:
3499%
3500% VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3501% const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3502%
3503% A description of each parameter follows:
3504%
3505% o image: the image.
3506%
3507% o virtual_pixel_method: choose the type of virtual pixel.
3508%
3509% o exception: return any errors or warnings in this structure.
3510%
3511*/
3512MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3513 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3514{
3515 assert(image != (const Image *) NULL);
3516 assert(image->signature == MagickCoreSignature);
3517 if (IsEventLogging() != MagickFalse)
3518 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3519 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
3520}
3521
3522/*
3523%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3524% %
3525% %
3526% %
3527% S m u s h I m a g e s %
3528% %
3529% %
3530% %
3531%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3532%
3533% SmushImages() takes all images from the current image pointer to the end
3534% of the image list and smushes them to each other top-to-bottom if the
3535% stack parameter is true, otherwise left-to-right.
3536%
3537% The current gravity setting now effects how the image is justified in the
3538% final image.
3539%
3540% The format of the SmushImages method is:
3541%
3542% Image *SmushImages(const Image *images,const MagickBooleanType stack,
3543% ExceptionInfo *exception)
3544%
3545% A description of each parameter follows:
3546%
3547% o images: the image sequence.
3548%
3549% o stack: A value other than 0 stacks the images top-to-bottom.
3550%
3551% o offset: minimum distance in pixels between images.
3552%
3553% o exception: return any errors or warnings in this structure.
3554%
3555*/
3556
3557static ssize_t SmushXGap(const Image *smush_image,const Image *images,
3558 const ssize_t offset,ExceptionInfo *exception)
3559{
3560 CacheView
3561 *left_view,
3562 *right_view;
3563
3564 const Image
3565 *left_image,
3566 *right_image;
3567
3568 RectangleInfo
3569 left_geometry,
3570 right_geometry;
3571
3572 const Quantum
3573 *p;
3574
3575 ssize_t
3576 i,
3577 y;
3578
3579 size_t
3580 gap;
3581
3582 ssize_t
3583 x;
3584
3585 if (images->previous == (Image *) NULL)
3586 return(0);
3587 right_image=images;
3588 SetGeometry(smush_image,&right_geometry);
3589 GravityAdjustGeometry(right_image->columns,right_image->rows,
3590 right_image->gravity,&right_geometry);
3591 left_image=images->previous;
3592 SetGeometry(smush_image,&left_geometry);
3593 GravityAdjustGeometry(left_image->columns,left_image->rows,
3594 left_image->gravity,&left_geometry);
3595 gap=right_image->columns;
3596 left_view=AcquireVirtualCacheView(left_image,exception);
3597 right_view=AcquireVirtualCacheView(right_image,exception);
3598 for (y=0; y < (ssize_t) smush_image->rows; y++)
3599 {
3600 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3601 {
3602 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3603 if ((p == (const Quantum *) NULL) ||
3604 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
3605 (((ssize_t) left_image->columns-x-1) >= (ssize_t) gap))
3606 break;
3607 }
3608 i=(ssize_t) left_image->columns-x-1;
3609 for (x=0; x < (ssize_t) right_image->columns; x++)
3610 {
3611 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
3612 exception);
3613 if ((p == (const Quantum *) NULL) ||
3614 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3615 ((x+i) >= (ssize_t) gap))
3616 break;
3617 }
3618 if ((x+i) < (ssize_t) gap)
3619 gap=(size_t) (x+i);
3620 }
3621 right_view=DestroyCacheView(right_view);
3622 left_view=DestroyCacheView(left_view);
3623 if (y < (ssize_t) smush_image->rows)
3624 return(offset);
3625 return((ssize_t) gap-offset);
3626}
3627
3628static ssize_t SmushYGap(const Image *smush_image,const Image *images,
3629 const ssize_t offset,ExceptionInfo *exception)
3630{
3631 CacheView
3632 *bottom_view,
3633 *top_view;
3634
3635 const Image
3636 *bottom_image,
3637 *top_image;
3638
3639 RectangleInfo
3640 bottom_geometry,
3641 top_geometry;
3642
3643 const Quantum
3644 *p;
3645
3646 ssize_t
3647 i,
3648 x;
3649
3650 size_t
3651 gap;
3652
3653 ssize_t
3654 y;
3655
3656 if (images->previous == (Image *) NULL)
3657 return(0);
3658 bottom_image=images;
3659 SetGeometry(smush_image,&bottom_geometry);
3660 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3661 bottom_image->gravity,&bottom_geometry);
3662 top_image=images->previous;
3663 SetGeometry(smush_image,&top_geometry);
3664 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3665 &top_geometry);
3666 gap=bottom_image->rows;
3667 top_view=AcquireVirtualCacheView(top_image,exception);
3668 bottom_view=AcquireVirtualCacheView(bottom_image,exception);
3669 for (x=0; x < (ssize_t) smush_image->columns; x++)
3670 {
3671 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3672 {
3673 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
3674 if ((p == (const Quantum *) NULL) ||
3675 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3676 (((ssize_t) top_image->rows-y-1) >= (ssize_t) gap))
3677 break;
3678 }
3679 i=(ssize_t) top_image->rows-y-1;
3680 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3681 {
3682 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3683 exception);
3684 if ((p == (const Quantum *) NULL) ||
3685 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3686 ((y+i) >= (ssize_t) gap))
3687 break;
3688 }
3689 if ((y+i) < (ssize_t) gap)
3690 gap=(size_t) (y+i);
3691 }
3692 bottom_view=DestroyCacheView(bottom_view);
3693 top_view=DestroyCacheView(top_view);
3694 if (x < (ssize_t) smush_image->columns)
3695 return(offset);
3696 return((ssize_t) gap-offset);
3697}
3698
3699MagickExport Image *SmushImages(const Image *images,
3700 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3701{
3702#define SmushImageTag "Smush/Image"
3703
3704 const Image
3705 *image;
3706
3707 Image
3708 *smush_image;
3709
3710 MagickBooleanType
3711 proceed,
3712 status;
3713
3714 MagickOffsetType
3715 n;
3716
3717 PixelTrait
3718 alpha_trait;
3719
3720 RectangleInfo
3721 geometry;
3722
3723 const Image
3724 *next;
3725
3726 size_t
3727 height,
3728 number_images,
3729 width;
3730
3731 ssize_t
3732 x_offset,
3733 y_offset;
3734
3735 /*
3736 Compute maximum area of smushed area.
3737 */
3738 assert(images != (Image *) NULL);
3739 assert(images->signature == MagickCoreSignature);
3740 assert(exception != (ExceptionInfo *) NULL);
3741 assert(exception->signature == MagickCoreSignature);
3742 if (IsEventLogging() != MagickFalse)
3743 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3744 image=images;
3745 alpha_trait=image->alpha_trait;
3746 number_images=1;
3747 width=image->columns;
3748 height=image->rows;
3749 next=GetNextImageInList(image);
3750 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3751 {
3752 if (next->alpha_trait != UndefinedPixelTrait)
3753 alpha_trait=BlendPixelTrait;
3754 number_images++;
3755 if (stack != MagickFalse)
3756 {
3757 if (next->columns > width)
3758 width=next->columns;
3759 height+=next->rows;
3760 if (next->previous != (Image *) NULL)
3761 height=(size_t) MagickMax((ssize_t) height+offset,0U);
3762 continue;
3763 }
3764 width+=next->columns;
3765 if (next->previous != (Image *) NULL)
3766 width=(size_t) MagickMax((ssize_t) width+offset,0U);
3767 if (next->rows > height)
3768 height=next->rows;
3769 }
3770 /*
3771 Smush images.
3772 */
3773 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3774 if (smush_image == (Image *) NULL)
3775 return((Image *) NULL);
3776 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
3777 {
3778 smush_image=DestroyImage(smush_image);
3779 return((Image *) NULL);
3780 }
3781 smush_image->alpha_trait=alpha_trait;
3782 (void) SetImageBackgroundColor(smush_image,exception);
3783 status=MagickTrue;
3784 x_offset=0;
3785 y_offset=0;
3786 for (n=0; n < (MagickOffsetType) number_images; n++)
3787 {
3788 SetGeometry(smush_image,&geometry);
3789 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3790 if (stack != MagickFalse)
3791 {
3792 x_offset-=geometry.x;
3793 y_offset-=SmushYGap(smush_image,image,offset,exception);
3794 }
3795 else
3796 {
3797 x_offset-=SmushXGap(smush_image,image,offset,exception);
3798 y_offset-=geometry.y;
3799 }
3800 status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3801 y_offset,exception);
3802 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3803 if (proceed == MagickFalse)
3804 break;
3805 if (stack == MagickFalse)
3806 {
3807 x_offset+=(ssize_t) image->columns;
3808 y_offset=0;
3809 }
3810 else
3811 {
3812 x_offset=0;
3813 y_offset+=(ssize_t) image->rows;
3814 }
3815 image=GetNextImageInList(image);
3816 }
3817 if (stack == MagickFalse)
3818 smush_image->columns=(size_t) x_offset;
3819 else
3820 smush_image->rows=(size_t) y_offset;
3821 if (status == MagickFalse)
3822 smush_image=DestroyImage(smush_image);
3823 return(smush_image);
3824}
3825
3826/*
3827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3828% %
3829% %
3830% %
3831% S t r i p I m a g e %
3832% %
3833% %
3834% %
3835%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3836%
3837% StripImage() strips an image of all profiles and comments.
3838%
3839% The format of the StripImage method is:
3840%
3841% MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
3842%
3843% A description of each parameter follows:
3844%
3845% o image: the image.
3846%
3847% o exception: return any errors or warnings in this structure.
3848%
3849*/
3850MagickExport MagickBooleanType StripImage(Image *image,
3851 ExceptionInfo *magick_unused(exception))
3852{
3853 MagickBooleanType
3854 status;
3855
3856 magick_unreferenced(exception);
3857 assert(image != (Image *) NULL);
3858 if (IsEventLogging() != MagickFalse)
3859 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3860 DestroyImageProfiles(image);
3861 (void) DeleteImageProperty(image,"comment");
3862 (void) DeleteImageProperty(image,"date:create");
3863 (void) DeleteImageProperty(image,"date:modify");
3864 (void) DeleteImageProperty(image,"date:timestamp");
3865 status=SetImageArtifact(image,"png:exclude-chunk",
3866 "bKGD,caNv,cHRM,eXIf,gAMA,iCCP,iTXt,pHYs,sRGB,tEXt,zCCP,zTXt,date");
3867 return(status);
3868}
3869
3870/*
3871%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3872% %
3873% %
3874% %
3875+ S y n c I m a g e %
3876% %
3877% %
3878% %
3879%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3880%
3881% SyncImage() initializes the red, green, and blue intensities of each pixel
3882% as defined by the colormap index.
3883%
3884% The format of the SyncImage method is:
3885%
3886% MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3887%
3888% A description of each parameter follows:
3889%
3890% o image: the image.
3891%
3892% o exception: return any errors or warnings in this structure.
3893%
3894*/
3895
3896static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3897 MagickBooleanType *range_exception)
3898{
3899 if ((size_t) index < image->colors)
3900 return(index);
3901 *range_exception=MagickTrue;
3902 return((Quantum) 0);
3903}
3904
3905MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3906{
3907 CacheView
3908 *image_view;
3909
3910 MagickBooleanType
3911 range_exception,
3912 status,
3913 taint;
3914
3915 ssize_t
3916 y;
3917
3918 assert(image != (Image *) NULL);
3919 assert(image->signature == MagickCoreSignature);
3920 if (IsEventLogging() != MagickFalse)
3921 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3922 if (image->ping != MagickFalse)
3923 return(MagickTrue);
3924 if (image->storage_class != PseudoClass)
3925 return(MagickFalse);
3926 assert(image->colormap != (PixelInfo *) NULL);
3927 range_exception=MagickFalse;
3928 status=MagickTrue;
3929 taint=image->taint;
3930 image_view=AcquireAuthenticCacheView(image,exception);
3931#if defined(MAGICKCORE_OPENMP_SUPPORT)
3932 #pragma omp parallel for schedule(static) shared(range_exception,status) \
3933 magick_number_threads(image,image,image->rows,2)
3934#endif
3935 for (y=0; y < (ssize_t) image->rows; y++)
3936 {
3937 Quantum
3938 index;
3939
3940 Quantum
3941 *magick_restrict q;
3942
3943 ssize_t
3944 x;
3945
3946 if (status == MagickFalse)
3947 continue;
3948 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3949 if (q == (Quantum *) NULL)
3950 {
3951 status=MagickFalse;
3952 continue;
3953 }
3954 for (x=0; x < (ssize_t) image->columns; x++)
3955 {
3956 index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
3957 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
3958 q+=(ptrdiff_t) GetPixelChannels(image);
3959 }
3960 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3961 status=MagickFalse;
3962 }
3963 image_view=DestroyCacheView(image_view);
3964 image->taint=taint;
3965 if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
3966 (void) ThrowMagickException(exception,GetMagickModule(),
3967 CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
3968 return(status);
3969}
3970
3971/*
3972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3973% %
3974% %
3975% %
3976% S y n c I m a g e S e t t i n g s %
3977% %
3978% %
3979% %
3980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3981%
3982% SyncImageSettings() syncs any image_info global options into per-image
3983% attributes.
3984%
3985% Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
3986% that operations and coders can find such settings. In IMv7 if a desired
3987% per-image artifact is not set, then it will directly look for a global
3988% option as a fallback, as such this copy is no longer needed, only the
3989% link set up.
3990%
3991% The format of the SyncImageSettings method is:
3992%
3993% MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
3994% Image *image,ExceptionInfo *exception)
3995% MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
3996% Image *image,ExceptionInfo *exception)
3997%
3998% A description of each parameter follows:
3999%
4000% o image_info: the image info.
4001%
4002% o image: the image.
4003%
4004% o exception: return any errors or warnings in this structure.
4005%
4006*/
4007
4008MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4009 Image *images,ExceptionInfo *exception)
4010{
4011 Image
4012 *image;
4013
4014 assert(image_info != (const ImageInfo *) NULL);
4015 assert(image_info->signature == MagickCoreSignature);
4016 assert(images != (Image *) NULL);
4017 assert(images->signature == MagickCoreSignature);
4018 if (IsEventLogging() != MagickFalse)
4019 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4020 image=images;
4021 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4022 (void) SyncImageSettings(image_info,image,exception);
4023 (void) DeleteImageOption(image_info,"page");
4024 return(MagickTrue);
4025}
4026
4027MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4028 Image *image,ExceptionInfo *exception)
4029{
4030 const char
4031 *option;
4032
4033 GeometryInfo
4034 geometry_info;
4035
4036 MagickStatusType
4037 flags;
4038
4039 ResolutionType
4040 units;
4041
4042 /*
4043 Sync image options.
4044 */
4045 assert(image_info != (const ImageInfo *) NULL);
4046 assert(image_info->signature == MagickCoreSignature);
4047 assert(image != (Image *) NULL);
4048 assert(image->signature == MagickCoreSignature);
4049 if (IsEventLogging() != MagickFalse)
4050 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4051 option=GetImageOption(image_info,"background");
4052 if (option != (const char *) NULL)
4053 (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
4054 exception);
4055 option=GetImageOption(image_info,"black-point-compensation");
4056 if (option != (const char *) NULL)
4057 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
4058 MagickBooleanOptions,MagickFalse,option);
4059 option=GetImageOption(image_info,"blue-primary");
4060 if (option != (const char *) NULL)
4061 {
4062 flags=ParseGeometry(option,&geometry_info);
4063 if ((flags & RhoValue) != 0)
4064 image->chromaticity.blue_primary.x=geometry_info.rho;
4065 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4066 if ((flags & SigmaValue) != 0)
4067 image->chromaticity.blue_primary.y=geometry_info.sigma;
4068 }
4069 option=GetImageOption(image_info,"bordercolor");
4070 if (option != (const char *) NULL)
4071 (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
4072 exception);
4073 /* FUTURE: do not sync compose to per-image compose setting here */
4074 option=GetImageOption(image_info,"compose");
4075 if (option != (const char *) NULL)
4076 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
4077 MagickFalse,option);
4078 /* -- */
4079 option=GetImageOption(image_info,"compress");
4080 if (option != (const char *) NULL)
4081 image->compression=(CompressionType) ParseCommandOption(
4082 MagickCompressOptions,MagickFalse,option);
4083 option=GetImageOption(image_info,"debug");
4084 if (option != (const char *) NULL)
4085 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
4086 MagickFalse,option);
4087 option=GetImageOption(image_info,"density");
4088 if (option != (const char *) NULL)
4089 {
4090 flags=ParseGeometry(option,&geometry_info);
4091 if ((flags & RhoValue) != 0)
4092 image->resolution.x=geometry_info.rho;
4093 image->resolution.y=image->resolution.x;
4094 if ((flags & SigmaValue) != 0)
4095 image->resolution.y=geometry_info.sigma;
4096 }
4097 option=GetImageOption(image_info,"depth");
4098 if (option != (const char *) NULL)
4099 image->depth=StringToUnsignedLong(option);
4100 option=GetImageOption(image_info,"endian");
4101 if (option != (const char *) NULL)
4102 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
4103 MagickFalse,option);
4104 option=GetImageOption(image_info,"filter");
4105 if (option != (const char *) NULL)
4106 image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
4107 MagickFalse,option);
4108 option=GetImageOption(image_info,"fuzz");
4109 if (option != (const char *) NULL)
4110 image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
4111 option=GetImageOption(image_info,"gravity");
4112 if (option != (const char *) NULL)
4113 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
4114 MagickFalse,option);
4115 option=GetImageOption(image_info,"green-primary");
4116 if (option != (const char *) NULL)
4117 {
4118 flags=ParseGeometry(option,&geometry_info);
4119 if ((flags & RhoValue) != 0)
4120 image->chromaticity.green_primary.x=geometry_info.rho;
4121 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4122 if ((flags & SigmaValue) != 0)
4123 image->chromaticity.green_primary.y=geometry_info.sigma;
4124 }
4125 option=GetImageOption(image_info,"intent");
4126 if (option != (const char *) NULL)
4127 image->rendering_intent=(RenderingIntent) ParseCommandOption(
4128 MagickIntentOptions,MagickFalse,option);
4129 option=GetImageOption(image_info,"intensity");
4130 if (option != (const char *) NULL)
4131 image->intensity=(PixelIntensityMethod) ParseCommandOption(
4132 MagickPixelIntensityOptions,MagickFalse,option);
4133 option=GetImageOption(image_info,"interlace");
4134 if (option != (const char *) NULL)
4135 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
4136 MagickFalse,option);
4137 option=GetImageOption(image_info,"interpolate");
4138 if (option != (const char *) NULL)
4139 image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
4140 MagickInterpolateOptions,MagickFalse,option);
4141 option=GetImageOption(image_info,"loop");
4142 if (option != (const char *) NULL)
4143 image->iterations=StringToUnsignedLong(option);
4144 option=GetImageOption(image_info,"mattecolor");
4145 if (option != (const char *) NULL)
4146 (void) QueryColorCompliance(option,AllCompliance,&image->matte_color,
4147 exception);
4148 option=GetImageOption(image_info,"orient");
4149 if (option != (const char *) NULL)
4150 image->orientation=(OrientationType) ParseCommandOption(
4151 MagickOrientationOptions,MagickFalse,option);
4152 option=GetImageOption(image_info,"page");
4153 if (option != (const char *) NULL)
4154 {
4155 char
4156 *geometry;
4157
4158 geometry=GetPageGeometry(option);
4159 flags=ParseAbsoluteGeometry(geometry,&image->page);
4160 geometry=DestroyString(geometry);
4161 }
4162 option=GetImageOption(image_info,"quality");
4163 if (option != (const char *) NULL)
4164 image->quality=StringToUnsignedLong(option);
4165 option=GetImageOption(image_info,"red-primary");
4166 if (option != (const char *) NULL)
4167 {
4168 flags=ParseGeometry(option,&geometry_info);
4169 if ((flags & RhoValue) != 0)
4170 image->chromaticity.red_primary.x=geometry_info.rho;
4171 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4172 if ((flags & SigmaValue) != 0)
4173 image->chromaticity.red_primary.y=geometry_info.sigma;
4174 }
4175 if (image_info->quality != UndefinedCompressionQuality)
4176 image->quality=image_info->quality;
4177 option=GetImageOption(image_info,"scene");
4178 if (option != (const char *) NULL)
4179 image->scene=StringToUnsignedLong(option);
4180 option=GetImageOption(image_info,"taint");
4181 if (option != (const char *) NULL)
4182 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
4183 MagickFalse,option);
4184 option=GetImageOption(image_info,"tile-offset");
4185 if (option != (const char *) NULL)
4186 {
4187 char
4188 *geometry;
4189
4190 geometry=GetPageGeometry(option);
4191 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4192 geometry=DestroyString(geometry);
4193 }
4194 option=GetImageOption(image_info,"transparent-color");
4195 if (option != (const char *) NULL)
4196 (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
4197 exception);
4198 option=GetImageOption(image_info,"type");
4199 if (option != (const char *) NULL)
4200 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
4201 option);
4202 option=GetImageOption(image_info,"units");
4203 units=image_info->units;
4204 if (option != (const char *) NULL)
4205 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
4206 MagickFalse,option);
4207 if (units != UndefinedResolution)
4208 {
4209 if (image->units != units)
4210 switch (image->units)
4211 {
4212 case PixelsPerInchResolution:
4213 {
4214 if (units == PixelsPerCentimeterResolution)
4215 {
4216 image->resolution.x/=2.54;
4217 image->resolution.y/=2.54;
4218 }
4219 break;
4220 }
4221 case PixelsPerCentimeterResolution:
4222 {
4223 if (units == PixelsPerInchResolution)
4224 {
4225 image->resolution.x=(double) ((size_t) (100.0*2.54*
4226 image->resolution.x+0.5))/100.0;
4227 image->resolution.y=(double) ((size_t) (100.0*2.54*
4228 image->resolution.y+0.5))/100.0;
4229 }
4230 break;
4231 }
4232 default:
4233 break;
4234 }
4235 image->units=units;
4236 option=GetImageOption(image_info,"density");
4237 if (option != (const char *) NULL)
4238 {
4239 flags=ParseGeometry(option,&geometry_info);
4240 if ((flags & RhoValue) != 0)
4241 image->resolution.x=geometry_info.rho;
4242 image->resolution.y=image->resolution.x;
4243 if ((flags & SigmaValue) != 0)
4244 image->resolution.y=geometry_info.sigma;
4245 }
4246 }
4247 option=GetImageOption(image_info,"virtual-pixel");
4248 if (option != (const char *) NULL)
4249 (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
4250 ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
4251 exception);
4252 option=GetImageOption(image_info,"white-point");
4253 if (option != (const char *) NULL)
4254 {
4255 flags=ParseGeometry(option,&geometry_info);
4256 if ((flags & RhoValue) != 0)
4257 image->chromaticity.white_point.x=geometry_info.rho;
4258 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4259 if ((flags & SigmaValue) != 0)
4260 image->chromaticity.white_point.y=geometry_info.sigma;
4261 }
4262 /*
4263 Pointer to allow the lookup of pre-image artifact will fallback to a global
4264 option setting/define. This saves a lot of duplication of global options
4265 into per-image artifacts, while ensuring only specifically set per-image
4266 artifacts are preserved when parenthesis ends.
4267 */
4268 if (image->image_info != (ImageInfo *) NULL)
4269 image->image_info=DestroyImageInfo(image->image_info);
4270 image->image_info=CloneImageInfo(image_info);
4271 return(MagickTrue);
4272}