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