1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % AAA TTTTT TTTTT RRRR IIIII BBBB U U TTTTT EEEEE %
7 % A A T T R R I B B U U T E %
8 % AAAAA T T RRRR I BBBB U U T EEE %
9 % A A T T R R I B B U U T E %
10 % A A T T R R IIIII BBBB UUU T EEEEE %
11 % %
12 % %
13 % MagickCore Get / Set Image Attributes %
14 % %
15 % Software Design %
16 % Cristy %
17 % October 2002 %
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/artifact.h"
45 #include "MagickCore/attribute.h"
46 #include "MagickCore/blob.h"
47 #include "MagickCore/blob-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/cache-private.h"
50 #include "MagickCore/cache-view.h"
51 #include "MagickCore/channel.h"
52 #include "MagickCore/client.h"
53 #include "MagickCore/color.h"
54 #include "MagickCore/color-private.h"
55 #include "MagickCore/colormap.h"
56 #include "MagickCore/colormap-private.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/constitute.h"
62 #include "MagickCore/draw.h"
63 #include "MagickCore/draw-private.h"
64 #include "MagickCore/effect.h"
65 #include "MagickCore/enhance.h"
66 #include "MagickCore/exception.h"
67 #include "MagickCore/exception-private.h"
68 #include "MagickCore/geometry.h"
69 #include "MagickCore/histogram.h"
70 #include "MagickCore/identify.h"
71 #include "MagickCore/image.h"
72 #include "MagickCore/image-private.h"
73 #include "MagickCore/list.h"
74 #include "MagickCore/log.h"
75 #include "MagickCore/memory_.h"
76 #include "MagickCore/magick.h"
77 #include "MagickCore/monitor.h"
78 #include "MagickCore/monitor-private.h"
79 #include "MagickCore/option.h"
80 #include "MagickCore/paint.h"
81 #include "MagickCore/pixel.h"
82 #include "MagickCore/pixel-accessor.h"
83 #include "MagickCore/property.h"
84 #include "MagickCore/quantize.h"
85 #include "MagickCore/quantum-private.h"
86 #include "MagickCore/random_.h"
87 #include "MagickCore/resource_.h"
88 #include "MagickCore/semaphore.h"
89 #include "MagickCore/segment.h"
90 #include "MagickCore/splay-tree.h"
91 #include "MagickCore/string_.h"
92 #include "MagickCore/string-private.h"
93 #include "MagickCore/thread-private.h"
94 #include "MagickCore/threshold.h"
95 #include "MagickCore/transform.h"
96 #include "MagickCore/utility.h"
97
98 /*
99 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 % %
101 % %
102 % %
103 + G e t I m a g e B o u n d i n g B o x %
104 % %
105 % %
106 % %
107 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108 %
109 % GetImageBoundingBox() returns the bounding box of an image canvas.
110 %
111 % The format of the GetImageBoundingBox method is:
112 %
113 % RectangleInfo GetImageBoundingBox(const Image *image,
114 % ExceptionInfo *exception)
115 %
116 % A description of each parameter follows:
117 %
118 % o bounds: Method GetImageBoundingBox returns the bounding box of an
119 % image canvas.
120 %
121 % o image: the image.
122 %
123 % o exception: return any errors or warnings in this structure.
124 %
125 */
126
127 typedef struct _EdgeInfo
128 {
129 double
130 left,
131 right,
132 top,
133 bottom;
134 } EdgeInfo;
135
GetEdgeBackgroundFactor(const Image * image,const CacheView * image_view,const GravityType gravity,const size_t width,const size_t height,const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo * exception)136 static double GetEdgeBackgroundFactor(const Image *image,
137 const CacheView *image_view,const GravityType gravity,const size_t width,
138 const size_t height,const ssize_t x_offset,const ssize_t y_offset,
139 ExceptionInfo *exception)
140 {
141 CacheView
142 *edge_view;
143
144 double
145 factor;
146
147 Image
148 *edge_image;
149
150 PixelInfo
151 background,
152 pixel;
153
154 RectangleInfo
155 edge_geometry;
156
157 register const Quantum
158 *p;
159
160 ssize_t
161 y;
162
163 /*
164 Determine the percent of image background for this edge.
165 */
166 switch (gravity)
167 {
168 case NorthWestGravity:
169 case NorthGravity:
170 default:
171 {
172 p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
173 break;
174 }
175 case NorthEastGravity:
176 case EastGravity:
177 {
178 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,0,1,1,
179 exception);
180 break;
181 }
182 case SouthEastGravity:
183 case SouthGravity:
184 {
185 p=GetCacheViewVirtualPixels(image_view,(ssize_t) image->columns-1,
186 (ssize_t) image->rows-1,1,1,exception);
187 break;
188 }
189 case SouthWestGravity:
190 case WestGravity:
191 {
192 p=GetCacheViewVirtualPixels(image_view,0,(ssize_t) image->rows-1,1,1,
193 exception);
194 break;
195 }
196 }
197 GetPixelInfoPixel(image,p,&background);
198 edge_geometry.width=width;
199 edge_geometry.height=height;
200 edge_geometry.x=x_offset;
201 edge_geometry.y=y_offset;
202 GravityAdjustGeometry(image->columns,image->rows,gravity,&edge_geometry);
203 edge_image=CropImage(image,&edge_geometry,exception);
204 if (edge_image == (Image *) NULL)
205 return(0.0);
206 factor=0.0;
207 edge_view=AcquireVirtualCacheView(edge_image,exception);
208 for (y=0; y < (ssize_t) edge_image->rows; y++)
209 {
210 register ssize_t
211 x;
212
213 p=GetCacheViewVirtualPixels(edge_view,0,y,edge_image->columns,1,exception);
214 if (p == (const Quantum *) NULL)
215 break;
216 for (x=0; x < (ssize_t) edge_image->columns; x++)
217 {
218 GetPixelInfoPixel(edge_image,p,&pixel);
219 if (IsFuzzyEquivalencePixelInfo(&pixel,&background) == MagickFalse)
220 factor++;
221 p+=GetPixelChannels(edge_image);
222 }
223 }
224 factor/=((double) edge_image->columns*edge_image->rows);
225 edge_view=DestroyCacheView(edge_view);
226 edge_image=DestroyImage(edge_image);
227 return(factor);
228 }
229
GetMinEdgeBackgroundFactor(const EdgeInfo * edge)230 static inline double GetMinEdgeBackgroundFactor(const EdgeInfo *edge)
231 {
232 double
233 factor;
234
235 factor=MagickMin(MagickMin(MagickMin(edge->left,edge->right),edge->top),
236 edge->bottom);
237 return(factor);
238 }
239
GetImageBoundingBox(const Image * image,ExceptionInfo * exception)240 MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
241 ExceptionInfo *exception)
242 {
243 CacheView
244 *edge_view;
245
246 const char
247 *artifact;
248
249 double
250 background_factor,
251 percent_background;
252
253 EdgeInfo
254 edge,
255 vertex;
256
257 Image
258 *edge_image;
259
260 RectangleInfo
261 bounds;
262
263 /*
264 Get the image bounding box.
265 */
266 assert(image != (Image *) NULL);
267 assert(image->signature == MagickCoreSignature);
268 if (image->debug != MagickFalse)
269 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
270 SetGeometry(image,&bounds);
271 edge_image=CloneImage(image,0,0,MagickTrue,exception);
272 if (edge_image == (Image *) NULL)
273 return(bounds);
274 (void) ParseAbsoluteGeometry("0x0+0+0",&edge_image->page);
275 memset(&vertex,0,sizeof(vertex));
276 edge_view=AcquireVirtualCacheView(edge_image,exception);
277 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,WestGravity,
278 1,0,0,0,exception);
279 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,EastGravity,
280 1,0,0,0,exception);
281 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,NorthGravity,
282 0,1,0,0,exception);
283 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,SouthGravity,
284 0,1,0,0,exception);
285 percent_background=1.0;
286 artifact=GetImageArtifact(edge_image,"trim:percent-background");
287 if (artifact != (const char *) NULL)
288 percent_background=StringToDouble(artifact,(char **) NULL)/100.0;
289 percent_background=MagickMin(MagickMax(1.0-percent_background,MagickEpsilon),
290 1.0);
291 background_factor=GetMinEdgeBackgroundFactor(&edge);
292 for ( ; background_factor < percent_background;
293 background_factor=GetMinEdgeBackgroundFactor(&edge))
294 {
295 if ((bounds.width == 0) || (bounds.height == 0))
296 break;
297 if (fabs(edge.left-background_factor) < MagickEpsilon)
298 {
299 /*
300 Trim left edge.
301 */
302 vertex.left++;
303 bounds.width--;
304 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
305 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
306 vertex.top,exception);
307 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
308 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
309 vertex.top,exception);
310 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
311 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
312 vertex.bottom,exception);
313 continue;
314 }
315 if (fabs(edge.right-background_factor) < MagickEpsilon)
316 {
317 /*
318 Trim right edge.
319 */
320 vertex.right++;
321 bounds.width--;
322 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
323 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
324 vertex.top,exception);
325 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
326 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
327 vertex.top,exception);
328 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
329 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
330 vertex.bottom,exception);
331 continue;
332 }
333 if (fabs(edge.top-background_factor) < MagickEpsilon)
334 {
335 /*
336 Trim top edge.
337 */
338 vertex.top++;
339 bounds.height--;
340 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
341 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
342 vertex.top,exception);
343 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
344 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
345 vertex.top,exception);
346 edge.top=GetEdgeBackgroundFactor(edge_image,edge_view,
347 NorthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
348 vertex.top,exception);
349 continue;
350 }
351 if (fabs(edge.bottom-background_factor) < MagickEpsilon)
352 {
353 /*
354 Trim bottom edge.
355 */
356 vertex.bottom++;
357 bounds.height--;
358 edge.left=GetEdgeBackgroundFactor(edge_image,edge_view,
359 NorthWestGravity,1,bounds.height,(ssize_t) vertex.left,(ssize_t)
360 vertex.top,exception);
361 edge.right=GetEdgeBackgroundFactor(edge_image,edge_view,
362 NorthEastGravity,1,bounds.height,(ssize_t) vertex.right,(ssize_t)
363 vertex.top,exception);
364 edge.bottom=GetEdgeBackgroundFactor(edge_image,edge_view,
365 SouthWestGravity,bounds.width,1,(ssize_t) vertex.left,(ssize_t)
366 vertex.bottom,exception);
367 continue;
368 }
369 }
370 edge_view=DestroyCacheView(edge_view);
371 edge_image=DestroyImage(edge_image);
372 bounds.x=(ssize_t) vertex.left;
373 bounds.y=(ssize_t) vertex.top;
374 if ((bounds.width == 0) || (bounds.height == 0))
375 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
376 "GeometryDoesNotContainImage","`%s'",image->filename);
377 return(bounds);
378 }
379
380 /*
381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 % %
383 % %
384 % %
385 % G e t I m a g e D e p t h %
386 % %
387 % %
388 % %
389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 %
391 % GetImageDepth() returns the depth of a particular image channel.
392 %
393 % The format of the GetImageDepth method is:
394 %
395 % size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
396 %
397 % A description of each parameter follows:
398 %
399 % o image: the image.
400 %
401 % o exception: return any errors or warnings in this structure.
402 %
403 */
GetImageDepth(const Image * image,ExceptionInfo * exception)404 MagickExport size_t GetImageDepth(const Image *image,ExceptionInfo *exception)
405 {
406 CacheView
407 *image_view;
408
409 MagickBooleanType
410 status;
411
412 register ssize_t
413 i;
414
415 size_t
416 *current_depth,
417 depth,
418 number_threads;
419
420 ssize_t
421 y;
422
423 /*
424 Compute image depth.
425 */
426 assert(image != (Image *) NULL);
427 assert(image->signature == MagickCoreSignature);
428 if (image->debug != MagickFalse)
429 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
430 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
431 current_depth=(size_t *) AcquireQuantumMemory(number_threads,
432 sizeof(*current_depth));
433 if (current_depth == (size_t *) NULL)
434 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
435 status=MagickTrue;
436 for (i=0; i < (ssize_t) number_threads; i++)
437 current_depth[i]=1;
438 if ((image->storage_class == PseudoClass) &&
439 (image->alpha_trait == UndefinedPixelTrait))
440 {
441 for (i=0; i < (ssize_t) image->colors; i++)
442 {
443 const int
444 id = GetOpenMPThreadId();
445
446 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
447 {
448 MagickBooleanType
449 atDepth;
450
451 QuantumAny
452 range;
453
454 atDepth=MagickTrue;
455 range=GetQuantumRange(current_depth[id]);
456 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
457 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].red),range) == MagickFalse)
458 atDepth=MagickFalse;
459 if ((atDepth != MagickFalse) &&
460 (GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
461 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].green),range) == MagickFalse)
462 atDepth=MagickFalse;
463 if ((atDepth != MagickFalse) &&
464 (GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
465 if (IsPixelAtDepth(ClampToQuantum(image->colormap[i].blue),range) == MagickFalse)
466 atDepth=MagickFalse;
467 if ((atDepth != MagickFalse))
468 break;
469 current_depth[id]++;
470 }
471 }
472 depth=current_depth[0];
473 for (i=1; i < (ssize_t) number_threads; i++)
474 if (depth < current_depth[i])
475 depth=current_depth[i];
476 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
477 return(depth);
478 }
479 image_view=AcquireVirtualCacheView(image,exception);
480 #if !defined(MAGICKCORE_HDRI_SUPPORT)
481 if ((1UL*QuantumRange) <= MaxMap)
482 {
483 size_t
484 *depth_map;
485
486 /*
487 Scale pixels to desired (optimized with depth map).
488 */
489 depth_map=(size_t *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
490 if (depth_map == (size_t *) NULL)
491 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
492 for (i=0; i <= (ssize_t) MaxMap; i++)
493 {
494 unsigned int
495 depth;
496
497 for (depth=1; depth < MAGICKCORE_QUANTUM_DEPTH; depth++)
498 {
499 Quantum
500 pixel;
501
502 QuantumAny
503 range;
504
505 range=GetQuantumRange(depth);
506 pixel=(Quantum) i;
507 if (pixel == ScaleAnyToQuantum(ScaleQuantumToAny(pixel,range),range))
508 break;
509 }
510 depth_map[i]=depth;
511 }
512 #if defined(MAGICKCORE_OPENMP_SUPPORT)
513 #pragma omp parallel for schedule(static) shared(status) \
514 magick_number_threads(image,image,image->rows,1)
515 #endif
516 for (y=0; y < (ssize_t) image->rows; y++)
517 {
518 const int
519 id = GetOpenMPThreadId();
520
521 register const Quantum
522 *magick_restrict p;
523
524 register ssize_t
525 x;
526
527 if (status == MagickFalse)
528 continue;
529 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
530 if (p == (const Quantum *) NULL)
531 continue;
532 for (x=0; x < (ssize_t) image->columns; x++)
533 {
534 register ssize_t
535 i;
536
537 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
538 {
539 PixelChannel channel = GetPixelChannelChannel(image,i);
540 PixelTrait traits = GetPixelChannelTraits(image,channel);
541 if ((traits & UpdatePixelTrait) == 0)
542 continue;
543 if (depth_map[ScaleQuantumToMap(p[i])] > current_depth[id])
544 current_depth[id]=depth_map[ScaleQuantumToMap(p[i])];
545 }
546 p+=GetPixelChannels(image);
547 }
548 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
549 status=MagickFalse;
550 }
551 image_view=DestroyCacheView(image_view);
552 depth=current_depth[0];
553 for (i=1; i < (ssize_t) number_threads; i++)
554 if (depth < current_depth[i])
555 depth=current_depth[i];
556 depth_map=(size_t *) RelinquishMagickMemory(depth_map);
557 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
558 return(depth);
559 }
560 #endif
561 /*
562 Compute pixel depth.
563 */
564 #if defined(MAGICKCORE_OPENMP_SUPPORT)
565 #pragma omp parallel for schedule(static) shared(status) \
566 magick_number_threads(image,image,image->rows,1)
567 #endif
568 for (y=0; y < (ssize_t) image->rows; y++)
569 {
570 const int
571 id = GetOpenMPThreadId();
572
573 register const Quantum
574 *magick_restrict p;
575
576 register ssize_t
577 x;
578
579 if (status == MagickFalse)
580 continue;
581 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
582 if (p == (const Quantum *) NULL)
583 continue;
584 for (x=0; x < (ssize_t) image->columns; x++)
585 {
586 register ssize_t
587 i;
588
589 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
590 {
591 PixelChannel
592 channel;
593
594 PixelTrait
595 traits;
596
597 channel=GetPixelChannelChannel(image,i);
598 traits=GetPixelChannelTraits(image,channel);
599 if ((traits & UpdatePixelTrait) == 0)
600 continue;
601 while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
602 {
603 QuantumAny
604 range;
605
606 range=GetQuantumRange(current_depth[id]);
607 if (p[i] == ScaleAnyToQuantum(ScaleQuantumToAny(p[i],range),range))
608 break;
609 current_depth[id]++;
610 }
611 }
612 p+=GetPixelChannels(image);
613 }
614 if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
615 status=MagickFalse;
616 }
617 image_view=DestroyCacheView(image_view);
618 depth=current_depth[0];
619 for (i=1; i < (ssize_t) number_threads; i++)
620 if (depth < current_depth[i])
621 depth=current_depth[i];
622 current_depth=(size_t *) RelinquishMagickMemory(current_depth);
623 return(depth);
624 }
625
626 /*
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628 % %
629 % %
630 % %
631 % G e t I m a g e Q u a n t u m D e p t h %
632 % %
633 % %
634 % %
635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636 %
637 % GetImageQuantumDepth() returns the depth of the image rounded to a legal
638 % quantum depth: 8, 16, or 32.
639 %
640 % The format of the GetImageQuantumDepth method is:
641 %
642 % size_t GetImageQuantumDepth(const Image *image,
643 % const MagickBooleanType constrain)
644 %
645 % A description of each parameter follows:
646 %
647 % o image: the image.
648 %
649 % o constrain: A value other than MagickFalse, constrains the depth to
650 % a maximum of MAGICKCORE_QUANTUM_DEPTH.
651 %
652 */
GetImageQuantumDepth(const Image * image,const MagickBooleanType constrain)653 MagickExport size_t GetImageQuantumDepth(const Image *image,
654 const MagickBooleanType constrain)
655 {
656 size_t
657 depth;
658
659 depth=image->depth;
660 if (depth <= 8)
661 depth=8;
662 else
663 if (depth <= 16)
664 depth=16;
665 else
666 if (depth <= 32)
667 depth=32;
668 else
669 if (depth <= 64)
670 depth=64;
671 if (constrain != MagickFalse)
672 depth=(size_t) MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH);
673 return(depth);
674 }
675
676 /*
677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 % %
679 % %
680 % %
681 % G e t I m a g e T y p e %
682 % %
683 % %
684 % %
685 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 %
687 % GetImageType() returns the type of image:
688 %
689 % Bilevel Grayscale GrayscaleMatte
690 % Palette PaletteMatte TrueColor
691 % TrueColorMatte ColorSeparation ColorSeparationMatte
692 %
693 % The format of the GetImageType method is:
694 %
695 % ImageType GetImageType(const Image *image)
696 %
697 % A description of each parameter follows:
698 %
699 % o image: the image.
700 %
701 */
GetImageType(const Image * image)702 MagickExport ImageType GetImageType(const Image *image)
703 {
704 assert(image != (Image *) NULL);
705 assert(image->signature == MagickCoreSignature);
706 if (image->colorspace == CMYKColorspace)
707 {
708 if (image->alpha_trait == UndefinedPixelTrait)
709 return(ColorSeparationType);
710 return(ColorSeparationAlphaType);
711 }
712 if (IsImageMonochrome(image) != MagickFalse)
713 return(BilevelType);
714 if (IsImageGray(image) != MagickFalse)
715 {
716 if (image->alpha_trait != UndefinedPixelTrait)
717 return(GrayscaleAlphaType);
718 return(GrayscaleType);
719 }
720 if (IsPaletteImage(image) != MagickFalse)
721 {
722 if (image->alpha_trait != UndefinedPixelTrait)
723 return(PaletteAlphaType);
724 return(PaletteType);
725 }
726 if (image->alpha_trait != UndefinedPixelTrait)
727 return(TrueColorAlphaType);
728 return(TrueColorType);
729 }
730
731 /*
732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
733 % %
734 % %
735 % %
736 % I d e n t i f y I m a g e G r a y %
737 % %
738 % %
739 % %
740 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
741 %
742 % IdentifyImageGray() returns grayscale if all the pixels in the image have
743 % the same red, green, and blue intensities, and bi-level is the intensity is
744 % either 0 or QuantumRange. Otherwise undefined is returned.
745 %
746 % The format of the IdentifyImageGray method is:
747 %
748 % ImageType IdentifyImageGray(const Image *image,ExceptionInfo *exception)
749 %
750 % A description of each parameter follows:
751 %
752 % o image: the image.
753 %
754 % o exception: return any errors or warnings in this structure.
755 %
756 */
IdentifyImageGray(const Image * image,ExceptionInfo * exception)757 MagickExport ImageType IdentifyImageGray(const Image *image,
758 ExceptionInfo *exception)
759 {
760 CacheView
761 *image_view;
762
763 ImageType
764 type;
765
766 register const Quantum
767 *p;
768
769 register ssize_t
770 x;
771
772 ssize_t
773 y;
774
775 assert(image != (Image *) NULL);
776 assert(image->signature == MagickCoreSignature);
777 if (image->debug != MagickFalse)
778 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
779 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
780 (image->type == GrayscaleAlphaType))
781 return(image->type);
782 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
783 return(UndefinedType);
784 type=BilevelType;
785 image_view=AcquireVirtualCacheView(image,exception);
786 for (y=0; y < (ssize_t) image->rows; y++)
787 {
788 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
789 if (p == (const Quantum *) NULL)
790 break;
791 for (x=0; x < (ssize_t) image->columns; x++)
792 {
793 if (IsPixelGray(image,p) == MagickFalse)
794 {
795 type=UndefinedType;
796 break;
797 }
798 if ((type == BilevelType) &&
799 (IsPixelMonochrome(image,p) == MagickFalse))
800 type=GrayscaleType;
801 p+=GetPixelChannels(image);
802 }
803 if (type == UndefinedType)
804 break;
805 }
806 image_view=DestroyCacheView(image_view);
807 if ((type == GrayscaleType) && (image->alpha_trait != UndefinedPixelTrait))
808 type=GrayscaleAlphaType;
809 return(type);
810 }
811
812 /*
813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
814 % %
815 % %
816 % %
817 % I d e n t i f y I m a g e M o n o c h r o m e %
818 % %
819 % %
820 % %
821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
822 %
823 % IdentifyImageMonochrome() returns MagickTrue if all the pixels in the image
824 % have the same red, green, and blue intensities and the intensity is either
825 % 0 or QuantumRange.
826 %
827 % The format of the IdentifyImageMonochrome method is:
828 %
829 % MagickBooleanType IdentifyImageMonochrome(const Image *image,
830 % ExceptionInfo *exception)
831 %
832 % A description of each parameter follows:
833 %
834 % o image: the image.
835 %
836 % o exception: return any errors or warnings in this structure.
837 %
838 */
IdentifyImageMonochrome(const Image * image,ExceptionInfo * exception)839 MagickExport MagickBooleanType IdentifyImageMonochrome(const Image *image,
840 ExceptionInfo *exception)
841 {
842 CacheView
843 *image_view;
844
845 MagickBooleanType
846 bilevel;
847
848 register ssize_t
849 x;
850
851 register const Quantum
852 *p;
853
854 ssize_t
855 y;
856
857 assert(image != (Image *) NULL);
858 assert(image->signature == MagickCoreSignature);
859 if (image->debug != MagickFalse)
860 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
861 if (image->type == BilevelType)
862 return(MagickTrue);
863 if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
864 return(MagickFalse);
865 bilevel=MagickTrue;
866 image_view=AcquireVirtualCacheView(image,exception);
867 for (y=0; y < (ssize_t) image->rows; y++)
868 {
869 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
870 if (p == (const Quantum *) NULL)
871 break;
872 for (x=0; x < (ssize_t) image->columns; x++)
873 {
874 if (IsPixelMonochrome(image,p) == MagickFalse)
875 {
876 bilevel=MagickFalse;
877 break;
878 }
879 p+=GetPixelChannels(image);
880 }
881 if (bilevel == MagickFalse)
882 break;
883 }
884 image_view=DestroyCacheView(image_view);
885 return(bilevel);
886 }
887
888 /*
889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
890 % %
891 % %
892 % %
893 % I d e n t i f y I m a g e T y p e %
894 % %
895 % %
896 % %
897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
898 %
899 % IdentifyImageType() returns the potential type of image:
900 %
901 % Bilevel Grayscale GrayscaleMatte
902 % Palette PaletteMatte TrueColor
903 % TrueColorMatte ColorSeparation ColorSeparationMatte
904 %
905 % To ensure the image type matches its potential, use SetImageType():
906 %
907 % (void) SetImageType(image,IdentifyImageType(image,exception),exception);
908 %
909 % The format of the IdentifyImageType method is:
910 %
911 % ImageType IdentifyImageType(const Image *image,ExceptionInfo *exception)
912 %
913 % A description of each parameter follows:
914 %
915 % o image: the image.
916 %
917 % o exception: return any errors or warnings in this structure.
918 %
919 */
IdentifyImageType(const Image * image,ExceptionInfo * exception)920 MagickExport ImageType IdentifyImageType(const Image *image,
921 ExceptionInfo *exception)
922 {
923 assert(image != (Image *) NULL);
924 assert(image->signature == MagickCoreSignature);
925 if (image->debug != MagickFalse)
926 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
927 if (image->colorspace == CMYKColorspace)
928 {
929 if (image->alpha_trait == UndefinedPixelTrait)
930 return(ColorSeparationType);
931 return(ColorSeparationAlphaType);
932 }
933 if (IdentifyImageMonochrome(image,exception) != MagickFalse)
934 return(BilevelType);
935 if (IdentifyImageGray(image,exception) != UndefinedType)
936 {
937 if (image->alpha_trait != UndefinedPixelTrait)
938 return(GrayscaleAlphaType);
939 return(GrayscaleType);
940 }
941 if (IdentifyPaletteImage(image,exception) != MagickFalse)
942 {
943 if (image->alpha_trait != UndefinedPixelTrait)
944 return(PaletteAlphaType);
945 return(PaletteType);
946 }
947 if (image->alpha_trait != UndefinedPixelTrait)
948 return(TrueColorAlphaType);
949 return(TrueColorType);
950 }
951
952 /*
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954 % %
955 % %
956 % %
957 % I s I m a g e G r a y %
958 % %
959 % %
960 % %
961 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
962 %
963 % IsImageGray() returns MagickTrue if the type of the image is grayscale or
964 % bi-level.
965 %
966 % The format of the IsImageGray method is:
967 %
968 % MagickBooleanType IsImageGray(const Image *image)
969 %
970 % A description of each parameter follows:
971 %
972 % o image: the image.
973 %
974 */
IsImageGray(const Image * image)975 MagickExport MagickBooleanType IsImageGray(const Image *image)
976 {
977 assert(image != (Image *) NULL);
978 assert(image->signature == MagickCoreSignature);
979 if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
980 (image->type == GrayscaleAlphaType))
981 return(MagickTrue);
982 return(MagickFalse);
983 }
984
985 /*
986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 % %
988 % %
989 % %
990 % I s I m a g e M o n o c h r o m e %
991 % %
992 % %
993 % %
994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
995 %
996 % IsImageMonochrome() returns MagickTrue if type of the image is bi-level.
997 %
998 % The format of the IsImageMonochrome method is:
999 %
1000 % MagickBooleanType IsImageMonochrome(const Image *image)
1001 %
1002 % A description of each parameter follows:
1003 %
1004 % o image: the image.
1005 %
1006 */
IsImageMonochrome(const Image * image)1007 MagickExport MagickBooleanType IsImageMonochrome(const Image *image)
1008 {
1009 assert(image != (Image *) NULL);
1010 assert(image->signature == MagickCoreSignature);
1011 if (image->type == BilevelType)
1012 return(MagickTrue);
1013 return(MagickFalse);
1014 }
1015
1016 /*
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 % %
1019 % %
1020 % %
1021 % I s I m a g e O p a q u e %
1022 % %
1023 % %
1024 % %
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026 %
1027 % IsImageOpaque() returns MagickTrue if none of the pixels in the image have
1028 % an alpha value other than OpaqueAlpha (QuantumRange).
1029 %
1030 % Will return true immediatally is alpha channel is not available.
1031 %
1032 % The format of the IsImageOpaque method is:
1033 %
1034 % MagickBooleanType IsImageOpaque(const Image *image,
1035 % ExceptionInfo *exception)
1036 %
1037 % A description of each parameter follows:
1038 %
1039 % o image: the image.
1040 %
1041 % o exception: return any errors or warnings in this structure.
1042 %
1043 */
IsImageOpaque(const Image * image,ExceptionInfo * exception)1044 MagickExport MagickBooleanType IsImageOpaque(const Image *image,
1045 ExceptionInfo *exception)
1046 {
1047 CacheView
1048 *image_view;
1049
1050 register const Quantum
1051 *p;
1052
1053 register ssize_t
1054 x;
1055
1056 ssize_t
1057 y;
1058
1059 /*
1060 Determine if image is opaque.
1061 */
1062 assert(image != (Image *) NULL);
1063 assert(image->signature == MagickCoreSignature);
1064 if (image->debug != MagickFalse)
1065 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1066 if (image->alpha_trait == UndefinedPixelTrait)
1067 return(MagickTrue);
1068 image_view=AcquireVirtualCacheView(image,exception);
1069 for (y=0; y < (ssize_t) image->rows; y++)
1070 {
1071 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1072 if (p == (const Quantum *) NULL)
1073 break;
1074 for (x=0; x < (ssize_t) image->columns; x++)
1075 {
1076 if (GetPixelAlpha(image,p) != OpaqueAlpha)
1077 break;
1078 p+=GetPixelChannels(image);
1079 }
1080 if (x < (ssize_t) image->columns)
1081 break;
1082 }
1083 image_view=DestroyCacheView(image_view);
1084 return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);
1085 }
1086
1087 /*
1088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1089 % %
1090 % %
1091 % %
1092 % S e t I m a g e D e p t h %
1093 % %
1094 % %
1095 % %
1096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1097 %
1098 % SetImageDepth() sets the depth of the image.
1099 %
1100 % The format of the SetImageDepth method is:
1101 %
1102 % MagickBooleanType SetImageDepth(Image *image,const size_t depth,
1103 % ExceptionInfo *exception)
1104 %
1105 % A description of each parameter follows:
1106 %
1107 % o image: the image.
1108 %
1109 % o channel: the channel.
1110 %
1111 % o depth: the image depth.
1112 %
1113 % o exception: return any errors or warnings in this structure.
1114 %
1115 */
SetImageDepth(Image * image,const size_t depth,ExceptionInfo * exception)1116 MagickExport MagickBooleanType SetImageDepth(Image *image,
1117 const size_t depth,ExceptionInfo *exception)
1118 {
1119 CacheView
1120 *image_view;
1121
1122 MagickBooleanType
1123 status;
1124
1125 QuantumAny
1126 range;
1127
1128 ssize_t
1129 y;
1130
1131 assert(image != (Image *) NULL);
1132 if (image->debug != MagickFalse)
1133 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1134 assert(image->signature == MagickCoreSignature);
1135 if (depth >= MAGICKCORE_QUANTUM_DEPTH)
1136 {
1137 image->depth=depth;
1138 return(MagickTrue);
1139 }
1140 range=GetQuantumRange(depth);
1141 if (image->storage_class == PseudoClass)
1142 {
1143 register ssize_t
1144 i;
1145
1146 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1147 #pragma omp parallel for schedule(static) shared(status) \
1148 magick_number_threads(image,image,image->colors,1)
1149 #endif
1150 for (i=0; i < (ssize_t) image->colors; i++)
1151 {
1152 if ((GetPixelRedTraits(image) & UpdatePixelTrait) != 0)
1153 image->colormap[i].red=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1154 ClampPixel(image->colormap[i].red),range),range);
1155 if ((GetPixelGreenTraits(image) & UpdatePixelTrait) != 0)
1156 image->colormap[i].green=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1157 ClampPixel(image->colormap[i].green),range),range);
1158 if ((GetPixelBlueTraits(image) & UpdatePixelTrait) != 0)
1159 image->colormap[i].blue=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1160 ClampPixel(image->colormap[i].blue),range),range);
1161 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
1162 image->colormap[i].alpha=(double) ScaleAnyToQuantum(ScaleQuantumToAny(
1163 ClampPixel(image->colormap[i].alpha),range),range);
1164 }
1165 }
1166 status=MagickTrue;
1167 image_view=AcquireAuthenticCacheView(image,exception);
1168 #if !defined(MAGICKCORE_HDRI_SUPPORT)
1169 if ((1UL*QuantumRange) <= MaxMap)
1170 {
1171 Quantum
1172 *depth_map;
1173
1174 register ssize_t
1175 i;
1176
1177 /*
1178 Scale pixels to desired (optimized with depth map).
1179 */
1180 depth_map=(Quantum *) AcquireQuantumMemory(MaxMap+1,sizeof(*depth_map));
1181 if (depth_map == (Quantum *) NULL)
1182 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1183 for (i=0; i <= (ssize_t) MaxMap; i++)
1184 depth_map[i]=ScaleAnyToQuantum(ScaleQuantumToAny((Quantum) i,range),
1185 range);
1186 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1187 #pragma omp parallel for schedule(static) shared(status) \
1188 magick_number_threads(image,image,image->rows,1)
1189 #endif
1190 for (y=0; y < (ssize_t) image->rows; y++)
1191 {
1192 register ssize_t
1193 x;
1194
1195 register Quantum
1196 *magick_restrict q;
1197
1198 if (status == MagickFalse)
1199 continue;
1200 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1201 exception);
1202 if (q == (Quantum *) NULL)
1203 {
1204 status=MagickFalse;
1205 continue;
1206 }
1207 for (x=0; x < (ssize_t) image->columns; x++)
1208 {
1209 register ssize_t
1210 i;
1211
1212 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1213 {
1214 PixelChannel
1215 channel;
1216
1217 PixelTrait
1218 traits;
1219
1220 channel=GetPixelChannelChannel(image,i);
1221 traits=GetPixelChannelTraits(image,channel);
1222 if ((traits & UpdatePixelTrait) == 0)
1223 continue;
1224 q[i]=depth_map[ScaleQuantumToMap(q[i])];
1225 }
1226 q+=GetPixelChannels(image);
1227 }
1228 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1229 {
1230 status=MagickFalse;
1231 continue;
1232 }
1233 }
1234 image_view=DestroyCacheView(image_view);
1235 depth_map=(Quantum *) RelinquishMagickMemory(depth_map);
1236 if (status != MagickFalse)
1237 image->depth=depth;
1238 return(status);
1239 }
1240 #endif
1241 /*
1242 Scale pixels to desired depth.
1243 */
1244 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1245 #pragma omp parallel for schedule(static) shared(status) \
1246 magick_number_threads(image,image,image->rows,1)
1247 #endif
1248 for (y=0; y < (ssize_t) image->rows; y++)
1249 {
1250 register ssize_t
1251 x;
1252
1253 register Quantum
1254 *magick_restrict q;
1255
1256 if (status == MagickFalse)
1257 continue;
1258 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1259 if (q == (Quantum *) NULL)
1260 {
1261 status=MagickFalse;
1262 continue;
1263 }
1264 for (x=0; x < (ssize_t) image->columns; x++)
1265 {
1266 register ssize_t
1267 i;
1268
1269 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1270 {
1271 PixelChannel
1272 channel;
1273
1274 PixelTrait
1275 traits;
1276
1277 channel=GetPixelChannelChannel(image,i);
1278 traits=GetPixelChannelTraits(image,channel);
1279 if ((traits & UpdatePixelTrait) == 0)
1280 continue;
1281 q[i]=ScaleAnyToQuantum(ScaleQuantumToAny(ClampPixel((MagickRealType)
1282 q[i]),range),range);
1283 }
1284 q+=GetPixelChannels(image);
1285 }
1286 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1287 {
1288 status=MagickFalse;
1289 continue;
1290 }
1291 }
1292 image_view=DestroyCacheView(image_view);
1293 if (status != MagickFalse)
1294 image->depth=depth;
1295 return(status);
1296 }
1297
1298 /*
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300 % %
1301 % %
1302 % %
1303 % S e t I m a g e T y p e %
1304 % %
1305 % %
1306 % %
1307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308 %
1309 % SetImageType() sets the type of image. Choose from these types:
1310 %
1311 % Bilevel Grayscale GrayscaleMatte
1312 % Palette PaletteMatte TrueColor
1313 % TrueColorMatte ColorSeparation ColorSeparationMatte
1314 % OptimizeType
1315 %
1316 % The format of the SetImageType method is:
1317 %
1318 % MagickBooleanType SetImageType(Image *image,const ImageType type,
1319 % ExceptionInfo *exception)
1320 %
1321 % A description of each parameter follows:
1322 %
1323 % o image: the image.
1324 %
1325 % o type: Image type.
1326 %
1327 % o exception: return any errors or warnings in this structure.
1328 %
1329 */
SetImageType(Image * image,const ImageType type,ExceptionInfo * exception)1330 MagickExport MagickBooleanType SetImageType(Image *image,const ImageType type,
1331 ExceptionInfo *exception)
1332 {
1333 const char
1334 *artifact;
1335
1336 ImageInfo
1337 *image_info;
1338
1339 MagickBooleanType
1340 status;
1341
1342 QuantizeInfo
1343 *quantize_info;
1344
1345 assert(image != (Image *) NULL);
1346 if (image->debug != MagickFalse)
1347 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1348 assert(image->signature == MagickCoreSignature);
1349 status=MagickTrue;
1350 image_info=AcquireImageInfo();
1351 image_info->dither=image->dither;
1352 artifact=GetImageArtifact(image,"dither");
1353 if (artifact != (const char *) NULL)
1354 (void) SetImageOption(image_info,"dither",artifact);
1355 switch (type)
1356 {
1357 case BilevelType:
1358 {
1359 status=TransformImageColorspace(image,GRAYColorspace,exception);
1360 (void) NormalizeImage(image,exception);
1361 quantize_info=AcquireQuantizeInfo(image_info);
1362 quantize_info->number_colors=2;
1363 quantize_info->colorspace=GRAYColorspace;
1364 status=QuantizeImage(quantize_info,image,exception);
1365 quantize_info=DestroyQuantizeInfo(quantize_info);
1366 image->alpha_trait=UndefinedPixelTrait;
1367 break;
1368 }
1369 case GrayscaleType:
1370 {
1371 status=TransformImageColorspace(image,GRAYColorspace,exception);
1372 image->alpha_trait=UndefinedPixelTrait;
1373 break;
1374 }
1375 case GrayscaleAlphaType:
1376 {
1377 status=TransformImageColorspace(image,GRAYColorspace,exception);
1378 if (image->alpha_trait == UndefinedPixelTrait)
1379 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1380 break;
1381 }
1382 case PaletteType:
1383 {
1384 status=TransformImageColorspace(image,sRGBColorspace,exception);
1385 if ((image->storage_class == DirectClass) || (image->colors > 256))
1386 {
1387 quantize_info=AcquireQuantizeInfo(image_info);
1388 quantize_info->number_colors=256;
1389 status=QuantizeImage(quantize_info,image,exception);
1390 quantize_info=DestroyQuantizeInfo(quantize_info);
1391 }
1392 image->alpha_trait=UndefinedPixelTrait;
1393 break;
1394 }
1395 case PaletteBilevelAlphaType:
1396 {
1397 ChannelType
1398 channel_mask;
1399
1400 status=TransformImageColorspace(image,sRGBColorspace,exception);
1401 if (image->alpha_trait == UndefinedPixelTrait)
1402 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1403 channel_mask=SetImageChannelMask(image,AlphaChannel);
1404 (void) BilevelImage(image,(double) QuantumRange/2.0,exception);
1405 (void) SetImageChannelMask(image,channel_mask);
1406 quantize_info=AcquireQuantizeInfo(image_info);
1407 status=QuantizeImage(quantize_info,image,exception);
1408 quantize_info=DestroyQuantizeInfo(quantize_info);
1409 break;
1410 }
1411 case PaletteAlphaType:
1412 {
1413 status=TransformImageColorspace(image,sRGBColorspace,exception);
1414 if (image->alpha_trait == UndefinedPixelTrait)
1415 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1416 quantize_info=AcquireQuantizeInfo(image_info);
1417 quantize_info->colorspace=TransparentColorspace;
1418 status=QuantizeImage(quantize_info,image,exception);
1419 quantize_info=DestroyQuantizeInfo(quantize_info);
1420 break;
1421 }
1422 case TrueColorType:
1423 {
1424 status=TransformImageColorspace(image,sRGBColorspace,exception);
1425 if (image->storage_class != DirectClass)
1426 status=SetImageStorageClass(image,DirectClass,exception);
1427 image->alpha_trait=UndefinedPixelTrait;
1428 break;
1429 }
1430 case TrueColorAlphaType:
1431 {
1432 status=TransformImageColorspace(image,sRGBColorspace,exception);
1433 if (image->storage_class != DirectClass)
1434 status=SetImageStorageClass(image,DirectClass,exception);
1435 if (image->alpha_trait == UndefinedPixelTrait)
1436 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1437 break;
1438 }
1439 case ColorSeparationType:
1440 {
1441 status=TransformImageColorspace(image,CMYKColorspace,exception);
1442 if (image->storage_class != DirectClass)
1443 status=SetImageStorageClass(image,DirectClass,exception);
1444 image->alpha_trait=UndefinedPixelTrait;
1445 break;
1446 }
1447 case ColorSeparationAlphaType:
1448 {
1449 status=TransformImageColorspace(image,CMYKColorspace,exception);
1450 if (image->storage_class != DirectClass)
1451 status=SetImageStorageClass(image,DirectClass,exception);
1452 if (image->alpha_trait == UndefinedPixelTrait)
1453 status=SetImageAlphaChannel(image,OpaqueAlphaChannel,exception);
1454 break;
1455 }
1456 case OptimizeType:
1457 case UndefinedType:
1458 break;
1459 }
1460 image_info=DestroyImageInfo(image_info);
1461 if (status == MagickFalse)
1462 return(status);
1463 image->type=type;
1464 return(MagickTrue);
1465 }
1466