root/ImageMagick/trunk/magick/attribute.c

Revision 532, 31.2 KB (checked in by cristy, 3 weeks ago)
Line 
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%                                John Cristy                                  %
17%                                October 2002                                 %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2009 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%    http://www.imagemagick.org/script/license.php                            %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41  Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/attribute.h"
45#include "magick/blob.h"
46#include "magick/blob-private.h"
47#include "magick/cache.h"
48#include "magick/cache-view.h"
49#include "magick/client.h"
50#include "magick/color.h"
51#include "magick/color-private.h"
52#include "magick/colormap.h"
53#include "magick/colormap-private.h"
54#include "magick/colorspace.h"
55#include "magick/composite.h"
56#include "magick/composite-private.h"
57#include "magick/constitute.h"
58#include "magick/deprecate.h"
59#include "magick/draw.h"
60#include "magick/draw-private.h"
61#include "magick/effect.h"
62#include "magick/enhance.h"
63#include "magick/exception.h"
64#include "magick/exception-private.h"
65#include "magick/geometry.h"
66#include "magick/histogram.h"
67#include "magick/identify.h"
68#include "magick/image.h"
69#include "magick/image-private.h"
70#include "magick/list.h"
71#include "magick/log.h"
72#include "magick/memory_.h"
73#include "magick/magick.h"
74#include "magick/monitor.h"
75#include "magick/monitor-private.h"
76#include "magick/paint.h"
77#include "magick/pixel.h"
78#include "magick/pixel-private.h"
79#include "magick/property.h"
80#include "magick/quantize.h"
81#include "magick/random_.h"
82#include "magick/resource_.h"
83#include "magick/semaphore.h"
84#include "magick/segment.h"
85#include "magick/splay-tree.h"
86#include "magick/string_.h"
87#include "magick/thread-private.h"
88#include "magick/threshold.h"
89#include "magick/transform.h"
90#include "magick/utility.h"
91
92/*
93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94%                                                                             %
95%                                                                             %
96%                                                                             %
97+   G e t I m a g e B o u n d i n g B o x                                     %
98%                                                                             %
99%                                                                             %
100%                                                                             %
101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102%
103%  GetImageBoundingBox() returns the bounding box of an image canvas.
104%
105%  The format of the GetImageBoundingBox method is:
106%
107%      RectangleInfo GetImageBoundingBox(const Image *image,
108%        ExceptionInfo *exception)
109%
110%  A description of each parameter follows:
111%
112%    o bounds: Method GetImageBoundingBox returns the bounding box of an
113%      image canvas.
114%
115%    o image: the image.
116%
117%    o exception: return any errors or warnings in this structure.
118%
119*/
120MagickExport RectangleInfo GetImageBoundingBox(const Image *image,
121  ExceptionInfo *exception)
122{
123  long
124    y;
125
126  MagickBooleanType
127    status;
128
129  MagickPixelPacket
130    target[3],
131    zero;
132
133  RectangleInfo
134    bounds;
135
136  register const PixelPacket
137    *p;
138
139  CacheView
140    *image_view;
141
142  assert(image != (Image *) NULL);
143  assert(image->signature == MagickSignature);
144  if (image->debug != MagickFalse)
145    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
146  bounds.width=0;
147  bounds.height=0;
148  bounds.x=(long) image->columns;
149  bounds.y=(long) image->rows;
150  GetMagickPixelPacket(image,&target[0]);
151  image_view=AcquireCacheView(image);
152  p=GetCacheViewVirtualPixels(image_view,0,0,1,1,exception);
153  if (p == (const PixelPacket *) NULL)
154    {
155      image_view=DestroyCacheView(image_view);
156      return(bounds);
157    }
158  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
159    &target[0]);
160  GetMagickPixelPacket(image,&target[1]);
161  p=GetCacheViewVirtualPixels(image_view,(long) image->columns-1,0,1,1,
162    exception);
163  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
164    &target[1]);
165  GetMagickPixelPacket(image,&target[2]);
166  p=GetCacheViewVirtualPixels(image_view,0,(long) image->rows-1,1,1,exception);
167  SetMagickPixelPacket(image,p,GetCacheViewAuthenticIndexQueue(image_view),
168    &target[2]);
169  status=MagickTrue;
170  GetMagickPixelPacket(image,&zero);
171#if defined(MAGICKCORE_OPENMP_SUPPORT)
172  #pragma omp parallel for schedule(dynamic,4) shared(status)
173#endif
174  for (y=0; y < (long) image->rows; y++)
175  {
176    MagickPixelPacket
177      pixel;
178
179    RectangleInfo
180      bounding_box;
181
182    register const IndexPacket
183      *__restrict indexes;
184
185    register const PixelPacket
186      *__restrict p;
187
188    register long
189      x;
190
191    if (status == MagickFalse)
192      continue;
193#if defined(MAGICKCORE_OPENMP_SUPPORT)
194pragma omp critical (MagickCore_GetImageBoundingBox)
195#endif
196    bounding_box=bounds;
197    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
198    if (p == (const PixelPacket *) NULL)
199      {
200        status=MagickFalse;
201        continue;
202      }
203    indexes=GetCacheViewVirtualIndexQueue(image_view);
204    pixel=zero;
205    for (x=0; x < (long) image->columns; x++)
206    {
207      SetMagickPixelPacket(image,p,indexes+x,&pixel);
208      if ((x < bounding_box.x) &&
209          (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
210        bounding_box.x=x;
211      if ((x > (long) bounding_box.width) &&
212          (IsMagickColorSimilar(&pixel,&target[1]) == MagickFalse))
213        bounding_box.width=(unsigned long) x;
214      if ((y < bounding_box.y) &&
215          (IsMagickColorSimilar(&pixel,&target[0]) == MagickFalse))
216        bounding_box.y=y;
217      if ((y > (long) bounding_box.height) &&
218          (IsMagickColorSimilar(&pixel,&target[2]) == MagickFalse))
219        bounding_box.height=(unsigned long) y;
220      p++;
221    }
222#if defined(MAGICKCORE_OPENMP_SUPPORT)
223pragma omp critical (MagickCore_GetImageBoundingBox)
224#endif
225    {
226      if (bounding_box.x < bounds.x)
227        bounds.x=bounding_box.x;
228      if (bounding_box.y < bounds.y)
229        bounds.y=bounding_box.y;
230      if (bounding_box.width > bounds.width)
231        bounds.width=bounding_box.width;
232      if (bounding_box.height > bounds.height)
233        bounds.height=bounding_box.height;
234    }
235  }
236  image_view=DestroyCacheView(image_view);
237  if ((bounds.width == 0) || (bounds.height == 0))
238    (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning,
239      "GeometryDoesNotContainImage","`%s'",image->filename);
240  else
241    {
242      bounds.width-=(bounds.x-1);
243      bounds.height-=(bounds.y-1);
244    }
245  return(bounds);
246}
247
248/*
249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250%                                                                             %
251%                                                                             %
252%                                                                             %
253%   G e t I m a g e C h a n n e l D e p t h                                   %
254%                                                                             %
255%                                                                             %
256%                                                                             %
257%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258%
259%  GetImageChannelDepth() returns the depth of a particular image channel.
260%
261%  The format of the GetImageChannelDepth method is:
262%
263%      unsigned long GetImageDepth(const Image *image,ExceptionInfo *exception)
264%      unsigned long GetImageChannelDepth(const Image *image,
265%        const ChannelType channel,ExceptionInfo *exception)
266%
267%  A description of each parameter follows:
268%
269%    o image: the image.
270%
271%    o channel: the channel.
272%
273%    o exception: return any errors or warnings in this structure.
274%
275*/
276
277MagickExport unsigned long GetImageDepth(const Image *image,
278  ExceptionInfo *exception)
279{
280  return(GetImageChannelDepth(image,AllChannels,exception));
281}
282
283MagickExport unsigned long GetImageChannelDepth(const Image *image,
284  const ChannelType channel,ExceptionInfo *exception)
285{
286  long
287    y;
288
289  MagickBooleanType
290    status;
291
292  register long
293    id;
294
295  unsigned long
296    *current_depth,
297    depth,
298    number_threads;
299
300  CacheView
301    *image_view;
302
303  /*
304    Compute image depth.
305  */
306  assert(image != (Image *) NULL);
307  assert(image->signature == MagickSignature);
308  if (image->debug != MagickFalse)
309    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
310  number_threads=GetOpenMPMaximumThreads();
311  current_depth=(unsigned long *) AcquireQuantumMemory(number_threads,
312    sizeof(*current_depth));
313  if (current_depth == (unsigned long *) NULL)
314    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
315  status=MagickTrue;
316  for (id=0; id < (long) number_threads; id++)
317    current_depth[id]=1;
318  if ((image->storage_class == PseudoClass) && (image->matte == MagickFalse))
319    {
320      register const PixelPacket
321        *__restrict p;
322
323      register long
324        i;
325
326      p=image->colormap;
327#if defined(MAGICKCORE_OPENMP_SUPPORT)
328  #pragma omp parallel for schedule(dynamic,4) shared(status)
329#endif
330      for (i=0; i < (long) image->colors; i++)
331      {
332        if (status == MagickFalse)
333          continue;
334        id=GetOpenMPThreadId();
335        while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
336        {
337          MagickStatusType
338            status;
339
340          QuantumAny
341            range;
342
343          status=0;
344          range=GetQuantumRange(current_depth[id]);
345          if ((channel & RedChannel) != 0)
346            status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,
347              range),range);
348          if ((channel & GreenChannel) != 0)
349            status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
350              range),range);
351          if ((channel & BlueChannel) != 0)
352            status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,
353              range),range);
354          if (status == 0)
355            break;
356          current_depth[id]++;
357        }
358        p++;
359      }
360      depth=current_depth[0];
361      for (id=1; id < (long) number_threads; id++)
362        if (depth < current_depth[id])
363          depth=current_depth[id];
364      current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
365      return(depth);
366    }
367  image_view=AcquireCacheView(image);
368#if defined(MAGICKCORE_OPENMP_SUPPORT)
369  #pragma omp parallel for schedule(dynamic,4) shared(status)
370#endif
371  for (y=0; y < (long) image->rows; y++)
372  {
373    register const IndexPacket
374      *__restrict indexes;
375
376    register const PixelPacket
377      *__restrict p;
378
379    register long
380      id,
381      x;
382
383    if (status == MagickFalse)
384      continue;
385    id=GetOpenMPThreadId();
386    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
387    if (p == (const PixelPacket *) NULL)
388      continue;
389    indexes=GetCacheViewVirtualIndexQueue(image_view);
390    for (x=0; x < (long) image->columns; x++)
391    {
392      while (current_depth[id] < MAGICKCORE_QUANTUM_DEPTH)
393      {
394        MagickStatusType
395          status;
396
397        QuantumAny
398          range;
399
400        status=0;
401        range=GetQuantumRange(current_depth[id]);
402        if ((channel & RedChannel) != 0)
403          status|=p->red != ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),
404            range);
405        if ((channel & GreenChannel) != 0)
406          status|=p->green != ScaleAnyToQuantum(ScaleQuantumToAny(p->green,
407            range),range);
408        if ((channel & BlueChannel) != 0)
409          status|=p->blue != ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),
410            range);
411        if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
412          status|=p->opacity != ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,
413            range),range);
414        if (((channel & IndexChannel) != 0) &&
415            (image->colorspace == CMYKColorspace))
416          status|=indexes[x] != ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],
417            range),range);
418        if (status == 0)
419          break;
420        current_depth[id]++;
421      }
422      p++;
423    }
424    if (current_depth[id] == MAGICKCORE_QUANTUM_DEPTH)
425      status=MagickFalse;
426  }
427  image_view=DestroyCacheView(image_view);
428  depth=current_depth[0];
429  for (id=1; id < (long) number_threads; id++)
430    if (depth < current_depth[id])
431      depth=current_depth[id];
432  current_depth=(unsigned long *) RelinquishMagickMemory(current_depth);
433  return(depth);
434}
435
436/*
437%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438%                                                                             %
439%                                                                             %
440%                                                                             %
441%   G e t I m a g e Q u a n t u m D e p t h                                   %
442%                                                                             %
443%                                                                             %
444%                                                                             %
445%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446%
447%  GetImageQuantumDepth() returns the depth of the image rounded to a legal
448%  quantum depth: 8, 16, or 32.
449%
450%  The format of the GetImageQuantumDepth method is:
451%
452%      unsigned long GetImageQuantumDepth(const Image *image,
453%        const MagickBooleanType constrain)
454%
455%  A description of each parameter follows:
456%
457%    o image: the image.
458%
459%    o constrain: A value other than MagickFalse, constrains the depth to
460%      a maximum of MAGICKCORE_QUANTUM_DEPTH.
461%
462*/
463
464static inline double MagickMin(const double x,const double y)
465{
466  if (x < y)
467    return(x);
468  return(y);
469}
470
471MagickExport unsigned long GetImageQuantumDepth(const Image *image,
472  const MagickBooleanType constrain)
473{
474  unsigned long
475    depth;
476
477  depth=image->depth;
478  if (depth <= 8)
479    depth=8;
480  else
481    if (depth <= 16)
482      depth=16;
483    else
484      if (depth <= 32)
485        depth=32;
486      else
487        if (depth <= 64)
488          depth=64;
489  if (constrain != MagickFalse)
490    depth=(unsigned long) MagickMin((double) depth,(double)
491      MAGICKCORE_QUANTUM_DEPTH);
492  return(depth);
493}
494
495/*
496%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497%                                                                             %
498%                                                                             %
499%                                                                             %
500%   G e t I m a g e T y p e                                                   %
501%                                                                             %
502%                                                                             %
503%                                                                             %
504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
505%
506%  GetImageType() returns the potential type of image:
507%
508%        Bilevel         Grayscale        GrayscaleMatte
509%        Palette         PaletteMatte     TrueColor
510%        TrueColorMatte  ColorSeparation  ColorSeparationMatte
511%
512%  To ensure the image type matches its potential, use SetImageType():
513%
514%    (void) SetImageType(image,GetImageType(image));
515%
516%  The format of the GetImageType method is:
517%
518%      ImageType GetImageType(const Image *image,ExceptionInfo *exception)
519%
520%  A description of each parameter follows:
521%
522%    o image: the image.
523%
524%    o exception: return any errors or warnings in this structure.
525%
526*/
527MagickExport ImageType GetImageType(const Image *image,ExceptionInfo *exception)
528{
529  assert(image != (Image *) NULL);
530  assert(image->signature == MagickSignature);
531  if (image->debug != MagickFalse)
532    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
533  if (image->colorspace == CMYKColorspace)
534    {
535      if (image->matte == MagickFalse)
536        return(ColorSeparationType);
537      return(ColorSeparationMatteType);
538    }
539  if (IsMonochromeImage(image,exception) != MagickFalse)
540    return(BilevelType);
541  if (IsGrayImage(image,exception) != MagickFalse)
542    {
543      if (image->matte != MagickFalse)
544        return(GrayscaleMatteType);
545      return(GrayscaleType);
546    }
547  if (IsPaletteImage(image,exception) != MagickFalse)
548    {
549      if (image->matte != MagickFalse)
550        return(PaletteMatteType);
551      return(PaletteType);
552    }
553  if (image->matte != MagickFalse)
554    return(TrueColorMatteType);
555  return(TrueColorType);
556}
557
558/*
559%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560%                                                                             %
561%                                                                             %
562%                                                                             %
563%     I s G r a y I m a g e                                                   %
564%                                                                             %
565%                                                                             %
566%                                                                             %
567%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
568%
569%  IsGrayImage() returns MagickTrue if all the pixels in the image have the
570%  same red, green, and blue intensities.
571%
572%  The format of the IsGrayImage method is:
573%
574%      MagickBooleanType IsGrayImage(const Image *image,
575%        ExceptionInfo *exception)
576%
577%  A description of each parameter follows:
578%
579%    o image: the image.
580%
581%    o exception: return any errors or warnings in this structure.
582%
583*/
584MagickExport MagickBooleanType IsGrayImage(const Image *image,
585  ExceptionInfo *exception)
586{
587  ImageType
588    type;
589
590  register const PixelPacket
591    *p;
592
593  assert(image != (Image *) NULL);
594  assert(image->signature == MagickSignature);
595  if (image->debug != MagickFalse)
596    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
597  if ((image->type == BilevelType) || (image->type == GrayscaleType) ||
598      (image->type == GrayscaleMatteType))
599    return(MagickTrue);
600  if (image->colorspace == CMYKColorspace)
601    return(MagickFalse);
602  type=BilevelType;
603  switch (image->storage_class)
604  {
605    case DirectClass:
606    case UndefinedClass:
607    {
608      long
609        y;
610
611      register long
612        x;
613
614      CacheView
615        *image_view;
616
617      image_view=AcquireCacheView(image);
618      for (y=0; y < (long) image->rows; y++)
619      {
620        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
621        if (p == (const PixelPacket *) NULL)
622          break;
623        for (x=0; x < (long) image->columns; x++)
624        {
625          if (IsGrayPixel(p) == MagickFalse)
626            {
627              type=UndefinedType;
628              break;
629            }
630          if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
631            type=GrayscaleType;
632          p++;
633        }
634        if (type == UndefinedType)
635          break;
636      }
637      image_view=DestroyCacheView(image_view);
638      break;
639    }
640    case PseudoClass:
641    {
642      register long
643        i;
644
645      p=image->colormap;
646      for (i=0; i < (long) image->colors; i++)
647      {
648        if (IsGrayPixel(p) == MagickFalse)
649          {
650            type=UndefinedType;
651            break;
652          }
653        if ((type == BilevelType) && (IsMonochromePixel(p) == MagickFalse))
654          type=GrayscaleType;
655        p++;
656      }
657      break;
658    }
659  }
660  if (type == UndefinedType)
661    return(MagickFalse);
662  ((Image *) image)->type=type;
663  if ((type == GrayscaleType) && (image->matte != MagickFalse))
664    ((Image *) image)->type=GrayscaleMatteType;
665  return(MagickTrue);
666}
667
668/*
669%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670%                                                                             %
671%                                                                             %
672%                                                                             %
673%   I s M o n o c h r o m e I m a g e                                         %
674%                                                                             %
675%                                                                             %
676%                                                                             %
677%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678%
679%  IsMonochromeImage() returns MagickTrue if all the pixels in the image have
680%  the same red, green, and blue intensities and the intensity is either
681%  0 or QuantumRange.
682%
683%  The format of the IsMonochromeImage method is:
684%
685%      MagickBooleanType IsMonochromeImage(const Image *image,
686%        ExceptionInfo *exception)
687%
688%  A description of each parameter follows:
689%
690%    o image: the image.
691%
692%    o exception: return any errors or warnings in this structure.
693%
694*/
695MagickExport MagickBooleanType IsMonochromeImage(const Image *image,
696  ExceptionInfo *exception)
697{
698  ImageType
699    type;
700
701  register const PixelPacket
702    *p;
703
704  assert(image != (Image *) NULL);
705  assert(image->signature == MagickSignature);
706  if (image->debug != MagickFalse)
707    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
708  if (image->type == BilevelType)
709    return(MagickTrue);
710  if (image->colorspace == CMYKColorspace)
711    return(MagickFalse);
712  type=BilevelType;
713  switch (image->storage_class)
714  {
715    case DirectClass:
716    case UndefinedClass:
717    {
718      long
719        y;
720
721      register long
722        x;
723
724      CacheView
725        *image_view;
726
727      image_view=AcquireCacheView(image);
728      for (y=0; y < (long) image->rows; y++)
729      {
730        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
731        if (p == (const PixelPacket *) NULL)
732          break;
733        for (x=0; x < (long) image->columns; x++)
734        {
735          if (IsMonochromePixel(p) == MagickFalse)
736            {
737              type=UndefinedType;
738              break;
739            }
740          p++;
741        }
742        if (type == UndefinedType)
743          break;
744      }
745      image_view=DestroyCacheView(image_view);
746      if (y == (long) image->rows)
747        ((Image *) image)->type=BilevelType;
748      break;
749    }
750    case PseudoClass:
751    {
752      register long
753        i;
754
755      p=image->colormap;
756      for (i=0; i < (long) image->colors; i++)
757      {
758        if (IsMonochromePixel(p) == MagickFalse)
759          {
760            type=UndefinedType;
761            break;
762          }
763        p++;
764      }
765      break;
766    }
767  }
768  if (type == UndefinedType)
769    return(MagickFalse);
770  ((Image *) image)->type=type;
771  return(MagickTrue);
772}
773
774/*
775%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
776%                                                                             %
777%                                                                             %
778%                                                                             %
779%     I s O p a q u e I m a g e                                               %
780%                                                                             %
781%                                                                             %
782%                                                                             %
783%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
784%
785%  IsOpaqueImage() returns MagickTrue if none of the pixels in the image have
786%  an opacity value other than opaque (0).
787%
788%  The format of the IsOpaqueImage method is:
789%
790%      MagickBooleanType IsOpaqueImage(const Image *image,
791%        ExceptionInfo *exception)
792%
793%  A description of each parameter follows:
794%
795%    o image: the image.
796%
797%    o exception: return any errors or warnings in this structure.
798%
799*/
800MagickExport MagickBooleanType IsOpaqueImage(const Image *image,
801  ExceptionInfo *exception)
802{
803  long
804    y;
805
806  register const PixelPacket
807    *p;
808
809  register long
810    x;
811
812  CacheView
813    *image_view;
814
815  /*
816    Determine if image is opaque.
817  */
818  assert(image != (Image *) NULL);
819  assert(image->signature == MagickSignature);
820  if (image->debug != MagickFalse)
821    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
822  if (image->matte == MagickFalse)
823    return(MagickTrue);
824  image_view=AcquireCacheView(image);
825  for (y=0; y < (long) image->rows; y++)
826  {
827    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
828    if (p == (const PixelPacket *) NULL)
829      break;
830    for (x=0; x < (long) image->columns; x++)
831    {
832      if (p->opacity != OpaqueOpacity)
833        break;
834      p++;
835    }
836    if (x < (long) image->columns)
837     break;
838  }
839  image_view=DestroyCacheView(image_view);
840  return(y < (long) image->rows ? MagickFalse : MagickTrue);
841}
842
843/*
844%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
845%                                                                             %
846%                                                                             %
847%                                                                             %
848%   S e t I m a g e C h a n n e l D e p t h                                   %
849%                                                                             %
850%                                                                             %
851%                                                                             %
852%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
853%
854%  SetImageChannelDepth() sets the depth of the image.
855%
856%  The format of the SetImageChannelDepth method is:
857%
858%      MagickBooleanType SetImageDepth(Image *image,const unsigned long depth)
859%      MagickBooleanType SetImageChannelDepth(Image *image,
860%        const ChannelType channel,const unsigned long depth)
861%
862%  A description of each parameter follows:
863%
864%    o image: the image.
865%
866%    o channel: the channel.
867%
868%    o depth: the image depth.
869%
870*/
871
872MagickExport MagickBooleanType SetImageDepth(Image *image,
873  const unsigned long depth)
874{
875  return(SetImageChannelDepth(image,AllChannels,depth));
876}
877
878MagickExport MagickBooleanType SetImageChannelDepth(Image *image,
879  const ChannelType channel,const unsigned long depth)
880{
881  ExceptionInfo
882    *exception;
883
884  long
885    y;
886
887  MagickBooleanType
888    status;
889
890  QuantumAny
891    range;
892
893  CacheView
894    *image_view;
895
896  assert(image != (Image *) NULL);
897  if (image->debug != MagickFalse)
898    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
899  assert(image->signature == MagickSignature);
900  if (GetImageDepth(image,&image->exception) <= (unsigned long)
901      MagickMin((double) depth,(double) MAGICKCORE_QUANTUM_DEPTH))
902    {
903      image->depth=depth;
904      return(MagickTrue);
905    }
906  /*
907    Scale pixels to desired depth.
908  */
909  status=MagickTrue;
910  range=GetQuantumRange(depth);
911  exception=(&image->exception);
912  image_view=AcquireCacheView(image);
913#if defined(MAGICKCORE_OPENMP_SUPPORT)
914  #pragma omp parallel for schedule(dynamic,4) shared(status)
915#endif
916  for (y=0; y < (long) image->rows; y++)
917  {
918    register IndexPacket
919      *__restrict indexes;
920
921    register long
922      x;
923
924    register PixelPacket
925      *__restrict q;
926
927    if (status == MagickFalse)
928      continue;
929    q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
930      exception);
931    if (q == (PixelPacket *) NULL)
932      {
933        status=MagickFalse;
934        continue;
935      }
936    indexes=GetCacheViewAuthenticIndexQueue(image_view);
937    for (x=0; x < (long) image->columns; x++)
938    {
939      if ((channel & RedChannel) != 0)
940        q->red=ScaleAnyToQuantum(ScaleQuantumToAny(q->red,range),range);
941      if ((channel & GreenChannel) != 0)
942        q->green=ScaleAnyToQuantum(ScaleQuantumToAny(q->green,range),range);
943      if ((channel & BlueChannel) != 0)
944        q->blue=ScaleAnyToQuantum(ScaleQuantumToAny(q->blue,range),range);
945      if (((channel & OpacityChannel) != 0) && (image->matte != MagickFalse))
946        q->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(q->opacity,range),range);
947      if (((channel & IndexChannel) != 0) &&
948          (image->colorspace == CMYKColorspace))
949        indexes[x]=ScaleAnyToQuantum(ScaleQuantumToAny(indexes[x],range),range);
950      q++;
951    }
952    if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
953      {
954        status=MagickFalse;
955        continue;
956      }
957  }
958  image_view=DestroyCacheView(image_view);
959  if (image->storage_class == PseudoClass)
960    {
961      QuantumAny
962        range;
963
964      register long
965        i;
966
967      register PixelPacket
968        *__restrict p;
969
970      p=image->colormap;
971      range=GetQuantumRange(depth);
972#if defined(MAGICKCORE_OPENMP_SUPPORT)
973  #pragma omp parallel for schedule(dynamic,4) shared(status)
974#endif
975      for (i=0; i < (long) image->colors; i++)
976      {
977        if ((channel & RedChannel) != 0)
978          p->red=ScaleAnyToQuantum(ScaleQuantumToAny(p->red,range),range);
979        if ((channel & GreenChannel) != 0)
980          p->green=ScaleAnyToQuantum(ScaleQuantumToAny(p->green,range),range);
981        if ((channel & BlueChannel) != 0)
982          p->blue=ScaleAnyToQuantum(ScaleQuantumToAny(p->blue,range),range);
983        if ((channel & OpacityChannel) != 0)
984          p->opacity=ScaleAnyToQuantum(ScaleQuantumToAny(p->opacity,range),
985            range);
986        p++;
987      }
988    }
989  image->depth=depth;
990  return(status);
991}
Note: See TracBrowser for help on using the browser.