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