forked from openkylin/imagemagick
382 lines
13 KiB
C
382 lines
13 KiB
C
![]() |
/*
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
% %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% CCCC OOO L OOO RRRR M M AAA PPPP %
|
|||
|
% C O O L O O R R MM MM A A P P %
|
|||
|
% C O O L O O RRRR M M M AAAAA PPPP %
|
|||
|
% C O O L O O R R M M A A P %
|
|||
|
% CCCC OOO LLLLL OOO R R M M A A P %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% MagickCore Colormap Methods %
|
|||
|
% %
|
|||
|
% Software Design %
|
|||
|
% Cristy %
|
|||
|
% July 1992 %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% Copyright 1999-2021 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 %
|
|||
|
% obtain a copy of the License at %
|
|||
|
% %
|
|||
|
% https://imagemagick.org/script/license.php %
|
|||
|
% %
|
|||
|
% Unless required by applicable law or agreed to in writing, software %
|
|||
|
% distributed under the License is distributed on an "AS IS" BASIS, %
|
|||
|
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
|
|||
|
% See the License for the specific language governing permissions and %
|
|||
|
% limitations under the License. %
|
|||
|
% %
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
%
|
|||
|
% We use linked-lists because splay-trees do not currently support duplicate
|
|||
|
% key / value pairs (.e.g X11 green compliance and SVG green compliance).
|
|||
|
%
|
|||
|
*/
|
|||
|
|
|||
|
/*
|
|||
|
Include declarations.
|
|||
|
*/
|
|||
|
#include "magick/studio.h"
|
|||
|
#include "magick/attribute.h"
|
|||
|
#include "magick/blob.h"
|
|||
|
#include "magick/cache-view.h"
|
|||
|
#include "magick/cache.h"
|
|||
|
#include "magick/color.h"
|
|||
|
#include "magick/color-private.h"
|
|||
|
#include "magick/colormap.h"
|
|||
|
#include "magick/colormap-private.h"
|
|||
|
#include "magick/client.h"
|
|||
|
#include "magick/configure.h"
|
|||
|
#include "magick/exception.h"
|
|||
|
#include "magick/exception-private.h"
|
|||
|
#include "magick/gem.h"
|
|||
|
#include "magick/geometry.h"
|
|||
|
#include "magick/image-private.h"
|
|||
|
#include "magick/memory_.h"
|
|||
|
#include "magick/monitor.h"
|
|||
|
#include "magick/monitor-private.h"
|
|||
|
#include "magick/option.h"
|
|||
|
#include "magick/pixel-accessor.h"
|
|||
|
#include "magick/pixel-private.h"
|
|||
|
#include "magick/quantize.h"
|
|||
|
#include "magick/quantum.h"
|
|||
|
#include "magick/semaphore.h"
|
|||
|
#include "magick/resource_.h"
|
|||
|
#include "magick/string_.h"
|
|||
|
#include "magick/thread-private.h"
|
|||
|
#include "magick/token.h"
|
|||
|
#include "magick/utility.h"
|
|||
|
#include "magick/xml-tree.h"
|
|||
|
|
|||
|
/*
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
% %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% A c q u i r e I m a g e C o l o r m a p %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% %
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
%
|
|||
|
% AcquireImageColormap() allocates an image colormap and initializes
|
|||
|
% it to a linear gray colorspace. If the image already has a colormap,
|
|||
|
% it is replaced. AcquireImageColormap() returns MagickTrue if successful,
|
|||
|
% otherwise MagickFalse if there is not enough memory.
|
|||
|
%
|
|||
|
% The format of the AcquireImageColormap method is:
|
|||
|
%
|
|||
|
% MagickBooleanType AcquireImageColormap(Image *image,const size_t colors)
|
|||
|
%
|
|||
|
% A description of each parameter follows:
|
|||
|
%
|
|||
|
% o image: the image.
|
|||
|
%
|
|||
|
% o colors: the number of colors in the image colormap.
|
|||
|
%
|
|||
|
*/
|
|||
|
MagickExport MagickBooleanType AcquireImageColormap(Image *image,
|
|||
|
const size_t colors)
|
|||
|
{
|
|||
|
ssize_t
|
|||
|
i;
|
|||
|
|
|||
|
/*
|
|||
|
Allocate image colormap.
|
|||
|
*/
|
|||
|
assert(image != (Image *) NULL);
|
|||
|
assert(image->signature == MagickCoreSignature);
|
|||
|
if (image->debug != MagickFalse)
|
|||
|
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
|
|||
|
if (colors > MaxColormapSize)
|
|||
|
{
|
|||
|
image->colors=0;
|
|||
|
image->storage_class=DirectClass;
|
|||
|
ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
|
|||
|
image->filename);
|
|||
|
}
|
|||
|
image->colors=MagickMax(colors,1);
|
|||
|
if (image->colormap == (PixelPacket *) NULL)
|
|||
|
image->colormap=(PixelPacket *) AcquireQuantumMemory(image->colors+256,
|
|||
|
sizeof(*image->colormap));
|
|||
|
else
|
|||
|
image->colormap=(PixelPacket *) ResizeQuantumMemory(image->colormap,
|
|||
|
image->colors+256,sizeof(*image->colormap));
|
|||
|
if (image->colormap == (PixelPacket *) NULL)
|
|||
|
{
|
|||
|
image->colors=0;
|
|||
|
image->storage_class=DirectClass;
|
|||
|
ThrowBinaryImageException(ResourceLimitError,"MemoryAllocationFailed",
|
|||
|
image->filename);
|
|||
|
}
|
|||
|
for (i=0; i < (ssize_t) image->colors; i++)
|
|||
|
{
|
|||
|
size_t
|
|||
|
pixel;
|
|||
|
|
|||
|
pixel=(size_t) (i*(QuantumRange/MagickMax(colors-1,1)));
|
|||
|
image->colormap[i].red=(Quantum) pixel;
|
|||
|
image->colormap[i].green=(Quantum) pixel;
|
|||
|
image->colormap[i].blue=(Quantum) pixel;
|
|||
|
image->colormap[i].opacity=OpaqueOpacity;
|
|||
|
}
|
|||
|
return(SetImageStorageClass(image,PseudoClass));
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
% %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% C y c l e C o l o r m a p I m a g e %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% %
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
%
|
|||
|
% CycleColormap() displaces an image's colormap by a given number of
|
|||
|
% positions. If you cycle the colormap a number of times you can produce
|
|||
|
% a psychodelic effect.
|
|||
|
%
|
|||
|
% The format of the CycleColormapImage method is:
|
|||
|
%
|
|||
|
% MagickBooleanType CycleColormapImage(Image *image,const ssize_t displace)
|
|||
|
%
|
|||
|
% A description of each parameter follows:
|
|||
|
%
|
|||
|
% o image: the image.
|
|||
|
%
|
|||
|
% o displace: displace the colormap this amount.
|
|||
|
%
|
|||
|
*/
|
|||
|
MagickExport MagickBooleanType CycleColormapImage(Image *image,
|
|||
|
const ssize_t displace)
|
|||
|
{
|
|||
|
CacheView
|
|||
|
*image_view;
|
|||
|
|
|||
|
ExceptionInfo
|
|||
|
*exception;
|
|||
|
|
|||
|
MagickBooleanType
|
|||
|
status;
|
|||
|
|
|||
|
ssize_t
|
|||
|
y;
|
|||
|
|
|||
|
assert(image != (Image *) NULL);
|
|||
|
assert(image->signature == MagickCoreSignature);
|
|||
|
if (image->debug != MagickFalse)
|
|||
|
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
|
|||
|
if (image->storage_class == DirectClass)
|
|||
|
(void) SetImageType(image,PaletteType);
|
|||
|
status=MagickTrue;
|
|||
|
exception=(&image->exception);
|
|||
|
image_view=AcquireAuthenticCacheView(image,exception);
|
|||
|
#if defined(MAGICKCORE_OPENMP_SUPPORT)
|
|||
|
#pragma omp parallel for schedule(static) shared(status) \
|
|||
|
magick_number_threads(image,image,image->rows,1)
|
|||
|
#endif
|
|||
|
for (y=0; y < (ssize_t) image->rows; y++)
|
|||
|
{
|
|||
|
IndexPacket
|
|||
|
*magick_restrict indexes;
|
|||
|
|
|||
|
ssize_t
|
|||
|
x;
|
|||
|
|
|||
|
PixelPacket
|
|||
|
*magick_restrict q;
|
|||
|
|
|||
|
ssize_t
|
|||
|
index;
|
|||
|
|
|||
|
if (status == MagickFalse)
|
|||
|
continue;
|
|||
|
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
|
|||
|
if (q == (PixelPacket *) NULL)
|
|||
|
{
|
|||
|
status=MagickFalse;
|
|||
|
continue;
|
|||
|
}
|
|||
|
indexes=GetCacheViewAuthenticIndexQueue(image_view);
|
|||
|
for (x=0; x < (ssize_t) image->columns; x++)
|
|||
|
{
|
|||
|
index=(ssize_t) (GetPixelIndex(indexes+x)+displace) %
|
|||
|
image->colors;
|
|||
|
if (index < 0)
|
|||
|
index+=(ssize_t) image->colors;
|
|||
|
SetPixelIndex(indexes+x,index);
|
|||
|
SetPixelRGBO(q,image->colormap+(ssize_t) index);
|
|||
|
q++;
|
|||
|
}
|
|||
|
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
|||
|
status=MagickFalse;
|
|||
|
}
|
|||
|
image_view=DestroyCacheView(image_view);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
% %
|
|||
|
% %
|
|||
|
% %
|
|||
|
+ S o r t C o l o r m a p B y I n t e n s i t y %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% %
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
%
|
|||
|
% SortColormapByIntensity() sorts the colormap of a PseudoClass image by
|
|||
|
% decreasing color intensity.
|
|||
|
%
|
|||
|
% The format of the SortColormapByIntensity method is:
|
|||
|
%
|
|||
|
% MagickBooleanType SortColormapByIntensity(Image *image)
|
|||
|
%
|
|||
|
% A description of each parameter follows:
|
|||
|
%
|
|||
|
% o image: A pointer to an Image structure.
|
|||
|
%
|
|||
|
*/
|
|||
|
|
|||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|||
|
extern "C" {
|
|||
|
#endif
|
|||
|
|
|||
|
static int IntensityCompare(const void *x,const void *y)
|
|||
|
{
|
|||
|
const PixelPacket
|
|||
|
*color_1,
|
|||
|
*color_2;
|
|||
|
|
|||
|
int
|
|||
|
intensity;
|
|||
|
|
|||
|
color_1=(const PixelPacket *) x;
|
|||
|
color_2=(const PixelPacket *) y;
|
|||
|
intensity=PixelPacketIntensity(color_2)-(int) PixelPacketIntensity(color_1);
|
|||
|
return(intensity);
|
|||
|
}
|
|||
|
|
|||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
MagickExport MagickBooleanType SortColormapByIntensity(Image *image)
|
|||
|
{
|
|||
|
CacheView
|
|||
|
*image_view;
|
|||
|
|
|||
|
ExceptionInfo
|
|||
|
*exception;
|
|||
|
|
|||
|
MagickBooleanType
|
|||
|
status;
|
|||
|
|
|||
|
ssize_t
|
|||
|
i;
|
|||
|
|
|||
|
ssize_t
|
|||
|
y;
|
|||
|
|
|||
|
unsigned short
|
|||
|
*pixels;
|
|||
|
|
|||
|
assert(image != (Image *) NULL);
|
|||
|
if (image->debug != MagickFalse)
|
|||
|
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
|
|||
|
assert(image->signature == MagickCoreSignature);
|
|||
|
if (image->storage_class != PseudoClass)
|
|||
|
return(MagickTrue);
|
|||
|
exception=(&image->exception);
|
|||
|
/*
|
|||
|
Allocate memory for pixel indexes.
|
|||
|
*/
|
|||
|
pixels=(unsigned short *) AcquireQuantumMemory((size_t) image->colors,
|
|||
|
sizeof(*pixels));
|
|||
|
if (pixels == (unsigned short *) NULL)
|
|||
|
ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
|
|||
|
image->filename);
|
|||
|
/*
|
|||
|
Assign index values to colormap entries.
|
|||
|
*/
|
|||
|
for (i=0; i < (ssize_t) image->colors; i++)
|
|||
|
image->colormap[i].opacity=(IndexPacket) i;
|
|||
|
/*
|
|||
|
Sort image colormap by decreasing color popularity.
|
|||
|
*/
|
|||
|
qsort((void *) image->colormap,(size_t) image->colors,
|
|||
|
sizeof(*image->colormap),IntensityCompare);
|
|||
|
/*
|
|||
|
Update image colormap indexes to sorted colormap order.
|
|||
|
*/
|
|||
|
for (i=0; i < (ssize_t) image->colors; i++)
|
|||
|
pixels[(ssize_t) image->colormap[i].opacity]=(unsigned short) i;
|
|||
|
status=MagickTrue;
|
|||
|
image_view=AcquireAuthenticCacheView(image,exception);
|
|||
|
for (y=0; y < (ssize_t) image->rows; y++)
|
|||
|
{
|
|||
|
IndexPacket
|
|||
|
index;
|
|||
|
|
|||
|
ssize_t
|
|||
|
x;
|
|||
|
|
|||
|
IndexPacket
|
|||
|
*magick_restrict indexes;
|
|||
|
|
|||
|
PixelPacket
|
|||
|
*magick_restrict q;
|
|||
|
|
|||
|
q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
|
|||
|
if (q == (PixelPacket *) NULL)
|
|||
|
{
|
|||
|
status=MagickFalse;
|
|||
|
continue;
|
|||
|
}
|
|||
|
indexes=GetCacheViewAuthenticIndexQueue(image_view);
|
|||
|
for (x=0; x < (ssize_t) image->columns; x++)
|
|||
|
{
|
|||
|
i=ConstrainColormapIndex(image,GetPixelIndex(indexes+x));
|
|||
|
index=(IndexPacket) pixels[i];
|
|||
|
SetPixelIndex(indexes+x,index);
|
|||
|
SetPixelRGBO(q,image->colormap+(ssize_t) index);
|
|||
|
q++;
|
|||
|
}
|
|||
|
if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
|
|||
|
status=MagickFalse;
|
|||
|
if (status == MagickFalse)
|
|||
|
break;
|
|||
|
}
|
|||
|
image_view=DestroyCacheView(image_view);
|
|||
|
pixels=(unsigned short *) RelinquishMagickMemory(pixels);
|
|||
|
return(status);
|
|||
|
}
|