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