Commit 6c5f330bb for imagemagick.org
commit 6c5f330bbf93600fc4fadfd3bd98621b16567296
Author: Rafael Niebles <rniebles@proton.me>
Date: Sat Apr 11 15:13:10 2026 -0400
Support for 4-bit (indexed 16-color) PCX (#8655)
* setting plane count and bit depth
* setting image type to palette type to mirror setimagemonochrome's logic
* working version 1
* unit tests
* leave extra unit tests only
* improve code style
* rm magicktype header
* rm comment
* rm am makefile
* leave extra unit tests only
* put unit tests in right place!
* restore makefile.am from tests
* remove tests
* remove extra newlines to match style
* remove extra newlines to match style in if/elses
* remove palettetype setting
* use correct naming in if/else
* windows build fix
Co-authored-by: Dirk Lemstra <dirk@lemstra.org>
---------
Co-authored-by: Dirk Lemstra <dirk@lemstra.org>
diff --git a/coders/pcx.c b/coders/pcx.c
index 58384d383..7890e2355 100644
--- a/coders/pcx.c
+++ b/coders/pcx.c
@@ -941,9 +941,11 @@ static MagickBooleanType WritePCXImage(const ImageInfo *image_info,Image *image,
pcx_info.version=5;
pcx_info.encoding=image_info->compression == NoCompression ? 0 : 1;
pcx_info.bits_per_pixel=8;
- if ((image->storage_class == PseudoClass) &&
- (SetImageMonochrome(image,exception) != MagickFalse))
- pcx_info.bits_per_pixel=1;
+ if (image->storage_class == PseudoClass)
+ {
+ if (SetImageMonochrome(image,exception) != MagickFalse || image->colors <= 16)
+ pcx_info.bits_per_pixel=1;
+ }
else
if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
(void) TransformImageColorspace(image,sRGBColorspace,exception);
@@ -970,7 +972,11 @@ static MagickBooleanType WritePCXImage(const ImageInfo *image_info,Image *image,
}
pcx_info.reserved=0;
pcx_info.planes=1;
- if ((image->storage_class == DirectClass) || (image->colors > 256))
+ if ((image->storage_class == PseudoClass) &&
+ (image->colors <= 16) &&
+ (image->type != BilevelType))
+ pcx_info.planes=4;
+ else if ((image->storage_class == DirectClass) || (image->colors > 256))
{
pcx_info.planes=3;
if (image->alpha_trait != UndefinedPixelTrait)
@@ -1127,6 +1133,54 @@ static MagickBooleanType WritePCXImage(const ImageInfo *image_info,Image *image,
break;
}
}
+ else if (pcx_info.planes == 4)
+ {
+ const Quantum
+ *r;
+
+ unsigned char
+ bit,
+ byte;
+
+ for (y=0; y < (ssize_t) image->rows; y++)
+ {
+ p=GetVirtualPixels(image,0,y,image->columns,1,exception);
+ if (p == (const Quantum *) NULL)
+ break;
+ for (i=0; i < (ssize_t) pcx_info.planes; i++)
+ {
+ r=p;
+ byte=0;
+ bit=0;
+ q=pixels+(i*(ssize_t) pcx_info.bytes_per_line);
+ for (x=0; x < (ssize_t) image->columns; x++)
+ {
+ bit<<=1;
+ if (((ssize_t) GetPixelIndex(image,r) & ((ssize_t) 1 << i)) != 0)
+ bit|=0x01;
+ byte++;
+ if (byte == 8)
+ {
+ *q++=bit;
+ byte=0;
+ bit=0;
+ }
+ r+=(ptrdiff_t) GetPixelChannels(image);
+ }
+ if (byte != 0)
+ *q++=bit << (8-byte);
+ }
+ if (PCXWritePixels(&pcx_info,pixels,image) == MagickFalse)
+ break;
+ if (image->previous == (Image *) NULL)
+ {
+ status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
+ image->rows);
+ if (status == MagickFalse)
+ break;
+ }
+ }
+ }
else
{
unsigned char