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-2019 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/token.h"
100 #include "MagickCore/token-private.h"
101 #include "MagickCore/utility.h"
102 #include "MagickCore/utility-private.h"
103 #include "MagickCore/version.h"
104 #include "MagickCore/xwindow-private.h"
105
106 /*
107 Constant declaration.
108 */
109 const char
110 BackgroundColor[] = "#ffffff", /* white */
111 BorderColor[] = "#dfdfdf", /* gray */
112 DefaultTileFrame[] = "15x15+3+3",
113 DefaultTileGeometry[] = "120x120+4+3>",
114 DefaultTileLabel[] = "%f\n%G\n%b",
115 ForegroundColor[] = "#000", /* black */
116 LoadImageTag[] = "Load/Image",
117 LoadImagesTag[] = "Load/Images",
118 MatteColor[] = "#bdbdbd", /* gray */
119 PSDensityGeometry[] = "72.0x72.0",
120 PSPageGeometry[] = "612x792",
121 SaveImageTag[] = "Save/Image",
122 SaveImagesTag[] = "Save/Images",
123 TransparentColor[] = "#00000000"; /* transparent black */
124
125 const double
126 DefaultResolution = 72.0;
127
128 /*
129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130 % %
131 % %
132 % %
133 % A c q u i r e I m a g e %
134 % %
135 % %
136 % %
137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138 %
139 % AcquireImage() returns a pointer to an image structure initialized to
140 % default values.
141 %
142 % The format of the AcquireImage method is:
143 %
144 % Image *AcquireImage(const ImageInfo *image_info,ExceptionInfo *exception)
145 %
146 % A description of each parameter follows:
147 %
148 % o image_info: Many of the image default values are set from this
149 % structure. For example, filename, compression, depth, background color,
150 % and others.
151 %
152 % o exception: return any errors or warnings in this structure.
153 %
154 */
AcquireImage(const ImageInfo * image_info,ExceptionInfo * exception)155 MagickExport Image *AcquireImage(const ImageInfo *image_info,
156 ExceptionInfo *exception)
157 {
158 const char
159 *option;
160
161 Image
162 *image;
163
164 MagickStatusType
165 flags;
166
167 /*
168 Allocate image structure.
169 */
170 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
171 image=(Image *) AcquireCriticalMemory(sizeof(*image));
172 (void) memset(image,0,sizeof(*image));
173 /*
174 Initialize Image structure.
175 */
176 (void) CopyMagickString(image->magick,"MIFF",MagickPathExtent);
177 image->storage_class=DirectClass;
178 image->depth=MAGICKCORE_QUANTUM_DEPTH;
179 image->colorspace=sRGBColorspace;
180 image->rendering_intent=PerceptualIntent;
181 image->gamma=1.000f/2.200f;
182 image->chromaticity.red_primary.x=0.6400f;
183 image->chromaticity.red_primary.y=0.3300f;
184 image->chromaticity.red_primary.z=0.0300f;
185 image->chromaticity.green_primary.x=0.3000f;
186 image->chromaticity.green_primary.y=0.6000f;
187 image->chromaticity.green_primary.z=0.1000f;
188 image->chromaticity.blue_primary.x=0.1500f;
189 image->chromaticity.blue_primary.y=0.0600f;
190 image->chromaticity.blue_primary.z=0.7900f;
191 image->chromaticity.white_point.x=0.3127f;
192 image->chromaticity.white_point.y=0.3290f;
193 image->chromaticity.white_point.z=0.3583f;
194 image->interlace=NoInterlace;
195 image->ticks_per_second=UndefinedTicksPerSecond;
196 image->compose=OverCompositeOp;
197 (void) QueryColorCompliance(MatteColor,AllCompliance,&image->matte_color,
198 exception);
199 (void) QueryColorCompliance(BackgroundColor,AllCompliance,
200 &image->background_color,exception);
201 (void) QueryColorCompliance(BorderColor,AllCompliance,&image->border_color,
202 exception);
203 (void) QueryColorCompliance(TransparentColor,AllCompliance,
204 &image->transparent_color,exception);
205 GetTimerInfo(&image->timer);
206 image->cache=AcquirePixelCache(0);
207 image->channel_mask=DefaultChannels;
208 image->channel_map=AcquirePixelChannelMap();
209 image->blob=CloneBlobInfo((BlobInfo *) NULL);
210 image->timestamp=time((time_t *) NULL);
211 image->debug=IsEventLogging();
212 image->reference_count=1;
213 image->semaphore=AcquireSemaphoreInfo();
214 image->signature=MagickCoreSignature;
215 if (image_info == (ImageInfo *) NULL)
216 return(image);
217 /*
218 Transfer image info.
219 */
220 SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
221 MagickFalse);
222 (void) CopyMagickString(image->filename,image_info->filename,
223 MagickPathExtent);
224 (void) CopyMagickString(image->magick_filename,image_info->filename,
225 MagickPathExtent);
226 (void) CopyMagickString(image->magick,image_info->magick,MagickPathExtent);
227 if (image_info->size != (char *) NULL)
228 {
229 (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
230 image->columns=image->extract_info.width;
231 image->rows=image->extract_info.height;
232 image->offset=image->extract_info.x;
233 image->extract_info.x=0;
234 image->extract_info.y=0;
235 }
236 if (image_info->extract != (char *) NULL)
237 {
238 RectangleInfo
239 geometry;
240
241 (void) memset(&geometry,0,sizeof(geometry));
242 flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
243 if (((flags & XValue) != 0) || ((flags & YValue) != 0))
244 {
245 image->extract_info=geometry;
246 Swap(image->columns,image->extract_info.width);
247 Swap(image->rows,image->extract_info.height);
248 }
249 }
250 image->compression=image_info->compression;
251 image->quality=image_info->quality;
252 image->endian=image_info->endian;
253 image->interlace=image_info->interlace;
254 image->units=image_info->units;
255 if (image_info->density != (char *) NULL)
256 {
257 GeometryInfo
258 geometry_info;
259
260 flags=ParseGeometry(image_info->density,&geometry_info);
261 image->resolution.x=geometry_info.rho;
262 image->resolution.y=geometry_info.sigma;
263 if ((flags & SigmaValue) == 0)
264 image->resolution.y=image->resolution.x;
265 }
266 if (image_info->page != (char *) NULL)
267 {
268 char
269 *geometry;
270
271 image->page=image->extract_info;
272 geometry=GetPageGeometry(image_info->page);
273 (void) ParseAbsoluteGeometry(geometry,&image->page);
274 geometry=DestroyString(geometry);
275 }
276 if (image_info->depth != 0)
277 image->depth=image_info->depth;
278 image->dither=image_info->dither;
279 image->matte_color=image_info->matte_color;
280 image->background_color=image_info->background_color;
281 image->border_color=image_info->border_color;
282 image->transparent_color=image_info->transparent_color;
283 image->ping=image_info->ping;
284 image->progress_monitor=image_info->progress_monitor;
285 image->client_data=image_info->client_data;
286 if (image_info->cache != (void *) NULL)
287 ClonePixelCacheMethods(image->cache,image_info->cache);
288 /*
289 Set all global options that map to per-image settings.
290 */
291 (void) SyncImageSettings(image_info,image,exception);
292 /*
293 Global options that are only set for new images.
294 */
295 option=GetImageOption(image_info,"delay");
296 if (option != (const char *) NULL)
297 {
298 GeometryInfo
299 geometry_info;
300
301 flags=ParseGeometry(option,&geometry_info);
302 if ((flags & GreaterValue) != 0)
303 {
304 if (image->delay > (size_t) floor(geometry_info.rho+0.5))
305 image->delay=(size_t) floor(geometry_info.rho+0.5);
306 }
307 else
308 if ((flags & LessValue) != 0)
309 {
310 if (image->delay < (size_t) floor(geometry_info.rho+0.5))
311 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
312 }
313 else
314 image->delay=(size_t) floor(geometry_info.rho+0.5);
315 if ((flags & SigmaValue) != 0)
316 image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
317 }
318 option=GetImageOption(image_info,"dispose");
319 if (option != (const char *) NULL)
320 image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
321 MagickFalse,option);
322 return(image);
323 }
324
325 /*
326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
327 % %
328 % %
329 % %
330 % A c q u i r e I m a g e I n f o %
331 % %
332 % %
333 % %
334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 %
336 % AcquireImageInfo() allocates the ImageInfo structure.
337 %
338 % The format of the AcquireImageInfo method is:
339 %
340 % ImageInfo *AcquireImageInfo(void)
341 %
342 */
AcquireImageInfo(void)343 MagickExport ImageInfo *AcquireImageInfo(void)
344 {
345 ImageInfo
346 *image_info;
347
348 image_info=(ImageInfo *) AcquireCriticalMemory(sizeof(*image_info));
349 GetImageInfo(image_info);
350 return(image_info);
351 }
352
353 /*
354 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355 % %
356 % %
357 % %
358 % A c q u i r e N e x t I m a g e %
359 % %
360 % %
361 % %
362 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
363 %
364 % AcquireNextImage() initializes the next image in a sequence to
365 % default values. The next member of image points to the newly allocated
366 % image. If there is a memory shortage, next is assigned NULL.
367 %
368 % The format of the AcquireNextImage method is:
369 %
370 % void AcquireNextImage(const ImageInfo *image_info,Image *image,
371 % ExceptionInfo *exception)
372 %
373 % A description of each parameter follows:
374 %
375 % o image_info: Many of the image default values are set from this
376 % structure. For example, filename, compression, depth, background color,
377 % and others.
378 %
379 % o image: the image.
380 %
381 % o exception: return any errors or warnings in this structure.
382 %
383 */
AcquireNextImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)384 MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image,
385 ExceptionInfo *exception)
386 {
387 /*
388 Allocate image structure.
389 */
390 assert(image != (Image *) NULL);
391 assert(image->signature == MagickCoreSignature);
392 if (image->debug != MagickFalse)
393 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
394 image->next=AcquireImage(image_info,exception);
395 if (GetNextImageInList(image) == (Image *) NULL)
396 return;
397 (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
398 MagickPathExtent);
399 if (image_info != (ImageInfo *) NULL)
400 (void) CopyMagickString(GetNextImageInList(image)->filename,
401 image_info->filename,MagickPathExtent);
402 DestroyBlob(GetNextImageInList(image));
403 image->next->blob=ReferenceBlob(image->blob);
404 image->next->endian=image->endian;
405 image->next->scene=image->scene+1;
406 image->next->previous=image;
407 }
408
409 /*
410 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 % %
412 % %
413 % %
414 % A p p e n d I m a g e s %
415 % %
416 % %
417 % %
418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 %
420 % AppendImages() takes all images from the current image pointer to the end
421 % of the image list and appends them to each other top-to-bottom if the
422 % stack parameter is true, otherwise left-to-right.
423 %
424 % The current gravity setting effects how the image is justified in the
425 % final image.
426 %
427 % The format of the AppendImages method is:
428 %
429 % Image *AppendImages(const Image *images,const MagickBooleanType stack,
430 % ExceptionInfo *exception)
431 %
432 % A description of each parameter follows:
433 %
434 % o images: the image sequence.
435 %
436 % o stack: A value other than 0 stacks the images top-to-bottom.
437 %
438 % o exception: return any errors or warnings in this structure.
439 %
440 */
AppendImages(const Image * images,const MagickBooleanType stack,ExceptionInfo * exception)441 MagickExport Image *AppendImages(const Image *images,
442 const MagickBooleanType stack,ExceptionInfo *exception)
443 {
444 #define AppendImageTag "Append/Image"
445
446 CacheView
447 *append_view;
448
449 Image
450 *append_image;
451
452 MagickBooleanType
453 homogeneous_colorspace,
454 status;
455
456 MagickOffsetType
457 n;
458
459 PixelTrait
460 alpha_trait;
461
462 RectangleInfo
463 geometry;
464
465 register const Image
466 *next;
467
468 size_t
469 depth,
470 height,
471 number_images,
472 width;
473
474 ssize_t
475 x_offset,
476 y,
477 y_offset;
478
479 /*
480 Compute maximum area of appended area.
481 */
482 assert(images != (Image *) NULL);
483 assert(images->signature == MagickCoreSignature);
484 if (images->debug != MagickFalse)
485 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
486 assert(exception != (ExceptionInfo *) NULL);
487 assert(exception->signature == MagickCoreSignature);
488 alpha_trait=images->alpha_trait;
489 number_images=1;
490 width=images->columns;
491 height=images->rows;
492 depth=images->depth;
493 homogeneous_colorspace=MagickTrue;
494 next=GetNextImageInList(images);
495 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
496 {
497 if (next->depth > depth)
498 depth=next->depth;
499 if (next->colorspace != images->colorspace)
500 homogeneous_colorspace=MagickFalse;
501 if (next->alpha_trait != UndefinedPixelTrait)
502 alpha_trait=BlendPixelTrait;
503 number_images++;
504 if (stack != MagickFalse)
505 {
506 if (next->columns > width)
507 width=next->columns;
508 height+=next->rows;
509 continue;
510 }
511 width+=next->columns;
512 if (next->rows > height)
513 height=next->rows;
514 }
515 /*
516 Append images.
517 */
518 append_image=CloneImage(images,width,height,MagickTrue,exception);
519 if (append_image == (Image *) NULL)
520 return((Image *) NULL);
521 if (SetImageStorageClass(append_image,DirectClass,exception) == MagickFalse)
522 {
523 append_image=DestroyImage(append_image);
524 return((Image *) NULL);
525 }
526 if (homogeneous_colorspace == MagickFalse)
527 (void) SetImageColorspace(append_image,sRGBColorspace,exception);
528 append_image->depth=depth;
529 append_image->alpha_trait=alpha_trait;
530 append_image->page=images->page;
531 (void) SetImageBackgroundColor(append_image,exception);
532 status=MagickTrue;
533 x_offset=0;
534 y_offset=0;
535 next=images;
536 append_view=AcquireAuthenticCacheView(append_image,exception);
537 for (n=0; n < (MagickOffsetType) number_images; n++)
538 {
539 CacheView
540 *image_view;
541
542 MagickBooleanType
543 proceed;
544
545 SetGeometry(append_image,&geometry);
546 GravityAdjustGeometry(next->columns,next->rows,next->gravity,&geometry);
547 if (stack != MagickFalse)
548 x_offset-=geometry.x;
549 else
550 y_offset-=geometry.y;
551 image_view=AcquireVirtualCacheView(next,exception);
552 #if defined(MAGICKCORE_OPENMP_SUPPORT)
553 #pragma omp parallel for schedule(static) shared(status) \
554 magick_number_threads(next,next,next->rows,1)
555 #endif
556 for (y=0; y < (ssize_t) next->rows; y++)
557 {
558 MagickBooleanType
559 sync;
560
561 PixelInfo
562 pixel;
563
564 register const Quantum
565 *magick_restrict p;
566
567 register Quantum
568 *magick_restrict q;
569
570 register ssize_t
571 x;
572
573 if (status == MagickFalse)
574 continue;
575 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
576 q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
577 next->columns,1,exception);
578 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
579 {
580 status=MagickFalse;
581 continue;
582 }
583 GetPixelInfo(next,&pixel);
584 for (x=0; x < (ssize_t) next->columns; x++)
585 {
586 GetPixelInfoPixel(next,p,&pixel);
587 SetPixelViaPixelInfo(append_image,&pixel,q);
588 p+=GetPixelChannels(next);
589 q+=GetPixelChannels(append_image);
590 }
591 sync=SyncCacheViewAuthenticPixels(append_view,exception);
592 if (sync == MagickFalse)
593 status=MagickFalse;
594 }
595 image_view=DestroyCacheView(image_view);
596 if (stack == MagickFalse)
597 {
598 x_offset+=(ssize_t) next->columns;
599 y_offset=0;
600 }
601 else
602 {
603 x_offset=0;
604 y_offset+=(ssize_t) next->rows;
605 }
606 proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
607 if (proceed == MagickFalse)
608 break;
609 next=GetNextImageInList(next);
610 }
611 append_view=DestroyCacheView(append_view);
612 if (status == MagickFalse)
613 append_image=DestroyImage(append_image);
614 return(append_image);
615 }
616
617 /*
618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619 % %
620 % %
621 % %
622 % C a t c h I m a g e E x c e p t i o n %
623 % %
624 % %
625 % %
626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
627 %
628 % CatchImageException() returns if no exceptions are found in the image
629 % sequence, otherwise it determines the most severe exception and reports
630 % it as a warning or error depending on the severity.
631 %
632 % The format of the CatchImageException method is:
633 %
634 % ExceptionType CatchImageException(Image *image)
635 %
636 % A description of each parameter follows:
637 %
638 % o image: An image sequence.
639 %
640 */
CatchImageException(Image * image)641 MagickExport ExceptionType CatchImageException(Image *image)
642 {
643 ExceptionInfo
644 *exception;
645
646 ExceptionType
647 severity;
648
649 assert(image != (const Image *) NULL);
650 assert(image->signature == MagickCoreSignature);
651 if (image->debug != MagickFalse)
652 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
653 exception=AcquireExceptionInfo();
654 CatchException(exception);
655 severity=exception->severity;
656 exception=DestroyExceptionInfo(exception);
657 return(severity);
658 }
659
660 /*
661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 % %
663 % %
664 % %
665 % C l i p I m a g e P a t h %
666 % %
667 % %
668 % %
669 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 %
671 % ClipImagePath() sets the image clip mask based any clipping path information
672 % if it exists.
673 %
674 % The format of the ClipImagePath method is:
675 %
676 % MagickBooleanType ClipImagePath(Image *image,const char *pathname,
677 % const MagickBooleanType inside,ExceptionInfo *exception)
678 %
679 % A description of each parameter follows:
680 %
681 % o image: the image.
682 %
683 % o pathname: name of clipping path resource. If name is preceded by #, use
684 % clipping path numbered by name.
685 %
686 % o inside: if non-zero, later operations take effect inside clipping path.
687 % Otherwise later operations take effect outside clipping path.
688 %
689 % o exception: return any errors or warnings in this structure.
690 %
691 */
692
ClipImage(Image * image,ExceptionInfo * exception)693 MagickExport MagickBooleanType ClipImage(Image *image,ExceptionInfo *exception)
694 {
695 return(ClipImagePath(image,"#1",MagickTrue,exception));
696 }
697
ClipImagePath(Image * image,const char * pathname,const MagickBooleanType inside,ExceptionInfo * exception)698 MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
699 const MagickBooleanType inside,ExceptionInfo *exception)
700 {
701 #define ClipImagePathTag "ClipPath/Image"
702
703 char
704 *property;
705
706 const char
707 *value;
708
709 Image
710 *clip_mask;
711
712 ImageInfo
713 *image_info;
714
715 assert(image != (const Image *) NULL);
716 assert(image->signature == MagickCoreSignature);
717 if (image->debug != MagickFalse)
718 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
719 assert(pathname != NULL);
720 property=AcquireString(pathname);
721 (void) FormatLocaleString(property,MagickPathExtent,"8BIM:1999,2998:%s",
722 pathname);
723 value=GetImageProperty(image,property,exception);
724 property=DestroyString(property);
725 if (value == (const char *) NULL)
726 {
727 ThrowFileException(exception,OptionError,"NoClipPathDefined",
728 image->filename);
729 return(MagickFalse);
730 }
731 image_info=AcquireImageInfo();
732 (void) CopyMagickString(image_info->filename,image->filename,
733 MagickPathExtent);
734 (void) ConcatenateMagickString(image_info->filename,pathname,
735 MagickPathExtent);
736 clip_mask=BlobToImage(image_info,value,strlen(value),exception);
737 image_info=DestroyImageInfo(image_info);
738 if (clip_mask == (Image *) NULL)
739 return(MagickFalse);
740 if (clip_mask->storage_class == PseudoClass)
741 {
742 (void) SyncImage(clip_mask,exception);
743 if (SetImageStorageClass(clip_mask,DirectClass,exception) == MagickFalse)
744 return(MagickFalse);
745 }
746 if (inside == MagickFalse)
747 (void) NegateImage(clip_mask,MagickFalse,exception);
748 (void) FormatLocaleString(clip_mask->magick_filename,MagickPathExtent,
749 "8BIM:1999,2998:%s\nPS",pathname);
750 (void) SetImageMask(image,WritePixelMask,clip_mask,exception);
751 clip_mask=DestroyImage(clip_mask);
752 return(MagickTrue);
753 }
754
755 /*
756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
757 % %
758 % %
759 % %
760 % C l o n e I m a g e %
761 % %
762 % %
763 % %
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765 %
766 % CloneImage() copies an image and returns the copy as a new image object.
767 %
768 % If the specified columns and rows is 0, an exact copy of the image is
769 % returned, otherwise the pixel data is undefined and must be initialized
770 % with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
771 % failure, a NULL image is returned and exception describes the reason for the
772 % failure.
773 %
774 % The format of the CloneImage method is:
775 %
776 % Image *CloneImage(const Image *image,const size_t columns,
777 % const size_t rows,const MagickBooleanType orphan,
778 % ExceptionInfo *exception)
779 %
780 % A description of each parameter follows:
781 %
782 % o image: the image.
783 %
784 % o columns: the number of columns in the cloned image.
785 %
786 % o rows: the number of rows in the cloned image.
787 %
788 % o detach: With a value other than 0, the cloned image is detached from
789 % its parent I/O stream.
790 %
791 % o exception: return any errors or warnings in this structure.
792 %
793 */
CloneImage(const Image * image,const size_t columns,const size_t rows,const MagickBooleanType detach,ExceptionInfo * exception)794 MagickExport Image *CloneImage(const Image *image,const size_t columns,
795 const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
796 {
797 Image
798 *clone_image;
799
800 double
801 scale;
802
803 size_t
804 length;
805
806 /*
807 Clone the image.
808 */
809 assert(image != (const Image *) NULL);
810 assert(image->signature == MagickCoreSignature);
811 if (image->debug != MagickFalse)
812 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
813 assert(exception != (ExceptionInfo *) NULL);
814 assert(exception->signature == MagickCoreSignature);
815 if ((image->columns == 0) || (image->rows == 0))
816 {
817 (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
818 "NegativeOrZeroImageSize","`%s'",image->filename);
819 return((Image *) NULL);
820 }
821 clone_image=(Image *) AcquireCriticalMemory(sizeof(*clone_image));
822 (void) memset(clone_image,0,sizeof(*clone_image));
823 clone_image->signature=MagickCoreSignature;
824 clone_image->storage_class=image->storage_class;
825 clone_image->number_channels=image->number_channels;
826 clone_image->number_meta_channels=image->number_meta_channels;
827 clone_image->metacontent_extent=image->metacontent_extent;
828 clone_image->colorspace=image->colorspace;
829 clone_image->alpha_trait=image->alpha_trait;
830 clone_image->channels=image->channels;
831 clone_image->mask_trait=image->mask_trait;
832 clone_image->columns=image->columns;
833 clone_image->rows=image->rows;
834 clone_image->dither=image->dither;
835 clone_image->image_info=CloneImageInfo(image->image_info);
836 (void) CloneImageProfiles(clone_image,image);
837 (void) CloneImageProperties(clone_image,image);
838 (void) CloneImageArtifacts(clone_image,image);
839 GetTimerInfo(&clone_image->timer);
840 if (image->ascii85 != (void *) NULL)
841 Ascii85Initialize(clone_image);
842 clone_image->extent=image->extent;
843 clone_image->magick_columns=image->magick_columns;
844 clone_image->magick_rows=image->magick_rows;
845 clone_image->type=image->type;
846 clone_image->channel_mask=image->channel_mask;
847 clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
848 (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
849 MagickPathExtent);
850 (void) CopyMagickString(clone_image->magick,image->magick,MagickPathExtent);
851 (void) CopyMagickString(clone_image->filename,image->filename,
852 MagickPathExtent);
853 clone_image->progress_monitor=image->progress_monitor;
854 clone_image->client_data=image->client_data;
855 clone_image->reference_count=1;
856 clone_image->next=image->next;
857 clone_image->previous=image->previous;
858 clone_image->list=NewImageList();
859 if (detach == MagickFalse)
860 clone_image->blob=ReferenceBlob(image->blob);
861 else
862 {
863 clone_image->next=NewImageList();
864 clone_image->previous=NewImageList();
865 clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
866 }
867 clone_image->ping=image->ping;
868 clone_image->debug=IsEventLogging();
869 clone_image->semaphore=AcquireSemaphoreInfo();
870 if (image->colormap != (PixelInfo *) NULL)
871 {
872 /*
873 Allocate and copy the image colormap.
874 */
875 clone_image->colors=image->colors;
876 length=(size_t) image->colors;
877 clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length+1,
878 sizeof(*clone_image->colormap));
879 if (clone_image->colormap == (PixelInfo *) NULL)
880 {
881 clone_image=DestroyImage(clone_image);
882 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
883 }
884 (void) memcpy(clone_image->colormap,image->colormap,length*
885 sizeof(*clone_image->colormap));
886 }
887 if ((columns == 0) || (rows == 0))
888 {
889 if (image->montage != (char *) NULL)
890 (void) CloneString(&clone_image->montage,image->montage);
891 if (image->directory != (char *) NULL)
892 (void) CloneString(&clone_image->directory,image->directory);
893 clone_image->cache=ReferencePixelCache(image->cache);
894 return(clone_image);
895 }
896 scale=1.0;
897 if (image->columns != 0)
898 scale=(double) columns/(double) image->columns;
899 clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
900 clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
901 clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
902 scale=1.0;
903 if (image->rows != 0)
904 scale=(double) rows/(double) image->rows;
905 clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
906 clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
907 clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
908 clone_image->cache=ClonePixelCache(image->cache);
909 if (SetImageExtent(clone_image,columns,rows,exception) == MagickFalse)
910 clone_image=DestroyImage(clone_image);
911 return(clone_image);
912 }
913
914 /*
915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916 % %
917 % %
918 % %
919 % C l o n e I m a g e I n f o %
920 % %
921 % %
922 % %
923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
924 %
925 % CloneImageInfo() makes a copy of the given image info structure. If
926 % NULL is specified, a new image info structure is created initialized to
927 % default values.
928 %
929 % The format of the CloneImageInfo method is:
930 %
931 % ImageInfo *CloneImageInfo(const ImageInfo *image_info)
932 %
933 % A description of each parameter follows:
934 %
935 % o image_info: the image info.
936 %
937 */
CloneImageInfo(const ImageInfo * image_info)938 MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
939 {
940 ImageInfo
941 *clone_info;
942
943 clone_info=AcquireImageInfo();
944 if (image_info == (ImageInfo *) NULL)
945 return(clone_info);
946 clone_info->compression=image_info->compression;
947 clone_info->temporary=image_info->temporary;
948 clone_info->adjoin=image_info->adjoin;
949 clone_info->antialias=image_info->antialias;
950 clone_info->scene=image_info->scene;
951 clone_info->number_scenes=image_info->number_scenes;
952 clone_info->depth=image_info->depth;
953 if (image_info->size != (char *) NULL)
954 (void) CloneString(&clone_info->size,image_info->size);
955 if (image_info->extract != (char *) NULL)
956 (void) CloneString(&clone_info->extract,image_info->extract);
957 if (image_info->scenes != (char *) NULL)
958 (void) CloneString(&clone_info->scenes,image_info->scenes);
959 if (image_info->page != (char *) NULL)
960 (void) CloneString(&clone_info->page,image_info->page);
961 clone_info->interlace=image_info->interlace;
962 clone_info->endian=image_info->endian;
963 clone_info->units=image_info->units;
964 clone_info->quality=image_info->quality;
965 if (image_info->sampling_factor != (char *) NULL)
966 (void) CloneString(&clone_info->sampling_factor,
967 image_info->sampling_factor);
968 if (image_info->server_name != (char *) NULL)
969 (void) CloneString(&clone_info->server_name,image_info->server_name);
970 if (image_info->font != (char *) NULL)
971 (void) CloneString(&clone_info->font,image_info->font);
972 if (image_info->texture != (char *) NULL)
973 (void) CloneString(&clone_info->texture,image_info->texture);
974 if (image_info->density != (char *) NULL)
975 (void) CloneString(&clone_info->density,image_info->density);
976 clone_info->pointsize=image_info->pointsize;
977 clone_info->fuzz=image_info->fuzz;
978 clone_info->matte_color=image_info->matte_color;
979 clone_info->background_color=image_info->background_color;
980 clone_info->border_color=image_info->border_color;
981 clone_info->transparent_color=image_info->transparent_color;
982 clone_info->dither=image_info->dither;
983 clone_info->monochrome=image_info->monochrome;
984 clone_info->colorspace=image_info->colorspace;
985 clone_info->type=image_info->type;
986 clone_info->orientation=image_info->orientation;
987 clone_info->ping=image_info->ping;
988 clone_info->verbose=image_info->verbose;
989 clone_info->progress_monitor=image_info->progress_monitor;
990 clone_info->client_data=image_info->client_data;
991 clone_info->cache=image_info->cache;
992 if (image_info->cache != (void *) NULL)
993 clone_info->cache=ReferencePixelCache(image_info->cache);
994 if (image_info->profile != (void *) NULL)
995 clone_info->profile=(void *) CloneStringInfo((StringInfo *)
996 image_info->profile);
997 SetImageInfoFile(clone_info,image_info->file);
998 SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
999 clone_info->stream=image_info->stream;
1000 clone_info->custom_stream=image_info->custom_stream;
1001 (void) CopyMagickString(clone_info->magick,image_info->magick,
1002 MagickPathExtent);
1003 (void) CopyMagickString(clone_info->unique,image_info->unique,
1004 MagickPathExtent);
1005 (void) CopyMagickString(clone_info->filename,image_info->filename,
1006 MagickPathExtent);
1007 clone_info->channel=image_info->channel;
1008 (void) CloneImageOptions(clone_info,image_info);
1009 clone_info->debug=IsEventLogging();
1010 clone_info->signature=image_info->signature;
1011 return(clone_info);
1012 }
1013
1014 /*
1015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1016 % %
1017 % %
1018 % %
1019 % C o p y I m a g e P i x e l s %
1020 % %
1021 % %
1022 % %
1023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1024 %
1025 % CopyImagePixels() copies pixels from the source image as defined by the
1026 % geometry the destination image at the specified offset.
1027 %
1028 % The format of the CopyImagePixels method is:
1029 %
1030 % MagickBooleanType CopyImagePixels(Image *image,const Image *source_image,
1031 % const RectangleInfo *geometry,const OffsetInfo *offset,
1032 % ExceptionInfo *exception);
1033 %
1034 % A description of each parameter follows:
1035 %
1036 % o image: the destination image.
1037 %
1038 % o source_image: the source image.
1039 %
1040 % o geometry: define the dimensions of the source pixel rectangle.
1041 %
1042 % o offset: define the offset in the destination image.
1043 %
1044 % o exception: return any errors or warnings in this structure.
1045 %
1046 */
CopyImagePixels(Image * image,const Image * source_image,const RectangleInfo * geometry,const OffsetInfo * offset,ExceptionInfo * exception)1047 MagickExport MagickBooleanType CopyImagePixels(Image *image,
1048 const Image *source_image,const RectangleInfo *geometry,
1049 const OffsetInfo *offset,ExceptionInfo *exception)
1050 {
1051 #define CopyImageTag "Copy/Image"
1052
1053 CacheView
1054 *image_view,
1055 *source_view;
1056
1057 MagickBooleanType
1058 status;
1059
1060 MagickOffsetType
1061 progress;
1062
1063 ssize_t
1064 y;
1065
1066 assert(image != (Image *) NULL);
1067 if (image->debug != MagickFalse)
1068 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1069 assert(source_image != (Image *) NULL);
1070 assert(geometry != (RectangleInfo *) NULL);
1071 assert(offset != (OffsetInfo *) NULL);
1072 if ((offset->x < 0) || (offset->y < 0) ||
1073 ((ssize_t) (offset->x+geometry->width) > (ssize_t) image->columns) ||
1074 ((ssize_t) (offset->y+geometry->height) > (ssize_t) image->rows))
1075 ThrowBinaryException(OptionError,"GeometryDoesNotContainImage",
1076 image->filename);
1077 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1078 return(MagickFalse);
1079 /*
1080 Copy image pixels.
1081 */
1082 status=MagickTrue;
1083 progress=0;
1084 source_view=AcquireVirtualCacheView(source_image,exception);
1085 image_view=AcquireAuthenticCacheView(image,exception);
1086 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1087 #pragma omp parallel for schedule(static) shared(progress,status) \
1088 magick_number_threads(image,source_image,geometry->height,1)
1089 #endif
1090 for (y=0; y < (ssize_t) geometry->height; y++)
1091 {
1092 MagickBooleanType
1093 sync;
1094
1095 register const Quantum
1096 *magick_restrict p;
1097
1098 register ssize_t
1099 x;
1100
1101 register Quantum
1102 *magick_restrict q;
1103
1104 if (status == MagickFalse)
1105 continue;
1106 p=GetCacheViewVirtualPixels(source_view,geometry->x,y+geometry->y,
1107 geometry->width,1,exception);
1108 q=QueueCacheViewAuthenticPixels(image_view,offset->x,y+offset->y,
1109 geometry->width,1,exception);
1110 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1111 {
1112 status=MagickFalse;
1113 continue;
1114 }
1115 for (x=0; x < (ssize_t) geometry->width; x++)
1116 {
1117 register ssize_t
1118 i;
1119
1120 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1121 {
1122 PixelChannel channel = GetPixelChannelChannel(image,i);
1123 PixelTrait traits = GetPixelChannelTraits(image,channel);
1124 PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1125 if ((traits == UndefinedPixelTrait) ||
1126 ((traits & UpdatePixelTrait) == 0) ||
1127 (source_traits == UndefinedPixelTrait))
1128 continue;
1129 SetPixelChannel(image,channel,p[i],q);
1130 }
1131 p+=GetPixelChannels(source_image);
1132 q+=GetPixelChannels(image);
1133 }
1134 sync=SyncCacheViewAuthenticPixels(image_view,exception);
1135 if (sync == MagickFalse)
1136 status=MagickFalse;
1137 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1138 {
1139 MagickBooleanType
1140 proceed;
1141
1142 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1143 #pragma omp atomic
1144 #endif
1145 progress++;
1146 proceed=SetImageProgress(image,CopyImageTag,progress,image->rows);
1147 if (proceed == MagickFalse)
1148 status=MagickFalse;
1149 }
1150 }
1151 source_view=DestroyCacheView(source_view);
1152 image_view=DestroyCacheView(image_view);
1153 return(status);
1154 }
1155
1156 /*
1157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 % %
1159 % %
1160 % %
1161 % D e s t r o y I m a g e %
1162 % %
1163 % %
1164 % %
1165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1166 %
1167 % DestroyImage() dereferences an image, deallocating memory associated with
1168 % the image if the reference count becomes zero.
1169 %
1170 % The format of the DestroyImage method is:
1171 %
1172 % Image *DestroyImage(Image *image)
1173 %
1174 % A description of each parameter follows:
1175 %
1176 % o image: the image.
1177 %
1178 */
DestroyImage(Image * image)1179 MagickExport Image *DestroyImage(Image *image)
1180 {
1181 MagickBooleanType
1182 destroy;
1183
1184 /*
1185 Dereference image.
1186 */
1187 assert(image != (Image *) NULL);
1188 assert(image->signature == MagickCoreSignature);
1189 if (image->debug != MagickFalse)
1190 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1191 destroy=MagickFalse;
1192 LockSemaphoreInfo(image->semaphore);
1193 image->reference_count--;
1194 if (image->reference_count == 0)
1195 destroy=MagickTrue;
1196 UnlockSemaphoreInfo(image->semaphore);
1197 if (destroy == MagickFalse)
1198 return((Image *) NULL);
1199 /*
1200 Destroy image.
1201 */
1202 DestroyImagePixels(image);
1203 image->channel_map=DestroyPixelChannelMap(image->channel_map);
1204 if (image->montage != (char *) NULL)
1205 image->montage=DestroyString(image->montage);
1206 if (image->directory != (char *) NULL)
1207 image->directory=DestroyString(image->directory);
1208 if (image->colormap != (PixelInfo *) NULL)
1209 image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
1210 if (image->geometry != (char *) NULL)
1211 image->geometry=DestroyString(image->geometry);
1212 DestroyImageProfiles(image);
1213 DestroyImageProperties(image);
1214 DestroyImageArtifacts(image);
1215 if (image->ascii85 != (Ascii85Info *) NULL)
1216 image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1217 if (image->image_info != (ImageInfo *) NULL)
1218 image->image_info=DestroyImageInfo(image->image_info);
1219 DestroyBlob(image);
1220 if (image->semaphore != (SemaphoreInfo *) NULL)
1221 RelinquishSemaphoreInfo(&image->semaphore);
1222 image->signature=(~MagickCoreSignature);
1223 image=(Image *) RelinquishMagickMemory(image);
1224 return(image);
1225 }
1226
1227 /*
1228 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1229 % %
1230 % %
1231 % %
1232 % D e s t r o y I m a g e I n f o %
1233 % %
1234 % %
1235 % %
1236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1237 %
1238 % DestroyImageInfo() deallocates memory associated with an ImageInfo
1239 % structure.
1240 %
1241 % The format of the DestroyImageInfo method is:
1242 %
1243 % ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1244 %
1245 % A description of each parameter follows:
1246 %
1247 % o image_info: the image info.
1248 %
1249 */
DestroyImageInfo(ImageInfo * image_info)1250 MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1251 {
1252 assert(image_info != (ImageInfo *) NULL);
1253 assert(image_info->signature == MagickCoreSignature);
1254 if (image_info->debug != MagickFalse)
1255 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1256 image_info->filename);
1257 if (image_info->size != (char *) NULL)
1258 image_info->size=DestroyString(image_info->size);
1259 if (image_info->extract != (char *) NULL)
1260 image_info->extract=DestroyString(image_info->extract);
1261 if (image_info->scenes != (char *) NULL)
1262 image_info->scenes=DestroyString(image_info->scenes);
1263 if (image_info->page != (char *) NULL)
1264 image_info->page=DestroyString(image_info->page);
1265 if (image_info->sampling_factor != (char *) NULL)
1266 image_info->sampling_factor=DestroyString(
1267 image_info->sampling_factor);
1268 if (image_info->server_name != (char *) NULL)
1269 image_info->server_name=DestroyString(
1270 image_info->server_name);
1271 if (image_info->font != (char *) NULL)
1272 image_info->font=DestroyString(image_info->font);
1273 if (image_info->texture != (char *) NULL)
1274 image_info->texture=DestroyString(image_info->texture);
1275 if (image_info->density != (char *) NULL)
1276 image_info->density=DestroyString(image_info->density);
1277 if (image_info->cache != (void *) NULL)
1278 image_info->cache=DestroyPixelCache(image_info->cache);
1279 if (image_info->profile != (StringInfo *) NULL)
1280 image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1281 image_info->profile);
1282 DestroyImageOptions(image_info);
1283 image_info->signature=(~MagickCoreSignature);
1284 image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1285 return(image_info);
1286 }
1287
1288 /*
1289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1290 % %
1291 % %
1292 % %
1293 + D i s a s s o c i a t e I m a g e S t r e a m %
1294 % %
1295 % %
1296 % %
1297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1298 %
1299 % DisassociateImageStream() disassociates the image stream. It checks if the
1300 % blob of the specified image is referenced by other images. If the reference
1301 % count is higher then 1 a new blob is assigned to the specified image.
1302 %
1303 % The format of the DisassociateImageStream method is:
1304 %
1305 % void DisassociateImageStream(const Image *image)
1306 %
1307 % A description of each parameter follows:
1308 %
1309 % o image: the image.
1310 %
1311 */
DisassociateImageStream(Image * image)1312 MagickExport void DisassociateImageStream(Image *image)
1313 {
1314 assert(image != (Image *) NULL);
1315 assert(image->signature == MagickCoreSignature);
1316 if (image->debug != MagickFalse)
1317 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1318 DisassociateBlob(image);
1319 }
1320
1321 /*
1322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1323 % %
1324 % %
1325 % %
1326 % G e t I m a g e I n f o %
1327 % %
1328 % %
1329 % %
1330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1331 %
1332 % GetImageInfo() initializes image_info to default values.
1333 %
1334 % The format of the GetImageInfo method is:
1335 %
1336 % void GetImageInfo(ImageInfo *image_info)
1337 %
1338 % A description of each parameter follows:
1339 %
1340 % o image_info: the image info.
1341 %
1342 */
GetImageInfo(ImageInfo * image_info)1343 MagickExport void GetImageInfo(ImageInfo *image_info)
1344 {
1345 char
1346 *synchronize;
1347
1348 ExceptionInfo
1349 *exception;
1350
1351 /*
1352 File and image dimension members.
1353 */
1354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1355 assert(image_info != (ImageInfo *) NULL);
1356 (void) memset(image_info,0,sizeof(*image_info));
1357 image_info->adjoin=MagickTrue;
1358 image_info->interlace=NoInterlace;
1359 image_info->channel=DefaultChannels;
1360 image_info->quality=UndefinedCompressionQuality;
1361 image_info->antialias=MagickTrue;
1362 image_info->dither=MagickTrue;
1363 synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1364 if (synchronize != (const char *) NULL)
1365 {
1366 image_info->synchronize=IsStringTrue(synchronize);
1367 synchronize=DestroyString(synchronize);
1368 }
1369 exception=AcquireExceptionInfo();
1370 (void) QueryColorCompliance(BackgroundColor,AllCompliance,
1371 &image_info->background_color,exception);
1372 (void) QueryColorCompliance(BorderColor,AllCompliance,
1373 &image_info->border_color,exception);
1374 (void) QueryColorCompliance(MatteColor,AllCompliance,&image_info->matte_color,
1375 exception);
1376 (void) QueryColorCompliance(TransparentColor,AllCompliance,
1377 &image_info->transparent_color,exception);
1378 exception=DestroyExceptionInfo(exception);
1379 image_info->debug=IsEventLogging();
1380 image_info->signature=MagickCoreSignature;
1381 }
1382
1383 /*
1384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385 % %
1386 % %
1387 % %
1388 % G e t I m a g e I n f o F i l e %
1389 % %
1390 % %
1391 % %
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393 %
1394 % GetImageInfoFile() returns the image info file member.
1395 %
1396 % The format of the GetImageInfoFile method is:
1397 %
1398 % FILE *GetImageInfoFile(const ImageInfo *image_info)
1399 %
1400 % A description of each parameter follows:
1401 %
1402 % o image_info: the image info.
1403 %
1404 */
GetImageInfoFile(const ImageInfo * image_info)1405 MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1406 {
1407 return(image_info->file);
1408 }
1409
1410 /*
1411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1412 % %
1413 % %
1414 % %
1415 % G e t I m a g e M a s k %
1416 % %
1417 % %
1418 % %
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1420 %
1421 % GetImageMask() returns the mask associated with the image.
1422 %
1423 % The format of the GetImageMask method is:
1424 %
1425 % Image *GetImageMask(const Image *image,const PixelMask type,
1426 % ExceptionInfo *exception)
1427 %
1428 % A description of each parameter follows:
1429 %
1430 % o image: the image.
1431 %
1432 % o type: the mask type, ReadPixelMask or WritePixelMask.
1433 %
1434 */
GetImageMask(const Image * image,const PixelMask type,ExceptionInfo * exception)1435 MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
1436 ExceptionInfo *exception)
1437 {
1438 CacheView
1439 *mask_view,
1440 *image_view;
1441
1442 Image
1443 *mask_image;
1444
1445 MagickBooleanType
1446 status;
1447
1448 ssize_t
1449 y;
1450
1451 /*
1452 Get image mask.
1453 */
1454 assert(image != (Image *) NULL);
1455 if (image->debug != MagickFalse)
1456 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1457 assert(image->signature == MagickCoreSignature);
1458 switch (type)
1459 {
1460 case ReadPixelMask:
1461 {
1462 if ((image->channels & ReadMaskChannel) == 0)
1463 return((Image *) NULL);
1464 break;
1465 }
1466 case WritePixelMask:
1467 {
1468 if ((image->channels & WriteMaskChannel) == 0)
1469 return((Image *) NULL);
1470 break;
1471 }
1472 default:
1473 {
1474 if ((image->channels & CompositeMaskChannel) == 0)
1475 return((Image *) NULL);
1476 break;
1477 }
1478 }
1479 mask_image=AcquireImage((ImageInfo *) NULL,exception);
1480 status=SetImageExtent(mask_image,image->columns,image->rows,exception);
1481 if (status == MagickFalse)
1482 return(DestroyImage(mask_image));
1483 status=MagickTrue;
1484 mask_image->alpha_trait=UndefinedPixelTrait;
1485 (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
1486 image_view=AcquireVirtualCacheView(image,exception);
1487 mask_view=AcquireAuthenticCacheView(mask_image,exception);
1488 for (y=0; y < (ssize_t) image->rows; y++)
1489 {
1490 register const Quantum
1491 *magick_restrict p;
1492
1493 register Quantum
1494 *magick_restrict q;
1495
1496 register ssize_t
1497 x;
1498
1499 if (status == MagickFalse)
1500 continue;
1501 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1502 q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1503 exception);
1504 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1505 {
1506 status=MagickFalse;
1507 continue;
1508 }
1509 for (x=0; x < (ssize_t) image->columns; x++)
1510 {
1511 switch (type)
1512 {
1513 case ReadPixelMask:
1514 {
1515 SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
1516 break;
1517 }
1518 case WritePixelMask:
1519 {
1520 SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
1521 break;
1522 }
1523 default:
1524 {
1525 SetPixelGray(mask_image,GetPixelCompositeMask(image,p),q);
1526 break;
1527 }
1528 }
1529 p+=GetPixelChannels(image);
1530 q+=GetPixelChannels(mask_image);
1531 }
1532 if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1533 status=MagickFalse;
1534 }
1535 mask_view=DestroyCacheView(mask_view);
1536 image_view=DestroyCacheView(image_view);
1537 if (status == MagickFalse)
1538 mask_image=DestroyImage(mask_image);
1539 return(mask_image);
1540 }
1541
1542 /*
1543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1544 % %
1545 % %
1546 % %
1547 + G e t I m a g e R e f e r e n c e C o u n t %
1548 % %
1549 % %
1550 % %
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1552 %
1553 % GetImageReferenceCount() returns the image reference count.
1554 %
1555 % The format of the GetReferenceCount method is:
1556 %
1557 % ssize_t GetImageReferenceCount(Image *image)
1558 %
1559 % A description of each parameter follows:
1560 %
1561 % o image: the image.
1562 %
1563 */
GetImageReferenceCount(Image * image)1564 MagickExport ssize_t GetImageReferenceCount(Image *image)
1565 {
1566 ssize_t
1567 reference_count;
1568
1569 assert(image != (Image *) NULL);
1570 assert(image->signature == MagickCoreSignature);
1571 if (image->debug != MagickFalse)
1572 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1573 LockSemaphoreInfo(image->semaphore);
1574 reference_count=image->reference_count;
1575 UnlockSemaphoreInfo(image->semaphore);
1576 return(reference_count);
1577 }
1578
1579 /*
1580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1581 % %
1582 % %
1583 % %
1584 % 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 %
1585 % %
1586 % %
1587 % %
1588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1589 %
1590 % GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1591 % image. A virtual pixel is any pixel access that is outside the boundaries
1592 % of the image cache.
1593 %
1594 % The format of the GetImageVirtualPixelMethod() method is:
1595 %
1596 % VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1597 %
1598 % A description of each parameter follows:
1599 %
1600 % o image: the image.
1601 %
1602 */
GetImageVirtualPixelMethod(const Image * image)1603 MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1604 {
1605 assert(image != (Image *) NULL);
1606 assert(image->signature == MagickCoreSignature);
1607 if (image->debug != MagickFalse)
1608 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1609 return(GetPixelCacheVirtualMethod(image));
1610 }
1611
1612 /*
1613 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1614 % %
1615 % %
1616 % %
1617 % I n t e r p r e t I m a g e F i l e n a m e %
1618 % %
1619 % %
1620 % %
1621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1622 %
1623 % InterpretImageFilename() interprets embedded characters in an image filename.
1624 % The filename length is returned.
1625 %
1626 % The format of the InterpretImageFilename method is:
1627 %
1628 % size_t InterpretImageFilename(const ImageInfo *image_info,Image *image,
1629 % const char *format,int value,char *filename,ExceptionInfo *exception)
1630 %
1631 % A description of each parameter follows.
1632 %
1633 % o image_info: the image info..
1634 %
1635 % o image: the image.
1636 %
1637 % o format: A filename describing the format to use to write the numeric
1638 % argument. Only the first numeric format identifier is replaced.
1639 %
1640 % o value: Numeric value to substitute into format filename.
1641 %
1642 % o filename: return the formatted filename in this character buffer.
1643 %
1644 % o exception: return any errors or warnings in this structure.
1645 %
1646 */
InterpretImageFilename(const ImageInfo * image_info,Image * image,const char * format,int value,char * filename,ExceptionInfo * exception)1647 MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1648 Image *image,const char *format,int value,char *filename,
1649 ExceptionInfo *exception)
1650 {
1651 char
1652 *q;
1653
1654 int
1655 c;
1656
1657 MagickBooleanType
1658 canonical;
1659
1660 register const char
1661 *p;
1662
1663 ssize_t
1664 field_width,
1665 offset;
1666
1667 canonical=MagickFalse;
1668 offset=0;
1669 (void) CopyMagickString(filename,format,MagickPathExtent);
1670 for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1671 {
1672 q=(char *) p+1;
1673 if (*q == '%')
1674 {
1675 p=q+1;
1676 continue;
1677 }
1678 field_width=0;
1679 if (*q == '0')
1680 field_width=(ssize_t) strtol(q,&q,10);
1681 switch (*q)
1682 {
1683 case 'd':
1684 case 'o':
1685 case 'x':
1686 {
1687 q++;
1688 c=(*q);
1689 *q='\0';
1690 (void) FormatLocaleString(filename+(p-format-offset),(size_t)
1691 (MagickPathExtent-(p-format-offset)),p,value);
1692 offset+=(4-field_width);
1693 *q=c;
1694 (void) ConcatenateMagickString(filename,q,MagickPathExtent);
1695 canonical=MagickTrue;
1696 if (*(q-1) != '%')
1697 break;
1698 p++;
1699 break;
1700 }
1701 case '[':
1702 {
1703 char
1704 pattern[MagickPathExtent];
1705
1706 const char
1707 *option;
1708
1709 register char
1710 *r;
1711
1712 register ssize_t
1713 i;
1714
1715 ssize_t
1716 depth;
1717
1718 /*
1719 Image option.
1720 */
1721 if (strchr(p,']') == (char *) NULL)
1722 break;
1723 depth=1;
1724 r=q+1;
1725 for (i=0; (i < (MagickPathExtent-1L)) && (*r != '\0'); i++)
1726 {
1727 if (*r == '[')
1728 depth++;
1729 if (*r == ']')
1730 depth--;
1731 if (depth <= 0)
1732 break;
1733 pattern[i]=(*r++);
1734 }
1735 pattern[i]='\0';
1736 if (LocaleNCompare(pattern,"filename:",9) != 0)
1737 break;
1738 option=(const char *) NULL;
1739 if (image != (Image *) NULL)
1740 option=GetImageProperty(image,pattern,exception);
1741 if ((option == (const char *) NULL) && (image != (Image *) NULL))
1742 option=GetImageArtifact(image,pattern);
1743 if ((option == (const char *) NULL) &&
1744 (image_info != (ImageInfo *) NULL))
1745 option=GetImageOption(image_info,pattern);
1746 if (option == (const char *) NULL)
1747 break;
1748 q--;
1749 c=(*q);
1750 *q='\0';
1751 (void) CopyMagickString(filename+(p-format-offset),option,(size_t)
1752 (MagickPathExtent-(p-format-offset)));
1753 offset+=strlen(pattern)-strlen(option)+3;
1754 *q=c;
1755 (void) ConcatenateMagickString(filename,r+1,MagickPathExtent);
1756 canonical=MagickTrue;
1757 if (*(q-1) != '%')
1758 break;
1759 p++;
1760 break;
1761 }
1762 default:
1763 break;
1764 }
1765 }
1766 for (q=filename; *q != '\0'; q++)
1767 if ((*q == '%') && (*(q+1) == '%'))
1768 {
1769 (void) CopyMagickString(q,q+1,(size_t) (MagickPathExtent-(q-filename)));
1770 canonical=MagickTrue;
1771 }
1772 if (canonical == MagickFalse)
1773 (void) CopyMagickString(filename,format,MagickPathExtent);
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 != OpaqueAlpha) &&
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) || (image->depth > (8*sizeof(MagickSizeType))))
2665 ThrowBinaryException(ImageError,"ImageDepthNotSupported",image->filename);
2666 return(SyncImagePixelCache(image,exception));
2667 }
2668
2669 /*
2670 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2671 % %
2672 % %
2673 % %
2674 + S e t I m a g e I n f o %
2675 % %
2676 % %
2677 % %
2678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2679 %
2680 % SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
2681 % It is set to a type of image format based on the prefix or suffix of the
2682 % filename. For example, 'ps:image' returns PS indicating a Postscript image.
2683 % JPEG is returned for this filename: 'image.jpg'. The filename prefix has
2684 % precendence over the suffix. Use an optional index enclosed in brackets
2685 % after a file name to specify a desired scene of a multi-resolution image
2686 % format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2687 % indicates success.
2688 %
2689 % The format of the SetImageInfo method is:
2690 %
2691 % MagickBooleanType SetImageInfo(ImageInfo *image_info,
2692 % const unsigned int frames,ExceptionInfo *exception)
2693 %
2694 % A description of each parameter follows:
2695 %
2696 % o image_info: the image info.
2697 %
2698 % o frames: the number of images you intend to write.
2699 %
2700 % o exception: return any errors or warnings in this structure.
2701 %
2702 */
SetImageInfo(ImageInfo * image_info,const unsigned int frames,ExceptionInfo * exception)2703 MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
2704 const unsigned int frames,ExceptionInfo *exception)
2705 {
2706 char
2707 component[MagickPathExtent],
2708 magic[MagickPathExtent],
2709 *q;
2710
2711 const MagicInfo
2712 *magic_info;
2713
2714 const MagickInfo
2715 *magick_info;
2716
2717 ExceptionInfo
2718 *sans_exception;
2719
2720 Image
2721 *image;
2722
2723 MagickBooleanType
2724 status;
2725
2726 register const char
2727 *p;
2728
2729 ssize_t
2730 count;
2731
2732 /*
2733 Look for 'image.format' in filename.
2734 */
2735 assert(image_info != (ImageInfo *) NULL);
2736 assert(image_info->signature == MagickCoreSignature);
2737 if (image_info->debug != MagickFalse)
2738 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2739 image_info->filename);
2740 *component='\0';
2741 GetPathComponent(image_info->filename,SubimagePath,component);
2742 if (*component != '\0')
2743 {
2744 /*
2745 Look for scene specification (e.g. img0001.pcd[4]).
2746 */
2747 if (IsSceneGeometry(component,MagickFalse) == MagickFalse)
2748 {
2749 if (IsGeometry(component) != MagickFalse)
2750 (void) CloneString(&image_info->extract,component);
2751 }
2752 else
2753 {
2754 size_t
2755 first,
2756 last;
2757
2758 (void) CloneString(&image_info->scenes,component);
2759 image_info->scene=StringToUnsignedLong(image_info->scenes);
2760 image_info->number_scenes=image_info->scene;
2761 p=image_info->scenes;
2762 for (q=(char *) image_info->scenes; *q != '\0'; p++)
2763 {
2764 while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2765 p++;
2766 first=(size_t) strtol(p,&q,10);
2767 last=first;
2768 while (isspace((int) ((unsigned char) *q)) != 0)
2769 q++;
2770 if (*q == '-')
2771 last=(size_t) strtol(q+1,&q,10);
2772 if (first > last)
2773 Swap(first,last);
2774 if (first < image_info->scene)
2775 image_info->scene=first;
2776 if (last > image_info->number_scenes)
2777 image_info->number_scenes=last;
2778 p=q;
2779 }
2780 image_info->number_scenes-=image_info->scene-1;
2781 }
2782 }
2783 *component='\0';
2784 if (*image_info->magick == '\0')
2785 GetPathComponent(image_info->filename,ExtensionPath,component);
2786 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2787 if (*component != '\0')
2788 if ((LocaleCompare(component,"gz") == 0) ||
2789 (LocaleCompare(component,"Z") == 0) ||
2790 (LocaleCompare(component,"svgz") == 0) ||
2791 (LocaleCompare(component,"wmz") == 0))
2792 {
2793 char
2794 path[MagickPathExtent];
2795
2796 (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
2797 path[strlen(path)-strlen(component)-1]='\0';
2798 GetPathComponent(path,ExtensionPath,component);
2799 }
2800 #endif
2801 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2802 if (*component != '\0')
2803 if (LocaleCompare(component,"bz2") == 0)
2804 {
2805 char
2806 path[MagickPathExtent];
2807
2808 (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
2809 path[strlen(path)-strlen(component)-1]='\0';
2810 GetPathComponent(path,ExtensionPath,component);
2811 }
2812 #endif
2813 image_info->affirm=MagickFalse;
2814 sans_exception=AcquireExceptionInfo();
2815 if ((*component != '\0') && (IsGlob(component) == MagickFalse))
2816 {
2817 MagickFormatType
2818 format_type;
2819
2820 register ssize_t
2821 i;
2822
2823 static const char
2824 *format_type_formats[] =
2825 {
2826 "AUTOTRACE",
2827 "BROWSE",
2828 "DCRAW",
2829 "EDIT",
2830 "LAUNCH",
2831 "MPEG:DECODE",
2832 "MPEG:ENCODE",
2833 "PRINT",
2834 "PS:ALPHA",
2835 "PS:CMYK",
2836 "PS:COLOR",
2837 "PS:GRAY",
2838 "PS:MONO",
2839 "SCAN",
2840 "SHOW",
2841 "WIN",
2842 (char *) NULL
2843 };
2844
2845 /*
2846 User specified image format.
2847 */
2848 (void) CopyMagickString(magic,component,MagickPathExtent);
2849 LocaleUpper(magic);
2850 /*
2851 Look for explicit image formats.
2852 */
2853 format_type=UndefinedFormatType;
2854 magick_info=GetMagickInfo(magic,sans_exception);
2855 if ((magick_info != (const MagickInfo *) NULL) &&
2856 (magick_info->format_type != UndefinedFormatType))
2857 format_type=magick_info->format_type;
2858 i=0;
2859 while ((format_type == UndefinedFormatType) &&
2860 (format_type_formats[i] != (char *) NULL))
2861 {
2862 if ((*magic == *format_type_formats[i]) &&
2863 (LocaleCompare(magic,format_type_formats[i]) == 0))
2864 format_type=ExplicitFormatType;
2865 i++;
2866 }
2867 if (format_type == UndefinedFormatType)
2868 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2869 else
2870 if (format_type == ExplicitFormatType)
2871 {
2872 image_info->affirm=MagickTrue;
2873 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2874 }
2875 if (LocaleCompare(magic,"RGB") == 0)
2876 image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
2877 }
2878 /*
2879 Look for explicit 'format:image' in filename.
2880 */
2881 *magic='\0';
2882 GetPathComponent(image_info->filename,MagickPath,magic);
2883 if (*magic == '\0')
2884 {
2885 (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
2886 magick_info=GetMagickInfo(magic,sans_exception);
2887 if (frames == 0)
2888 GetPathComponent(image_info->filename,CanonicalPath,component);
2889 else
2890 GetPathComponent(image_info->filename,SubcanonicalPath,component);
2891 (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
2892 }
2893 else
2894 {
2895 const DelegateInfo
2896 *delegate_info;
2897
2898 /*
2899 User specified image format.
2900 */
2901 LocaleUpper(magic);
2902 magick_info=GetMagickInfo(magic,sans_exception);
2903 delegate_info=GetDelegateInfo(magic,"*",sans_exception);
2904 if (delegate_info == (const DelegateInfo *) NULL)
2905 delegate_info=GetDelegateInfo("*",magic,sans_exception);
2906 if (((magick_info != (const MagickInfo *) NULL) ||
2907 (delegate_info != (const DelegateInfo *) NULL)) &&
2908 (IsMagickConflict(magic) == MagickFalse))
2909 {
2910 image_info->affirm=MagickTrue;
2911 (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2912 GetPathComponent(image_info->filename,CanonicalPath,component);
2913 (void) CopyMagickString(image_info->filename,component,
2914 MagickPathExtent);
2915 }
2916 }
2917 sans_exception=DestroyExceptionInfo(sans_exception);
2918 if ((magick_info == (const MagickInfo *) NULL) ||
2919 (GetMagickEndianSupport(magick_info) == MagickFalse))
2920 image_info->endian=UndefinedEndian;
2921 if ((image_info->adjoin != MagickFalse) && (frames > 1))
2922 {
2923 /*
2924 Test for multiple image support (e.g. image%02d.png).
2925 */
2926 (void) InterpretImageFilename(image_info,(Image *) NULL,
2927 image_info->filename,(int) image_info->scene,component,exception);
2928 if ((LocaleCompare(component,image_info->filename) != 0) &&
2929 (strchr(component,'%') == (char *) NULL))
2930 image_info->adjoin=MagickFalse;
2931 }
2932 if ((image_info->adjoin != MagickFalse) && (frames > 0))
2933 {
2934 /*
2935 Some image formats do not support multiple frames per file.
2936 */
2937 magick_info=GetMagickInfo(magic,exception);
2938 if (magick_info != (const MagickInfo *) NULL)
2939 if (GetMagickAdjoin(magick_info) == MagickFalse)
2940 image_info->adjoin=MagickFalse;
2941 }
2942 if (image_info->affirm != MagickFalse)
2943 return(MagickTrue);
2944 if (frames == 0)
2945 {
2946 unsigned char
2947 *magick;
2948
2949 size_t
2950 magick_size;
2951
2952 /*
2953 Determine the image format from the first few bytes of the file.
2954 */
2955 magick_size=GetMagicPatternExtent(exception);
2956 if (magick_size == 0)
2957 return(MagickFalse);
2958 image=AcquireImage(image_info,exception);
2959 (void) CopyMagickString(image->filename,image_info->filename,
2960 MagickPathExtent);
2961 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2962 if (status == MagickFalse)
2963 {
2964 image=DestroyImage(image);
2965 return(MagickFalse);
2966 }
2967 if ((IsBlobSeekable(image) == MagickFalse) ||
2968 (IsBlobExempt(image) != MagickFalse))
2969 {
2970 /*
2971 Copy image to seekable temporary file.
2972 */
2973 *component='\0';
2974 status=ImageToFile(image,component,exception);
2975 (void) CloseBlob(image);
2976 if (status == MagickFalse)
2977 {
2978 image=DestroyImage(image);
2979 return(MagickFalse);
2980 }
2981 SetImageInfoFile(image_info,(FILE *) NULL);
2982 (void) CopyMagickString(image->filename,component,MagickPathExtent);
2983 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2984 if (status == MagickFalse)
2985 {
2986 image=DestroyImage(image);
2987 return(MagickFalse);
2988 }
2989 (void) CopyMagickString(image_info->filename,component,
2990 MagickPathExtent);
2991 image_info->temporary=MagickTrue;
2992 }
2993 magick=(unsigned char *) AcquireMagickMemory(magick_size);
2994 if (magick == (unsigned char *) NULL)
2995 {
2996 (void) CloseBlob(image);
2997 image=DestroyImage(image);
2998 return(MagickFalse);
2999 }
3000 (void) memset(magick,0,magick_size);
3001 count=ReadBlob(image,magick_size,magick);
3002 (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
3003 (void) CloseBlob(image);
3004 image=DestroyImage(image);
3005 /*
3006 Check magic cache.
3007 */
3008 sans_exception=AcquireExceptionInfo();
3009 magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3010 magick=(unsigned char *) RelinquishMagickMemory(magick);
3011 if ((magic_info != (const MagicInfo *) NULL) &&
3012 (GetMagicName(magic_info) != (char *) NULL))
3013 {
3014 /*
3015 Try to use magick_info that was determined earlier by the extension
3016 */
3017 if ((magick_info != (const MagickInfo *) NULL) &&
3018 (GetMagickUseExtension(magick_info) != MagickFalse) &&
3019 (LocaleCompare(magick_info->module,GetMagicName(
3020 magic_info)) == 0))
3021 (void) CopyMagickString(image_info->magick,magick_info->name,
3022 MagickPathExtent);
3023 else
3024 {
3025 (void) CopyMagickString(image_info->magick,GetMagicName(
3026 magic_info),MagickPathExtent);
3027 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3028 }
3029 if ((magick_info == (const MagickInfo *) NULL) ||
3030 (GetMagickEndianSupport(magick_info) == MagickFalse))
3031 image_info->endian=UndefinedEndian;
3032 sans_exception=DestroyExceptionInfo(sans_exception);
3033 return(MagickTrue);
3034 }
3035 magick_info=GetMagickInfo(image_info->magick,sans_exception);
3036 if ((magick_info == (const MagickInfo *) NULL) ||
3037 (GetMagickEndianSupport(magick_info) == MagickFalse))
3038 image_info->endian=UndefinedEndian;
3039 sans_exception=DestroyExceptionInfo(sans_exception);
3040 }
3041 return(MagickTrue);
3042 }
3043
3044 /*
3045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046 % %
3047 % %
3048 % %
3049 % S e t I m a g e I n f o B l o b %
3050 % %
3051 % %
3052 % %
3053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054 %
3055 % SetImageInfoBlob() sets the image info blob member.
3056 %
3057 % The format of the SetImageInfoBlob method is:
3058 %
3059 % void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3060 % const size_t length)
3061 %
3062 % A description of each parameter follows:
3063 %
3064 % o image_info: the image info.
3065 %
3066 % o blob: the blob.
3067 %
3068 % o length: the blob length.
3069 %
3070 */
SetImageInfoBlob(ImageInfo * image_info,const void * blob,const size_t length)3071 MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3072 const size_t length)
3073 {
3074 assert(image_info != (ImageInfo *) NULL);
3075 assert(image_info->signature == MagickCoreSignature);
3076 if (image_info->debug != MagickFalse)
3077 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3078 image_info->filename);
3079 image_info->blob=(void *) blob;
3080 image_info->length=length;
3081 }
3082
3083 /*
3084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3085 % %
3086 % %
3087 % %
3088 % S e t I m a g e I n f o C u s t o m S t r e a m %
3089 % %
3090 % %
3091 % %
3092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3093 %
3094 % SetImageInfoCustomStream() sets the image info custom stream handlers.
3095 %
3096 % The format of the SetImageInfoCustomStream method is:
3097 %
3098 % void SetImageInfoCustomStream(ImageInfo *image_info,
3099 % CustomStreamInfo *custom_stream)
3100 %
3101 % A description of each parameter follows:
3102 %
3103 % o image_info: the image info.
3104 %
3105 % o custom_stream: your custom stream methods.
3106 %
3107 */
SetImageInfoCustomStream(ImageInfo * image_info,CustomStreamInfo * custom_stream)3108 MagickExport void SetImageInfoCustomStream(ImageInfo *image_info,
3109 CustomStreamInfo *custom_stream)
3110 {
3111 assert(image_info != (ImageInfo *) NULL);
3112 assert(image_info->signature == MagickCoreSignature);
3113 if (image_info->debug != MagickFalse)
3114 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3115 image_info->filename);
3116 image_info->custom_stream=(CustomStreamInfo *) custom_stream;
3117 }
3118
3119 /*
3120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3121 % %
3122 % %
3123 % %
3124 % S e t I m a g e I n f o F i l e %
3125 % %
3126 % %
3127 % %
3128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3129 %
3130 % SetImageInfoFile() sets the image info file member.
3131 %
3132 % The format of the SetImageInfoFile method is:
3133 %
3134 % void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3135 %
3136 % A description of each parameter follows:
3137 %
3138 % o image_info: the image info.
3139 %
3140 % o file: the file.
3141 %
3142 */
SetImageInfoFile(ImageInfo * image_info,FILE * file)3143 MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3144 {
3145 assert(image_info != (ImageInfo *) NULL);
3146 assert(image_info->signature == MagickCoreSignature);
3147 if (image_info->debug != MagickFalse)
3148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3149 image_info->filename);
3150 image_info->file=file;
3151 }
3152
3153 /*
3154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3155 % %
3156 % %
3157 % %
3158 % S e t I m a g e M a s k %
3159 % %
3160 % %
3161 % %
3162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3163 %
3164 % SetImageMask() associates a mask with the image. The mask must be the same
3165 % dimensions as the image.
3166 %
3167 % The format of the SetImageMask method is:
3168 %
3169 % MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3170 % const Image *mask,ExceptionInfo *exception)
3171 %
3172 % A description of each parameter follows:
3173 %
3174 % o image: the image.
3175 %
3176 % o type: the mask type, ReadPixelMask or WritePixelMask.
3177 %
3178 % o mask: the image mask.
3179 %
3180 % o exception: return any errors or warnings in this structure.
3181 %
3182 */
SetImageMask(Image * image,const PixelMask type,const Image * mask,ExceptionInfo * exception)3183 MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3184 const Image *mask,ExceptionInfo *exception)
3185 {
3186 CacheView
3187 *mask_view,
3188 *image_view;
3189
3190 MagickBooleanType
3191 status;
3192
3193 ssize_t
3194 y;
3195
3196 /*
3197 Set image mask.
3198 */
3199 assert(image != (Image *) NULL);
3200 if (image->debug != MagickFalse)
3201 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3202 assert(image->signature == MagickCoreSignature);
3203 if (mask == (const Image *) NULL)
3204 {
3205 switch (type)
3206 {
3207 case ReadPixelMask:
3208 {
3209 image->channels=(ChannelType) (image->channels & ~ReadMaskChannel);
3210 break;
3211 }
3212 case WritePixelMask:
3213 {
3214 image->channels=(ChannelType) (image->channels & ~WriteMaskChannel);
3215 }
3216 default:
3217 {
3218 image->channels=(ChannelType) (image->channels & ~CompositeMaskChannel);
3219 break;
3220 }
3221 }
3222 return(SyncImagePixelCache(image,exception));
3223 }
3224 switch (type)
3225 {
3226 case ReadPixelMask:
3227 {
3228 image->channels=(ChannelType) (image->channels | ReadMaskChannel);
3229 break;
3230 }
3231 case WritePixelMask:
3232 {
3233 image->channels=(ChannelType) (image->channels | WriteMaskChannel);
3234 break;
3235 }
3236 default:
3237 {
3238 image->channels=(ChannelType) (image->channels | CompositeMaskChannel);
3239 break;
3240 }
3241 }
3242 if (SyncImagePixelCache(image,exception) == MagickFalse)
3243 return(MagickFalse);
3244 status=MagickTrue;
3245 image->mask_trait=UpdatePixelTrait;
3246 mask_view=AcquireVirtualCacheView(mask,exception);
3247 image_view=AcquireAuthenticCacheView(image,exception);
3248 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3249 #pragma omp parallel for schedule(static) shared(status) \
3250 magick_number_threads(mask,image,image->rows,1)
3251 #endif
3252 for (y=0; y < (ssize_t) image->rows; y++)
3253 {
3254 register const Quantum
3255 *magick_restrict p;
3256
3257 register Quantum
3258 *magick_restrict q;
3259
3260 register ssize_t
3261 x;
3262
3263 if (status == MagickFalse)
3264 continue;
3265 p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
3266 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3267 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3268 {
3269 status=MagickFalse;
3270 continue;
3271 }
3272 for (x=0; x < (ssize_t) image->columns; x++)
3273 {
3274 MagickRealType
3275 intensity;
3276
3277 intensity=0.0;
3278 if ((x < (ssize_t) mask->columns) && (y < (ssize_t) mask->rows))
3279 intensity=GetPixelIntensity(mask,p);
3280 switch (type)
3281 {
3282 case ReadPixelMask:
3283 {
3284 SetPixelReadMask(image,ClampToQuantum(intensity),q);
3285 break;
3286 }
3287 case WritePixelMask:
3288 {
3289 SetPixelWriteMask(image,ClampToQuantum(intensity),q);
3290 break;
3291 }
3292 default:
3293 {
3294 SetPixelCompositeMask(image,ClampToQuantum(intensity),q);
3295 break;
3296 }
3297 }
3298 p+=GetPixelChannels(mask);
3299 q+=GetPixelChannels(image);
3300 }
3301 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3302 status=MagickFalse;
3303 }
3304 image->mask_trait=UndefinedPixelTrait;
3305 mask_view=DestroyCacheView(mask_view);
3306 image_view=DestroyCacheView(image_view);
3307 return(status);
3308 }
3309
3310 /*
3311 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3312 % %
3313 % %
3314 % %
3315 % S e t I m a g e R e g i o n M a s k %
3316 % %
3317 % %
3318 % %
3319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3320 %
3321 % SetImageRegionMask() associates a mask with the image as defined by the
3322 % specified region.
3323 %
3324 % The format of the SetImageRegionMask method is:
3325 %
3326 % MagickBooleanType SetImageRegionMask(Image *image,const PixelMask type,
3327 % const RectangleInfo *region,ExceptionInfo *exception)
3328 %
3329 % A description of each parameter follows:
3330 %
3331 % o image: the image.
3332 %
3333 % o type: the mask type, ReadPixelMask or WritePixelMask.
3334 %
3335 % o geometry: the mask region.
3336 %
3337 % o exception: return any errors or warnings in this structure.
3338 %
3339 */
SetImageRegionMask(Image * image,const PixelMask type,const RectangleInfo * region,ExceptionInfo * exception)3340 MagickExport MagickBooleanType SetImageRegionMask(Image *image,
3341 const PixelMask type,const RectangleInfo *region,ExceptionInfo *exception)
3342 {
3343 CacheView
3344 *image_view;
3345
3346 MagickBooleanType
3347 status;
3348
3349 ssize_t
3350 y;
3351
3352 /*
3353 Set image mask as defined by the region.
3354 */
3355 assert(image != (Image *) NULL);
3356 if (image->debug != MagickFalse)
3357 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3358 assert(image->signature == MagickCoreSignature);
3359 if (region == (const RectangleInfo *) NULL)
3360 {
3361 switch (type)
3362 {
3363 case ReadPixelMask:
3364 {
3365 image->channels=(ChannelType) (image->channels & ~ReadMaskChannel);
3366 break;
3367 }
3368 case WritePixelMask:
3369 {
3370 image->channels=(ChannelType) (image->channels & ~WriteMaskChannel);
3371 break;
3372 }
3373 default:
3374 {
3375 image->channels=(ChannelType) (image->channels & ~CompositeMaskChannel);
3376 break;
3377 }
3378 }
3379 return(SyncImagePixelCache(image,exception));
3380 }
3381 switch (type)
3382 {
3383 case ReadPixelMask:
3384 {
3385 image->channels=(ChannelType) (image->channels | ReadMaskChannel);
3386 break;
3387 }
3388 case WritePixelMask:
3389 {
3390 image->channels=(ChannelType) (image->channels | WriteMaskChannel);
3391 break;
3392 }
3393 default:
3394 {
3395 image->channels=(ChannelType) (image->channels | CompositeMaskChannel);
3396 break;
3397 }
3398 }
3399 if (SyncImagePixelCache(image,exception) == MagickFalse)
3400 return(MagickFalse);
3401 status=MagickTrue;
3402 image->mask_trait=UpdatePixelTrait;
3403 image_view=AcquireAuthenticCacheView(image,exception);
3404 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3405 #pragma omp parallel for schedule(static) shared(status) \
3406 magick_number_threads(image,image,image->rows,1)
3407 #endif
3408 for (y=0; y < (ssize_t) image->rows; y++)
3409 {
3410 register Quantum
3411 *magick_restrict q;
3412
3413 register ssize_t
3414 x;
3415
3416 if (status == MagickFalse)
3417 continue;
3418 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3419 if (q == (Quantum *) NULL)
3420 {
3421 status=MagickFalse;
3422 continue;
3423 }
3424 for (x=0; x < (ssize_t) image->columns; x++)
3425 {
3426 Quantum
3427 pixel;
3428
3429 pixel=QuantumRange;
3430 if (((x >= region->x) && (x < (region->x+(ssize_t) region->width))) &&
3431 ((y >= region->y) && (y < (region->y+(ssize_t) region->height))))
3432 pixel=(Quantum) 0;
3433 switch (type)
3434 {
3435 case ReadPixelMask:
3436 {
3437 SetPixelReadMask(image,pixel,q);
3438 break;
3439 }
3440 case WritePixelMask:
3441 {
3442 SetPixelWriteMask(image,pixel,q);
3443 break;
3444 }
3445 default:
3446 {
3447 SetPixelCompositeMask(image,pixel,q);
3448 break;
3449 }
3450 }
3451 q+=GetPixelChannels(image);
3452 }
3453 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3454 status=MagickFalse;
3455 }
3456 image->mask_trait=UndefinedPixelTrait;
3457 image_view=DestroyCacheView(image_view);
3458 return(status);
3459 }
3460
3461 /*
3462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3463 % %
3464 % %
3465 % %
3466 % 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 %
3467 % %
3468 % %
3469 % %
3470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3471 %
3472 % SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3473 % image and returns the previous setting. A virtual pixel is any pixel access
3474 % that is outside the boundaries of the image cache.
3475 %
3476 % The format of the SetImageVirtualPixelMethod() method is:
3477 %
3478 % VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3479 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3480 %
3481 % A description of each parameter follows:
3482 %
3483 % o image: the image.
3484 %
3485 % o virtual_pixel_method: choose the type of virtual pixel.
3486 %
3487 % o exception: return any errors or warnings in this structure.
3488 %
3489 */
SetImageVirtualPixelMethod(Image * image,const VirtualPixelMethod virtual_pixel_method,ExceptionInfo * exception)3490 MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3491 const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3492 {
3493 assert(image != (const Image *) NULL);
3494 assert(image->signature == MagickCoreSignature);
3495 if (image->debug != MagickFalse)
3496 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3497 return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
3498 }
3499
3500 /*
3501 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3502 % %
3503 % %
3504 % %
3505 % S m u s h I m a g e s %
3506 % %
3507 % %
3508 % %
3509 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3510 %
3511 % SmushImages() takes all images from the current image pointer to the end
3512 % of the image list and smushes them to each other top-to-bottom if the
3513 % stack parameter is true, otherwise left-to-right.
3514 %
3515 % The current gravity setting now effects how the image is justified in the
3516 % final image.
3517 %
3518 % The format of the SmushImages method is:
3519 %
3520 % Image *SmushImages(const Image *images,const MagickBooleanType stack,
3521 % ExceptionInfo *exception)
3522 %
3523 % A description of each parameter follows:
3524 %
3525 % o images: the image sequence.
3526 %
3527 % o stack: A value other than 0 stacks the images top-to-bottom.
3528 %
3529 % o offset: minimum distance in pixels between images.
3530 %
3531 % o exception: return any errors or warnings in this structure.
3532 %
3533 */
3534
SmushXGap(const Image * smush_image,const Image * images,const ssize_t offset,ExceptionInfo * exception)3535 static ssize_t SmushXGap(const Image *smush_image,const Image *images,
3536 const ssize_t offset,ExceptionInfo *exception)
3537 {
3538 CacheView
3539 *left_view,
3540 *right_view;
3541
3542 const Image
3543 *left_image,
3544 *right_image;
3545
3546 RectangleInfo
3547 left_geometry,
3548 right_geometry;
3549
3550 register const Quantum
3551 *p;
3552
3553 register ssize_t
3554 i,
3555 y;
3556
3557 size_t
3558 gap;
3559
3560 ssize_t
3561 x;
3562
3563 if (images->previous == (Image *) NULL)
3564 return(0);
3565 right_image=images;
3566 SetGeometry(smush_image,&right_geometry);
3567 GravityAdjustGeometry(right_image->columns,right_image->rows,
3568 right_image->gravity,&right_geometry);
3569 left_image=images->previous;
3570 SetGeometry(smush_image,&left_geometry);
3571 GravityAdjustGeometry(left_image->columns,left_image->rows,
3572 left_image->gravity,&left_geometry);
3573 gap=right_image->columns;
3574 left_view=AcquireVirtualCacheView(left_image,exception);
3575 right_view=AcquireVirtualCacheView(right_image,exception);
3576 for (y=0; y < (ssize_t) smush_image->rows; y++)
3577 {
3578 for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3579 {
3580 p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3581 if ((p == (const Quantum *) NULL) ||
3582 (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
3583 ((left_image->columns-x-1) >= gap))
3584 break;
3585 }
3586 i=(ssize_t) left_image->columns-x-1;
3587 for (x=0; x < (ssize_t) right_image->columns; x++)
3588 {
3589 p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
3590 exception);
3591 if ((p == (const Quantum *) NULL) ||
3592 (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3593 ((x+i) >= (ssize_t) gap))
3594 break;
3595 }
3596 if ((x+i) < (ssize_t) gap)
3597 gap=(size_t) (x+i);
3598 }
3599 right_view=DestroyCacheView(right_view);
3600 left_view=DestroyCacheView(left_view);
3601 if (y < (ssize_t) smush_image->rows)
3602 return(offset);
3603 return((ssize_t) gap-offset);
3604 }
3605
SmushYGap(const Image * smush_image,const Image * images,const ssize_t offset,ExceptionInfo * exception)3606 static ssize_t SmushYGap(const Image *smush_image,const Image *images,
3607 const ssize_t offset,ExceptionInfo *exception)
3608 {
3609 CacheView
3610 *bottom_view,
3611 *top_view;
3612
3613 const Image
3614 *bottom_image,
3615 *top_image;
3616
3617 RectangleInfo
3618 bottom_geometry,
3619 top_geometry;
3620
3621 register const Quantum
3622 *p;
3623
3624 register ssize_t
3625 i,
3626 x;
3627
3628 size_t
3629 gap;
3630
3631 ssize_t
3632 y;
3633
3634 if (images->previous == (Image *) NULL)
3635 return(0);
3636 bottom_image=images;
3637 SetGeometry(smush_image,&bottom_geometry);
3638 GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3639 bottom_image->gravity,&bottom_geometry);
3640 top_image=images->previous;
3641 SetGeometry(smush_image,&top_geometry);
3642 GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3643 &top_geometry);
3644 gap=bottom_image->rows;
3645 top_view=AcquireVirtualCacheView(top_image,exception);
3646 bottom_view=AcquireVirtualCacheView(bottom_image,exception);
3647 for (x=0; x < (ssize_t) smush_image->columns; x++)
3648 {
3649 for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3650 {
3651 p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
3652 if ((p == (const Quantum *) NULL) ||
3653 (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3654 ((top_image->rows-y-1) >= gap))
3655 break;
3656 }
3657 i=(ssize_t) top_image->rows-y-1;
3658 for (y=0; y < (ssize_t) bottom_image->rows; y++)
3659 {
3660 p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3661 exception);
3662 if ((p == (const Quantum *) NULL) ||
3663 (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3664 ((y+i) >= (ssize_t) gap))
3665 break;
3666 }
3667 if ((y+i) < (ssize_t) gap)
3668 gap=(size_t) (y+i);
3669 }
3670 bottom_view=DestroyCacheView(bottom_view);
3671 top_view=DestroyCacheView(top_view);
3672 if (x < (ssize_t) smush_image->columns)
3673 return(offset);
3674 return((ssize_t) gap-offset);
3675 }
3676
SmushImages(const Image * images,const MagickBooleanType stack,const ssize_t offset,ExceptionInfo * exception)3677 MagickExport Image *SmushImages(const Image *images,
3678 const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3679 {
3680 #define SmushImageTag "Smush/Image"
3681
3682 const Image
3683 *image;
3684
3685 Image
3686 *smush_image;
3687
3688 MagickBooleanType
3689 proceed,
3690 status;
3691
3692 MagickOffsetType
3693 n;
3694
3695 PixelTrait
3696 alpha_trait;
3697
3698 RectangleInfo
3699 geometry;
3700
3701 register const Image
3702 *next;
3703
3704 size_t
3705 height,
3706 number_images,
3707 width;
3708
3709 ssize_t
3710 x_offset,
3711 y_offset;
3712
3713 /*
3714 Compute maximum area of smushed area.
3715 */
3716 assert(images != (Image *) NULL);
3717 assert(images->signature == MagickCoreSignature);
3718 if (images->debug != MagickFalse)
3719 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3720 assert(exception != (ExceptionInfo *) NULL);
3721 assert(exception->signature == MagickCoreSignature);
3722 image=images;
3723 alpha_trait=image->alpha_trait;
3724 number_images=1;
3725 width=image->columns;
3726 height=image->rows;
3727 next=GetNextImageInList(image);
3728 for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3729 {
3730 if (next->alpha_trait != UndefinedPixelTrait)
3731 alpha_trait=BlendPixelTrait;
3732 number_images++;
3733 if (stack != MagickFalse)
3734 {
3735 if (next->columns > width)
3736 width=next->columns;
3737 height+=next->rows;
3738 if (next->previous != (Image *) NULL)
3739 height+=offset;
3740 continue;
3741 }
3742 width+=next->columns;
3743 if (next->previous != (Image *) NULL)
3744 width+=offset;
3745 if (next->rows > height)
3746 height=next->rows;
3747 }
3748 /*
3749 Smush images.
3750 */
3751 smush_image=CloneImage(image,width,height,MagickTrue,exception);
3752 if (smush_image == (Image *) NULL)
3753 return((Image *) NULL);
3754 if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
3755 {
3756 smush_image=DestroyImage(smush_image);
3757 return((Image *) NULL);
3758 }
3759 smush_image->alpha_trait=alpha_trait;
3760 (void) SetImageBackgroundColor(smush_image,exception);
3761 status=MagickTrue;
3762 x_offset=0;
3763 y_offset=0;
3764 for (n=0; n < (MagickOffsetType) number_images; n++)
3765 {
3766 SetGeometry(smush_image,&geometry);
3767 GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3768 if (stack != MagickFalse)
3769 {
3770 x_offset-=geometry.x;
3771 y_offset-=SmushYGap(smush_image,image,offset,exception);
3772 }
3773 else
3774 {
3775 x_offset-=SmushXGap(smush_image,image,offset,exception);
3776 y_offset-=geometry.y;
3777 }
3778 status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3779 y_offset,exception);
3780 proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3781 if (proceed == MagickFalse)
3782 break;
3783 if (stack == MagickFalse)
3784 {
3785 x_offset+=(ssize_t) image->columns;
3786 y_offset=0;
3787 }
3788 else
3789 {
3790 x_offset=0;
3791 y_offset+=(ssize_t) image->rows;
3792 }
3793 image=GetNextImageInList(image);
3794 }
3795 if (stack == MagickFalse)
3796 smush_image->columns=(size_t) x_offset;
3797 else
3798 smush_image->rows=(size_t) y_offset;
3799 if (status == MagickFalse)
3800 smush_image=DestroyImage(smush_image);
3801 return(smush_image);
3802 }
3803
3804 /*
3805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3806 % %
3807 % %
3808 % %
3809 % S t r i p I m a g e %
3810 % %
3811 % %
3812 % %
3813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3814 %
3815 % StripImage() strips an image of all profiles and comments.
3816 %
3817 % The format of the StripImage method is:
3818 %
3819 % MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
3820 %
3821 % A description of each parameter follows:
3822 %
3823 % o image: the image.
3824 %
3825 % o exception: return any errors or warnings in this structure.
3826 %
3827 */
StripImage(Image * image,ExceptionInfo * exception)3828 MagickExport MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
3829 {
3830 MagickBooleanType
3831 status;
3832
3833 assert(image != (Image *) NULL);
3834 if (image->debug != MagickFalse)
3835 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3836 (void) exception;
3837 DestroyImageProfiles(image);
3838 (void) DeleteImageProperty(image,"comment");
3839 (void) DeleteImageProperty(image,"date:create");
3840 (void) DeleteImageProperty(image,"date:modify");
3841 status=SetImageArtifact(image,"png:exclude-chunk",
3842 "bKGD,caNv,cHRM,eXIf,gAMA,iCCP,iTXt,pHYs,sRGB,tEXt,zCCP,zTXt,date");
3843 return(status);
3844 }
3845
3846 /*
3847 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3848 % %
3849 % %
3850 % %
3851 + S y n c I m a g e %
3852 % %
3853 % %
3854 % %
3855 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3856 %
3857 % SyncImage() initializes the red, green, and blue intensities of each pixel
3858 % as defined by the colormap index.
3859 %
3860 % The format of the SyncImage method is:
3861 %
3862 % MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3863 %
3864 % A description of each parameter follows:
3865 %
3866 % o image: the image.
3867 %
3868 % o exception: return any errors or warnings in this structure.
3869 %
3870 */
3871
PushColormapIndex(Image * image,const Quantum index,MagickBooleanType * range_exception)3872 static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3873 MagickBooleanType *range_exception)
3874 {
3875 if ((size_t) index < image->colors)
3876 return(index);
3877 *range_exception=MagickTrue;
3878 return((Quantum) 0);
3879 }
3880
SyncImage(Image * image,ExceptionInfo * exception)3881 MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3882 {
3883 CacheView
3884 *image_view;
3885
3886 MagickBooleanType
3887 range_exception,
3888 status,
3889 taint;
3890
3891 ssize_t
3892 y;
3893
3894 assert(image != (Image *) NULL);
3895 if (image->debug != MagickFalse)
3896 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3897 assert(image->signature == MagickCoreSignature);
3898 if (image->ping != MagickFalse)
3899 return(MagickTrue);
3900 if (image->storage_class != PseudoClass)
3901 return(MagickFalse);
3902 assert(image->colormap != (PixelInfo *) NULL);
3903 range_exception=MagickFalse;
3904 status=MagickTrue;
3905 taint=image->taint;
3906 image_view=AcquireAuthenticCacheView(image,exception);
3907 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3908 #pragma omp parallel for schedule(static) shared(range_exception,status) \
3909 magick_number_threads(image,image,image->rows,1)
3910 #endif
3911 for (y=0; y < (ssize_t) image->rows; y++)
3912 {
3913 Quantum
3914 index;
3915
3916 register Quantum
3917 *magick_restrict q;
3918
3919 register ssize_t
3920 x;
3921
3922 if (status == MagickFalse)
3923 continue;
3924 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3925 if (q == (Quantum *) NULL)
3926 {
3927 status=MagickFalse;
3928 continue;
3929 }
3930 for (x=0; x < (ssize_t) image->columns; x++)
3931 {
3932 index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
3933 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
3934 q+=GetPixelChannels(image);
3935 }
3936 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3937 status=MagickFalse;
3938 }
3939 image_view=DestroyCacheView(image_view);
3940 image->taint=taint;
3941 if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
3942 (void) ThrowMagickException(exception,GetMagickModule(),
3943 CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
3944 return(status);
3945 }
3946
3947 /*
3948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3949 % %
3950 % %
3951 % %
3952 % S y n c I m a g e S e t t i n g s %
3953 % %
3954 % %
3955 % %
3956 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3957 %
3958 % SyncImageSettings() syncs any image_info global options into per-image
3959 % attributes.
3960 %
3961 % Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
3962 % that operations and coders can find such settings. In IMv7 if a desired
3963 % per-image artifact is not set, then it will directly look for a global
3964 % option as a fallback, as such this copy is no longer needed, only the
3965 % link set up.
3966 %
3967 % The format of the SyncImageSettings method is:
3968 %
3969 % MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
3970 % Image *image,ExceptionInfo *exception)
3971 % MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
3972 % Image *image,ExceptionInfo *exception)
3973 %
3974 % A description of each parameter follows:
3975 %
3976 % o image_info: the image info.
3977 %
3978 % o image: the image.
3979 %
3980 % o exception: return any errors or warnings in this structure.
3981 %
3982 */
3983
SyncImagesSettings(ImageInfo * image_info,Image * images,ExceptionInfo * exception)3984 MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
3985 Image *images,ExceptionInfo *exception)
3986 {
3987 Image
3988 *image;
3989
3990 assert(image_info != (const ImageInfo *) NULL);
3991 assert(image_info->signature == MagickCoreSignature);
3992 assert(images != (Image *) NULL);
3993 assert(images->signature == MagickCoreSignature);
3994 if (images->debug != MagickFalse)
3995 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3996 image=images;
3997 for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
3998 (void) SyncImageSettings(image_info,image,exception);
3999 (void) DeleteImageOption(image_info,"page");
4000 return(MagickTrue);
4001 }
4002
SyncImageSettings(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)4003 MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4004 Image *image,ExceptionInfo *exception)
4005 {
4006 const char
4007 *option;
4008
4009 GeometryInfo
4010 geometry_info;
4011
4012 MagickStatusType
4013 flags;
4014
4015 ResolutionType
4016 units;
4017
4018 /*
4019 Sync image options.
4020 */
4021 assert(image_info != (const ImageInfo *) NULL);
4022 assert(image_info->signature == MagickCoreSignature);
4023 assert(image != (Image *) NULL);
4024 assert(image->signature == MagickCoreSignature);
4025 if (image->debug != MagickFalse)
4026 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4027 option=GetImageOption(image_info,"background");
4028 if (option != (const char *) NULL)
4029 (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
4030 exception);
4031 option=GetImageOption(image_info,"black-point-compensation");
4032 if (option != (const char *) NULL)
4033 image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
4034 MagickBooleanOptions,MagickFalse,option);
4035 option=GetImageOption(image_info,"blue-primary");
4036 if (option != (const char *) NULL)
4037 {
4038 flags=ParseGeometry(option,&geometry_info);
4039 image->chromaticity.blue_primary.x=geometry_info.rho;
4040 image->chromaticity.blue_primary.y=geometry_info.sigma;
4041 if ((flags & SigmaValue) == 0)
4042 image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4043 }
4044 option=GetImageOption(image_info,"bordercolor");
4045 if (option != (const char *) NULL)
4046 (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
4047 exception);
4048 /* FUTURE: do not sync compose to per-image compose setting here */
4049 option=GetImageOption(image_info,"compose");
4050 if (option != (const char *) NULL)
4051 image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
4052 MagickFalse,option);
4053 /* -- */
4054 option=GetImageOption(image_info,"compress");
4055 if (option != (const char *) NULL)
4056 image->compression=(CompressionType) ParseCommandOption(
4057 MagickCompressOptions,MagickFalse,option);
4058 option=GetImageOption(image_info,"debug");
4059 if (option != (const char *) NULL)
4060 image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
4061 MagickFalse,option);
4062 option=GetImageOption(image_info,"density");
4063 if (option != (const char *) NULL)
4064 {
4065 flags=ParseGeometry(option,&geometry_info);
4066 image->resolution.x=geometry_info.rho;
4067 image->resolution.y=geometry_info.sigma;
4068 if ((flags & SigmaValue) == 0)
4069 image->resolution.y=image->resolution.x;
4070 }
4071 option=GetImageOption(image_info,"depth");
4072 if (option != (const char *) NULL)
4073 image->depth=StringToUnsignedLong(option);
4074 option=GetImageOption(image_info,"endian");
4075 if (option != (const char *) NULL)
4076 image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
4077 MagickFalse,option);
4078 option=GetImageOption(image_info,"filter");
4079 if (option != (const char *) NULL)
4080 image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
4081 MagickFalse,option);
4082 option=GetImageOption(image_info,"fuzz");
4083 if (option != (const char *) NULL)
4084 image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
4085 option=GetImageOption(image_info,"gravity");
4086 if (option != (const char *) NULL)
4087 image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
4088 MagickFalse,option);
4089 option=GetImageOption(image_info,"green-primary");
4090 if (option != (const char *) NULL)
4091 {
4092 flags=ParseGeometry(option,&geometry_info);
4093 image->chromaticity.green_primary.x=geometry_info.rho;
4094 image->chromaticity.green_primary.y=geometry_info.sigma;
4095 if ((flags & SigmaValue) == 0)
4096 image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4097 }
4098 option=GetImageOption(image_info,"intent");
4099 if (option != (const char *) NULL)
4100 image->rendering_intent=(RenderingIntent) ParseCommandOption(
4101 MagickIntentOptions,MagickFalse,option);
4102 option=GetImageOption(image_info,"intensity");
4103 if (option != (const char *) NULL)
4104 image->intensity=(PixelIntensityMethod) ParseCommandOption(
4105 MagickPixelIntensityOptions,MagickFalse,option);
4106 option=GetImageOption(image_info,"interlace");
4107 if (option != (const char *) NULL)
4108 image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
4109 MagickFalse,option);
4110 option=GetImageOption(image_info,"interpolate");
4111 if (option != (const char *) NULL)
4112 image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
4113 MagickInterpolateOptions,MagickFalse,option);
4114 option=GetImageOption(image_info,"loop");
4115 if (option != (const char *) NULL)
4116 image->iterations=StringToUnsignedLong(option);
4117 option=GetImageOption(image_info,"mattecolor");
4118 if (option != (const char *) NULL)
4119 (void) QueryColorCompliance(option,AllCompliance,&image->matte_color,
4120 exception);
4121 option=GetImageOption(image_info,"orient");
4122 if (option != (const char *) NULL)
4123 image->orientation=(OrientationType) ParseCommandOption(
4124 MagickOrientationOptions,MagickFalse,option);
4125 option=GetImageOption(image_info,"page");
4126 if (option != (const char *) NULL)
4127 {
4128 char
4129 *geometry;
4130
4131 geometry=GetPageGeometry(option);
4132 flags=ParseAbsoluteGeometry(geometry,&image->page);
4133 geometry=DestroyString(geometry);
4134 }
4135 option=GetImageOption(image_info,"quality");
4136 if (option != (const char *) NULL)
4137 image->quality=StringToUnsignedLong(option);
4138 option=GetImageOption(image_info,"red-primary");
4139 if (option != (const char *) NULL)
4140 {
4141 flags=ParseGeometry(option,&geometry_info);
4142 image->chromaticity.red_primary.x=geometry_info.rho;
4143 image->chromaticity.red_primary.y=geometry_info.sigma;
4144 if ((flags & SigmaValue) == 0)
4145 image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4146 }
4147 if (image_info->quality != UndefinedCompressionQuality)
4148 image->quality=image_info->quality;
4149 option=GetImageOption(image_info,"scene");
4150 if (option != (const char *) NULL)
4151 image->scene=StringToUnsignedLong(option);
4152 option=GetImageOption(image_info,"taint");
4153 if (option != (const char *) NULL)
4154 image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
4155 MagickFalse,option);
4156 option=GetImageOption(image_info,"tile-offset");
4157 if (option != (const char *) NULL)
4158 {
4159 char
4160 *geometry;
4161
4162 geometry=GetPageGeometry(option);
4163 flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4164 geometry=DestroyString(geometry);
4165 }
4166 option=GetImageOption(image_info,"transparent-color");
4167 if (option != (const char *) NULL)
4168 (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
4169 exception);
4170 option=GetImageOption(image_info,"type");
4171 if (option != (const char *) NULL)
4172 image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
4173 option);
4174 option=GetImageOption(image_info,"units");
4175 units=image_info->units;
4176 if (option != (const char *) NULL)
4177 units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
4178 MagickFalse,option);
4179 if (units != UndefinedResolution)
4180 {
4181 if (image->units != units)
4182 switch (image->units)
4183 {
4184 case PixelsPerInchResolution:
4185 {
4186 if (units == PixelsPerCentimeterResolution)
4187 {
4188 image->resolution.x/=2.54;
4189 image->resolution.y/=2.54;
4190 }
4191 break;
4192 }
4193 case PixelsPerCentimeterResolution:
4194 {
4195 if (units == PixelsPerInchResolution)
4196 {
4197 image->resolution.x=(double) ((size_t) (100.0*2.54*
4198 image->resolution.x+0.5))/100.0;
4199 image->resolution.y=(double) ((size_t) (100.0*2.54*
4200 image->resolution.y+0.5))/100.0;
4201 }
4202 break;
4203 }
4204 default:
4205 break;
4206 }
4207 image->units=units;
4208 }
4209 option=GetImageOption(image_info,"virtual-pixel");
4210 if (option != (const char *) NULL)
4211 (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
4212 ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
4213 exception);
4214 option=GetImageOption(image_info,"white-point");
4215 if (option != (const char *) NULL)
4216 {
4217 flags=ParseGeometry(option,&geometry_info);
4218 image->chromaticity.white_point.x=geometry_info.rho;
4219 image->chromaticity.white_point.y=geometry_info.sigma;
4220 if ((flags & SigmaValue) == 0)
4221 image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4222 }
4223 /*
4224 Pointer to allow the lookup of pre-image artifact will fallback to a global
4225 option setting/define. This saves a lot of duplication of global options
4226 into per-image artifacts, while ensuring only specifically set per-image
4227 artifacts are preserved when parenthesis ends.
4228 */
4229 if (image->image_info != (ImageInfo *) NULL)
4230 image->image_info=DestroyImageInfo(image->image_info);
4231 image->image_info=CloneImageInfo(image_info);
4232 return(MagickTrue);
4233 }
4234