% July 1992 %
% %
% %
-% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
#include "magick/quantize.h"
#include "magick/quantum.h"
#include "magick/string_.h"
+#include "magick/thread-private.h"
\f
/*
Define declarations.
*/
+#if !defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
#define CacheShift 2
+#else
+#define CacheShift 3
+#endif
#define ErrorQueueLength 16
#define MaxNodes 266817
#define MaxTreeDepth 8
QuantizeInfo
*quantize_info;
- quantize_info=(QuantizeInfo *) AcquireAlignedMemory(1,sizeof(*quantize_info));
+ quantize_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*quantize_info));
if (quantize_info == (QuantizeInfo *) NULL)
ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
GetQuantizeInfo(quantize_info);
ssize_t
y;
- MagickBooleanType
- proceed;
-
- RealPixelPacket
- pixel;
-
- register ssize_t
- i,
- x;
-
- register const NodeInfo
- *node_info;
-
- ssize_t
- count;
-
- size_t
- id,
- index;
-
/*
Allocate image colormap.
*/
(void) DitherImage(image,cube_info);
else
{
+ CacheView
+ *image_view;
+
ExceptionInfo
*exception;
- CacheView
- *image_view;
+ MagickBooleanType
+ status;
+ status=MagickTrue;
exception=(&image->exception);
image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(dynamic,4) shared(status)
+#endif
for (y=0; y < (ssize_t) image->rows; y++)
{
+ CubeInfo
+ cube;
+
register IndexPacket
*restrict indexes;
register PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
+ ssize_t
+ count;
+
+ if (status == MagickFalse)
+ continue;
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
exception);
if (q == (PixelPacket *) NULL)
- break;
+ {
+ status=MagickFalse;
+ continue;
+ }
indexes=GetCacheViewAuthenticIndexQueue(image_view);
+ cube=(*cube_info);
for (x=0; x < (ssize_t) image->columns; x+=count)
{
+ RealPixelPacket
+ pixel;
+
+ register const NodeInfo
+ *node_info;
+
+ register ssize_t
+ i;
+
+ size_t
+ id,
+ index;
+
/*
Identify the deepest node containing the pixel's color.
*/
for (count=1; (x+count) < (ssize_t) image->columns; count++)
if (IsSameColor(image,q,q+count) == MagickFalse)
break;
- AssociateAlphaPixel(cube_info,q,&pixel);
- node_info=cube_info->root;
+ AssociateAlphaPixel(&cube,q,&pixel);
+ node_info=cube.root;
for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
{
- id=ColorToNodeId(cube_info,&pixel,index);
+ id=ColorToNodeId(&cube,&pixel,index);
if (node_info->child[id] == (NodeInfo *) NULL)
break;
node_info=node_info->child[id];
/*
Find closest color among siblings and their children.
*/
- cube_info->target=pixel;
- cube_info->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*
+ cube.target=pixel;
+ cube.distance=(MagickRealType) (4.0*(QuantumRange+1.0)*
(QuantumRange+1.0)+1.0);
- ClosestColor(image,cube_info,node_info->parent);
- index=cube_info->color_number;
+ ClosestColor(image,&cube,node_info->parent);
+ index=cube.color_number;
for (i=0; i < (ssize_t) count; i++)
{
if (image->storage_class == PseudoClass)
indexes[x+i]=(IndexPacket) index;
- if (cube_info->quantize_info->measure_error == MagickFalse)
+ if (cube.quantize_info->measure_error == MagickFalse)
{
q->red=image->colormap[index].red;
q->green=image->colormap[index].green;
q->blue=image->colormap[index].blue;
- if (cube_info->associate_alpha != MagickFalse)
+ if (cube.associate_alpha != MagickFalse)
q->opacity=image->colormap[index].opacity;
}
q++;
}
}
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
- break;
- proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) y,
- image->rows);
- if (proceed == MagickFalse)
- break;
+ status=MagickFalse;
+ if (image->progress_monitor != (MagickProgressMonitor) NULL)
+ {
+ MagickBooleanType
+ proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp critical (MagickCore_AssignImageColors)
+#endif
+ proceed=SetImageProgress(image,AssignImageTag,(MagickOffsetType) y,
+ image->rows);
+ if (proceed == MagickFalse)
+ status=MagickFalse;
+ }
}
image_view=DestroyCacheView(image_view);
}
register PixelPacket
*restrict q;
+ register ssize_t
+ i;
+
/*
Monochrome image.
*/
CacheView
*image_view;
- ssize_t
- y;
-
MagickBooleanType
proceed;
pixel;
size_t
- count;
-
- size_t
+ count,
id,
index,
level;
+ ssize_t
+ y;
+
/*
Classify the first cube_info->maximum_colors colors to a tree depth of 8.
*/
/*
Start at the root and descend the color cube tree.
*/
- for (count=1; (x+count) < image->columns; count++)
+ for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
if (IsSameColor(image,p,p+count) == MagickFalse)
break;
AssociateAlphaPixel(cube_info,p,&pixel);
/*
Start at the root and descend the color cube tree.
*/
- for (count=1; (x+count) < image->columns; count++)
+ for (count=1; (x+(ssize_t) count) < (ssize_t) image->columns; count++)
if (IsSameColor(image,p,p+count) == MagickFalse)
break;
AssociateAlphaPixel(cube_info,p,&pixel);
if (cube_info->associate_alpha != MagickFalse)
error.opacity=QuantumScale*(pixel.opacity-mid.opacity);
node_info->quantize_error+=sqrt((double) (count*error.red*error.red+
- count*error.green*error.green+error.blue*error.blue+
+ count*error.green*error.green+count*error.blue*error.blue+
count*error.opacity*error.opacity));
cube_info->root->quantize_error+=node_info->quantize_error;
index--;
QuantizeInfo
*clone_info;
- clone_info=(QuantizeInfo *) AcquireAlignedMemory(1,sizeof(*clone_info));
+ clone_info=(QuantizeInfo *) AcquireMagickMemory(sizeof(*clone_info));
if (clone_info == (QuantizeInfo *) NULL)
ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
GetQuantizeInfo(clone_info);
q=(&cube_info->target);
alpha=1.0;
beta=1.0;
- if (cube_info->associate_alpha == MagickFalse)
+ if (cube_info->associate_alpha != MagickFalse)
{
alpha=(MagickRealType) (QuantumScale*GetAlphaPixelComponent(p));
beta=(MagickRealType) (QuantumScale*GetAlphaPixelComponent(q));
}
pixel=alpha*p->red-beta*q->red;
distance=pixel*pixel;
- if (distance < cube_info->distance)
+ if (distance <= cube_info->distance)
{
pixel=alpha*p->green-beta*q->green;
distance+=pixel*pixel;
- if (distance < cube_info->distance)
+ if (distance <= cube_info->distance)
{
pixel=alpha*p->blue-beta*q->blue;
distance+=pixel*pixel;
- if (distance < cube_info->distance)
+ if (distance <= cube_info->distance)
{
pixel=alpha-beta;
distance+=pixel*pixel;
- if (distance < cube_info->distance)
+ if (distance <= cube_info->distance)
{
cube_info->distance=distance;
cube_info->color_number=node_info->color_number;
%
*/
+static RealPixelPacket **DestroyPixelThreadSet(RealPixelPacket **pixels)
+{
+ register ssize_t
+ i;
+
+ assert(pixels != (RealPixelPacket **) NULL);
+ for (i=0; i < (ssize_t) GetOpenMPMaximumThreads(); i++)
+ if (pixels[i] != (RealPixelPacket *) NULL)
+ pixels[i]=(RealPixelPacket *) RelinquishMagickMemory(pixels[i]);
+ pixels=(RealPixelPacket **) RelinquishMagickMemory(pixels);
+ return(pixels);
+}
+
+static RealPixelPacket **AcquirePixelThreadSet(const size_t count)
+{
+ RealPixelPacket
+ **pixels;
+
+ register ssize_t
+ i;
+
+ size_t
+ number_threads;
+
+ number_threads=GetOpenMPMaximumThreads();
+ pixels=(RealPixelPacket **) AcquireQuantumMemory(number_threads,
+ sizeof(*pixels));
+ if (pixels == (RealPixelPacket **) NULL)
+ return((RealPixelPacket **) NULL);
+ (void) ResetMagickMemory(pixels,0,number_threads*sizeof(*pixels));
+ for (i=0; i < (ssize_t) number_threads; i++)
+ {
+ pixels[i]=(RealPixelPacket *) AcquireQuantumMemory(count,
+ 2*sizeof(**pixels));
+ if (pixels[i] == (RealPixelPacket *) NULL)
+ return(DestroyPixelThreadSet(pixels));
+ }
+ return(pixels);
+}
+
+static inline ssize_t CacheOffset(CubeInfo *cube_info,
+ const RealPixelPacket *pixel)
+{
+#define RedShift(pixel) (((pixel) >> CacheShift) << (0*(8-CacheShift)))
+#define GreenShift(pixel) (((pixel) >> CacheShift) << (1*(8-CacheShift)))
+#define BlueShift(pixel) (((pixel) >> CacheShift) << (2*(8-CacheShift)))
+#define AlphaShift(pixel) (((pixel) >> CacheShift) << (3*(8-CacheShift)))
+
+ ssize_t
+ offset;
+
+ offset=(ssize_t)
+ (RedShift(ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->red))) |
+ GreenShift(ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->green))) |
+ BlueShift(ScaleQuantumToChar(ClampToUnsignedQuantum(pixel->blue))));
+ if (cube_info->associate_alpha != MagickFalse)
+ offset|=AlphaShift(ScaleQuantumToChar(ClampToUnsignedQuantum(
+ pixel->opacity)));
+ return(offset);
+}
+
static MagickBooleanType FloydSteinbergDither(Image *image,CubeInfo *cube_info)
{
#define DitherImageTag "Dither/Image"
ExceptionInfo
*exception;
- ssize_t
- u,
- v,
- y;
-
MagickBooleanType
- proceed;
+ status;
RealPixelPacket
- color,
- *current,
- pixel,
- *previous,
- *scanlines;
-
- register CubeInfo
- *p;
+ **pixels;
- size_t
- index;
+ ssize_t
+ y;
/*
Distribute quantization error using Floyd-Steinberg.
*/
- scanlines=(RealPixelPacket *) AcquireQuantumMemory(image->columns,
- 2*sizeof(*scanlines));
- if (scanlines == (RealPixelPacket *) NULL)
+ pixels=AcquirePixelThreadSet(image->columns);
+ if (pixels == (RealPixelPacket **) NULL)
return(MagickFalse);
- p=cube_info;
exception=(&image->exception);
+ status=MagickTrue;
image_view=AcquireCacheView(image);
for (y=0; y < (ssize_t) image->rows; y++)
{
+ const int
+ id = GetOpenMPThreadId();
+
+ CubeInfo
+ cube;
+
+ RealPixelPacket
+ *current,
+ *previous;
+
register IndexPacket
*restrict indexes;
+ register PixelPacket
+ *restrict q;
+
register ssize_t
- i,
x;
- register PixelPacket
- *restrict q;
+ size_t
+ index;
+ ssize_t
+ v;
+
+ if (status == MagickFalse)
+ continue;
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
if (q == (PixelPacket *) NULL)
- return(MagickFalse);
+ {
+ status=MagickFalse;
+ break;
+ }
indexes=GetCacheViewAuthenticIndexQueue(image_view);
- current=scanlines+(y & 0x01)*image->columns;
- previous=scanlines+((y+1) & 0x01)*image->columns;
+ cube=(*cube_info);
+ current=pixels[id]+(y & 0x01)*image->columns;
+ previous=pixels[id]+((y+1) & 0x01)*image->columns;
v=(ssize_t) ((y & 0x01) ? -1 : 1);
for (x=0; x < (ssize_t) image->columns; x++)
{
+ RealPixelPacket
+ color,
+ pixel;
+
+ register ssize_t
+ i;
+
+ ssize_t
+ u;
+
u=(y & 0x01) ? (ssize_t) image->columns-1-x : x;
- AssociateAlphaPixel(cube_info,q+u,&pixel);
+ AssociateAlphaPixel(&cube,q+u,&pixel);
if (x > 0)
{
pixel.red+=7*current[u-v].red/16;
pixel.green+=7*current[u-v].green/16;
pixel.blue+=7*current[u-v].blue/16;
- if (cube_info->associate_alpha != MagickFalse)
+ if (cube.associate_alpha != MagickFalse)
pixel.opacity+=7*current[u-v].opacity/16;
}
if (y > 0)
pixel.red+=previous[u+v].red/16;
pixel.green+=previous[u+v].green/16;
pixel.blue+=previous[u+v].blue/16;
- if (cube_info->associate_alpha != MagickFalse)
+ if (cube.associate_alpha != MagickFalse)
pixel.opacity+=previous[u+v].opacity/16;
}
pixel.red+=5*previous[u].red/16;
pixel.green+=5*previous[u].green/16;
pixel.blue+=5*previous[u].blue/16;
- if (cube_info->associate_alpha != MagickFalse)
+ if (cube.associate_alpha != MagickFalse)
pixel.opacity+=5*previous[u].opacity/16;
if (x > 0)
{
pixel.red+=3*previous[u-v].red/16;
pixel.green+=3*previous[u-v].green/16;
pixel.blue+=3*previous[u-v].blue/16;
- if (cube_info->associate_alpha != MagickFalse)
+ if (cube.associate_alpha != MagickFalse)
pixel.opacity+=3*previous[u-v].opacity/16;
}
}
pixel.red=(MagickRealType) ClampToUnsignedQuantum(pixel.red);
pixel.green=(MagickRealType) ClampToUnsignedQuantum(pixel.green);
pixel.blue=(MagickRealType) ClampToUnsignedQuantum(pixel.blue);
- if (cube_info->associate_alpha != MagickFalse)
+ if (cube.associate_alpha != MagickFalse)
pixel.opacity=(MagickRealType) ClampToUnsignedQuantum(pixel.opacity);
- i=(ssize_t) ((ScaleQuantumToChar(ClampToUnsignedQuantum(pixel.red)) >> CacheShift) |
- (ScaleQuantumToChar(ClampToUnsignedQuantum(pixel.green)) >> CacheShift) << 6 |
- (ScaleQuantumToChar(ClampToUnsignedQuantum(pixel.blue)) >> CacheShift) << 12);
- if (cube_info->associate_alpha != MagickFalse)
- i|=((ScaleQuantumToChar(ClampToUnsignedQuantum(pixel.opacity)) >> CacheShift)
- << 18);
- if (p->cache[i] < 0)
+ i=CacheOffset(&cube,&pixel);
+ if (cube.cache[i] < 0)
{
register NodeInfo
*node_info;
/*
Identify the deepest node containing the pixel's color.
*/
- node_info=p->root;
+ node_info=cube.root;
for (index=MaxTreeDepth-1; (ssize_t) index > 0; index--)
{
- id=ColorToNodeId(cube_info,&pixel,index);
+ id=ColorToNodeId(&cube,&pixel,index);
if (node_info->child[id] == (NodeInfo *) NULL)
break;
node_info=node_info->child[id];
/*
Find closest color among siblings and their children.
*/
- p->target=pixel;
- p->distance=(MagickRealType) (4.0*(QuantumRange+1.0)*(QuantumRange+
+ cube.target=pixel;
+ cube.distance=(MagickRealType) (4.0*(QuantumRange+1.0)*(QuantumRange+
1.0)+1.0);
- ClosestColor(image,p,node_info->parent);
- p->cache[i]=(ssize_t) p->color_number;
+ ClosestColor(image,&cube,node_info->parent);
+ cube.cache[i]=(ssize_t) cube.color_number;
}
/*
Assign pixel to closest colormap entry.
*/
- index=(size_t) p->cache[i];
+ index=(size_t) cube.cache[i];
if (image->storage_class == PseudoClass)
indexes[u]=(IndexPacket) index;
- if (cube_info->quantize_info->measure_error == MagickFalse)
+ if (cube.quantize_info->measure_error == MagickFalse)
{
(q+u)->red=image->colormap[index].red;
(q+u)->green=image->colormap[index].green;
(q+u)->blue=image->colormap[index].blue;
- if (cube_info->associate_alpha != MagickFalse)
+ if (cube.associate_alpha != MagickFalse)
(q+u)->opacity=image->colormap[index].opacity;
}
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
- return(MagickFalse);
+ status=MagickFalse;
/*
Store the error.
*/
- AssociateAlphaPixel(cube_info,image->colormap+index,&color);
+ AssociateAlphaPixel(&cube,image->colormap+index,&color);
current[u].red=pixel.red-color.red;
current[u].green=pixel.green-color.green;
current[u].blue=pixel.blue-color.blue;
- if (cube_info->associate_alpha != MagickFalse)
+ if (cube.associate_alpha != MagickFalse)
current[u].opacity=pixel.opacity-color.opacity;
- proceed=SetImageProgress(image,DitherImageTag,p->offset,p->span);
- if (proceed == MagickFalse)
- return(MagickFalse);
- p->offset++;
+ if (image->progress_monitor != (MagickProgressMonitor) NULL)
+ {
+ MagickBooleanType
+ proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp critical (MagickCore_FloydSteinbergDither)
+#endif
+ proceed=SetImageProgress(image,DitherImageTag,(MagickOffsetType) y,
+ image->rows);
+ if (proceed == MagickFalse)
+ status=MagickFalse;
+ }
}
}
- scanlines=(RealPixelPacket *) RelinquishMagickMemory(scanlines);
image_view=DestroyCacheView(image_view);
+ pixels=DestroyPixelThreadSet(pixels);
return(MagickTrue);
}
register IndexPacket
*restrict indexes;
- register ssize_t
- i;
-
register PixelPacket
*restrict q;
+ register ssize_t
+ i;
+
/*
Distribute error.
*/
pixel.blue=(MagickRealType) ClampToUnsignedQuantum(pixel.blue);
if (cube_info->associate_alpha != MagickFalse)
pixel.opacity=(MagickRealType) ClampToUnsignedQuantum(pixel.opacity);
- i=(ssize_t) ((ScaleQuantumToChar(ClampToUnsignedQuantum(pixel.red)) >> CacheShift) |
- (ScaleQuantumToChar(ClampToUnsignedQuantum(pixel.green)) >> CacheShift) << 6 |
- (ScaleQuantumToChar(ClampToUnsignedQuantum(pixel.blue)) >> CacheShift) << 12);
- if (cube_info->associate_alpha != MagickFalse)
- i|=((ScaleQuantumToChar(ClampToUnsignedQuantum(pixel.opacity)) >> CacheShift)
- << 18);
+ i=CacheOffset(cube_info,&pixel);
if (p->cache[i] < 0)
{
register NodeInfo
break;
node_info=node_info->child[id];
}
+ node_info=node_info->parent;
/*
Find closest color among siblings and their children.
*/
size_t
depth;
- if (cube_info->quantize_info->dither_method == FloydSteinbergDitherMethod)
+ if (cube_info->quantize_info->dither_method != RiemersmaDitherMethod)
return(FloydSteinbergDither(image,cube_info));
/*
Distribute quantization error along a Hilbert curve.
sum,
weight;
- size_t
- length;
-
register ssize_t
i;
+ size_t
+ length;
+
/*
Initialize tree to describe color cube_info.
*/
- cube_info=(CubeInfo *) AcquireAlignedMemory(1,sizeof(*cube_info));
+ cube_info=(CubeInfo *) AcquireMagickMemory(sizeof(*cube_info));
if (cube_info == (CubeInfo *) NULL)
return((CubeInfo *) NULL);
(void) ResetMagickMemory(cube_info,0,sizeof(*cube_info));
/*
Allocate a new queue of nodes.
*/
- nodes=(Nodes *) AcquireAlignedMemory(1,sizeof(*nodes));
+ nodes=(Nodes *) AcquireMagickMemory(sizeof(*nodes));
if (nodes == (Nodes *) NULL)
return((NodeInfo *) NULL);
nodes->nodes=(NodeInfo *) AcquireQuantumMemory(NodesInAList,
IndexPacket
*indexes;
- ssize_t
- y;
-
MagickRealType
alpha,
area,
size_t
index;
+ ssize_t
+ y;
+
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
% %
% %
% %
-% P o s t e r i z e I m a g e %
+% P o s t e r i z e I m a g e C h a n n e l %
% %
% %
% %
%
% MagickBooleanType PosterizeImage(Image *image,const size_t levels,
% const MagickBooleanType dither)
+% MagickBooleanType PosterizeImageChannel(Image *image,
+% const ChannelType channel,const size_t levels,
+% const MagickBooleanType dither)
%
% A description of each parameter follows:
%
% o levels: Number of color levels allowed in each channel. Very low values
% (2, 3, or 4) have the most visible effect.
%
-% o dither: Set this integer value to something other than zero to
-% dither the mapped image.
+% o dither: Set this integer value to something other than zero to dither
+% the mapped image.
%
*/
-MagickExport MagickBooleanType PosterizeImage(Image *image,
- const size_t levels,const MagickBooleanType dither)
+
+static inline ssize_t MagickRound(MagickRealType x)
{
- CacheView
- *posterize_view;
+ /*
+ Round the fraction to nearest integer.
+ */
+ if (x >= 0.0)
+ return((ssize_t) (x+0.5));
+ return((ssize_t) (x-0.5));
+}
- ExceptionInfo
- *exception;
+MagickExport MagickBooleanType PosterizeImage(Image *image,const size_t levels,
+ const MagickBooleanType dither)
+{
+ MagickBooleanType
+ status;
- Image
- *posterize_image;
+ status=PosterizeImageChannel(image,DefaultChannels,levels,dither);
+ return(status);
+}
- IndexPacket
- *indexes;
+MagickExport MagickBooleanType PosterizeImageChannel(Image *image,
+ const ChannelType channel,const size_t levels,const MagickBooleanType dither)
+{
+#define PosterizeImageTag "Posterize/Image"
+#define PosterizePixel(pixel) (Quantum) (QuantumRange*(MagickRound( \
+ QuantumScale*pixel*(levels-1)))/MagickMax((ssize_t) levels-1,1))
- ssize_t
- j,
- k,
- l,
- length,
- n;
+ CacheView
+ *image_view;
+
+ ExceptionInfo
+ *exception;
MagickBooleanType
status;
+ MagickOffsetType
+ progress;
+
QuantizeInfo
*quantize_info;
register ssize_t
i;
- register PixelPacket
- *restrict q;
+ ssize_t
+ y;
- /*
- Posterize image.
- */
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
- posterize_image=AcquireImage((ImageInfo *) NULL);
- if (posterize_image == (Image *) NULL)
- return(MagickFalse);
- l=1;
- length=levels*levels*levels;
- while ((l*l*l) < (ssize_t) MagickMin((ssize_t) length,MaxColormapSize+1))
- l++;
- status=SetImageExtent(posterize_image,(size_t) (l*l*l),1);
- if (status == MagickFalse)
- {
- posterize_image=DestroyImage(posterize_image);
- return(MagickFalse);
- }
- status=AcquireImageColormap(posterize_image,levels*levels*levels);
- if (status == MagickFalse)
+ if (image->storage_class == PseudoClass)
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+ for (i=0; i < (ssize_t) image->colors; i++)
{
- posterize_image=DestroyImage(posterize_image);
- return(MagickFalse);
+ /*
+ Posterize colormap.
+ */
+ if ((channel & RedChannel) != 0)
+ image->colormap[i].red=PosterizePixel(image->colormap[i].red);
+ if ((channel & GreenChannel) != 0)
+ image->colormap[i].green=PosterizePixel(image->colormap[i].green);
+ if ((channel & BlueChannel) != 0)
+ image->colormap[i].blue=PosterizePixel(image->colormap[i].blue);
+ if ((channel & OpacityChannel) != 0)
+ image->colormap[i].opacity=PosterizePixel(image->colormap[i].opacity);
}
- posterize_view=AcquireCacheView(posterize_image);
+ /*
+ Posterize image.
+ */
+ status=MagickTrue;
+ progress=0;
exception=(&image->exception);
- q=QueueCacheViewAuthenticPixels(posterize_view,0,0,posterize_image->columns,1,
- exception);
- if (q == (PixelPacket *) NULL)
- {
- posterize_view=DestroyCacheView(posterize_view);
- posterize_image=DestroyImage(posterize_image);
- return(MagickFalse);
- }
- indexes=GetCacheViewAuthenticIndexQueue(posterize_view);
- n=0;
- for (i=0; i < l; i++)
- for (j=0; j < l; j++)
- for (k=0; k < l; k++)
+ image_view=AcquireCacheView(image);
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
+#endif
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ register IndexPacket
+ *restrict indexes;
+
+ register PixelPacket
+ *restrict q;
+
+ register ssize_t
+ x;
+
+ if (status == MagickFalse)
+ continue;
+ q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
+ if (q == (PixelPacket *) NULL)
{
- posterize_image->colormap[n].red=(Quantum) (QuantumRange*i/
- MagickMax(l-1L,1L));
- posterize_image->colormap[n].green=(Quantum)
- (QuantumRange*j/MagickMax(l-1L,1L));
- posterize_image->colormap[n].blue=(Quantum) (QuantumRange*k/
- MagickMax(l-1L,1L));
- posterize_image->colormap[n].opacity=OpaqueOpacity;
- *q++=posterize_image->colormap[n];
- indexes[n]=(IndexPacket) n;
- n++;
+ status=MagickFalse;
+ continue;
}
- if (SyncCacheViewAuthenticPixels(posterize_view,exception) == MagickFalse)
+ indexes=GetCacheViewAuthenticIndexQueue(image_view);
+ for (x=0; x < (ssize_t) image->columns; x++)
{
- posterize_view=DestroyCacheView(posterize_view);
- posterize_image=DestroyImage(posterize_image);
- return(MagickFalse);
+ if ((channel & RedChannel) != 0)
+ q->red=PosterizePixel(q->red);
+ if ((channel & GreenChannel) != 0)
+ q->green=PosterizePixel(q->green);
+ if ((channel & BlueChannel) != 0)
+ q->blue=PosterizePixel(q->blue);
+ if (((channel & OpacityChannel) != 0) &&
+ (image->matte == MagickTrue))
+ q->opacity=PosterizePixel(q->opacity);
+ if (((channel & IndexChannel) != 0) &&
+ (image->colorspace == CMYKColorspace))
+ indexes[x]=PosterizePixel(indexes[x]);
+ q++;
}
- posterize_view=DestroyCacheView(posterize_view);
+ if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
+ status=MagickFalse;
+ if (image->progress_monitor != (MagickProgressMonitor) NULL)
+ {
+ MagickBooleanType
+ proceed;
+
+#if defined(MAGICKCORE_OPENMP_SUPPORT)
+ #pragma omp critical (MagickCore_PosterizeImageChannel)
+#endif
+ proceed=SetImageProgress(image,PosterizeImageTag,progress++,
+ image->rows);
+ if (proceed == MagickFalse)
+ status=MagickFalse;
+ }
+ }
+ image_view=DestroyCacheView(image_view);
quantize_info=AcquireQuantizeInfo((ImageInfo *) NULL);
+ quantize_info->number_colors=(size_t) MagickMin((ssize_t) levels*levels*
+ levels,MaxColormapSize+1);
quantize_info->dither=dither;
- status=RemapImage(quantize_info,image,posterize_image);
+ quantize_info->tree_depth=MaxTreeDepth;
+ status=QuantizeImage(quantize_info,image);
quantize_info=DestroyQuantizeInfo(quantize_info);
- posterize_image=DestroyImage(posterize_image);
return(status);
}
\f
CacheView
*image_view;
- ssize_t
- y;
-
MagickBooleanType
status;
size_t
number_colors;
+ ssize_t
+ y;
+
status=MagickTrue;
number_colors=(size_t) (image->columns*image->rows);
if (AcquireImageColormap(image,number_colors) == MagickFalse)
static int IntensityCompare(const void *x,const void *y)
{
- ssize_t
- intensity;
-
PixelPacket
*color_1,
*color_2;
+ ssize_t
+ intensity;
+
color_1=(PixelPacket *) x;
color_2=(PixelPacket *) y;
intensity=PixelIntensityToQuantum(color_1)-(ssize_t)
ExceptionInfo
*exception;
- ssize_t
- j,
- y;
+ MagickBooleanType
+ status;
PixelPacket
*colormap;
- ssize_t
- *colormap_index;
-
register ssize_t
i;
- MagickBooleanType
- status;
+ ssize_t
+ *colormap_index,
+ j,
+ y;
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
register IndexPacket
*restrict indexes;
- register ssize_t
- x;
-
register const PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
register IndexPacket
*restrict indexes;
- register ssize_t
- x;
-
register const PixelPacket
*restrict q;
+ register ssize_t
+ x;
+
if (status == MagickFalse)
continue;
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);