问题
Background, I am converting images to ascii art. This works perfectly and even works with 24-bit color, converting the colors to the right rgb values. However, I now want to render the ascii art in 4-bit color palette rather than 24-bit.
How do I convert 24-bit colors to 4-bit with PHP?
More specifically, I have the standard IRC color pallet which I need to convert any given Hexidecimal or RGB value to. It is preferred that the colors match as best as possible when converted to the 4-bit color.
Other ideas I have had on this are to convert the image itself to a 4-bit palette (using GD, which is what I use to read in the colors right now) before trying to grab colors off of it. And another idea might be to define a color range for each of the following color and just check that the given 24-bit color is in the range, however I wouldn't know how to get the ranges for all colors into that palette.

回答1:
imagetruecolortopalette allows you to reduce the colours, but results can vary wildly and I don't know if there is a way of 'mapping' the colours correctly or specifying the palette.
Test image (24-bit):

Reduced to 4-bit (without dithering):
$img = imagecreatefrompng('Bliss.png');
imagetruecolortopalette($img, false, 16);
imagepng($img, 'Bliss2.png');

Reduced to 4-bit (with dithering):
$img = imagecreatefrompng('Bliss.png');
imagetruecolortopalette($img, true, 16);
imagepng($img, 'Bliss3.png');

As you can see, results are far from perfect. But perhaps this is a good start for you.
回答2:
I think ImageMagick (or GraphicsMagick) can do this with the -depth option. There's a discussion of it here: http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=15395
UPDATE: I should add that ImageMagick is not a PHP library, however there's a PECL wrapper (imagick) for it at http://pecl.php.net/package/imagick.
回答3:
I think you need to use remap
to map the colours in the image to the palette of colours in your swatch. I do it at the command line like this:
convert image.jpg -remap palette.jpg out.jpg
You may, or may not want the dither
option - check it out.
Original image is here:

palette.jpg
(you only need a really small image, this is way too big - I will address this shortly)

and the result

You can also create your palette according to the colours you want using ImageMagick. I hand-coded the following and didn't pay too much attention, so you would want to check the RGB values in here before assuming they are correct:
#/bin/bash
cat<<EOF | convert txt:- palette.png
# ImageMagick pixel enumeration: 8,2,256,rgb
0,0: (255,255,255)
1,0: (0,0,0)
2,0: (0,0,255)
3,0: (255,255,0)
4,0: (255,0,0)
5,0: (128,128,128)
6,0: (255,105,180)
7,0: (173,216,230)
0,1: (50,205,50)
1,1: (139,0,0)
2,1: (255,165,0)
3,1: (128,0,128)
4,1: (0,0,139)
5,1: (0,128,128)
6,1: (0,128,0)
7,1: (211,211,211)
EOF
Basically, the script above gives ImageMagick the RGB values as text and asks it to make small 8x2 image that looks like this:

Then you would use this palette with your remap
operation.
回答4:
In the end, despite the wonderful suggestions surrounding imagemagick I found a good solution using straight php. I was able to calculate the closest color through the use of delta E 2000 with a modified version of php-color-difference library found on github, here is my fork: https://github.com/nalipaz/php-color-difference
The pertinent example is:
<?php
include('lib/color_difference.class.php');
$palette = array(
'00' => array(255, 255, 255),
'01' => array(0, 0, 0),
'02' => array(0, 0, 139),
'03' => array(0, 128, 0),
'04' => array(255, 0, 0),
'05' => array(139, 0, 0),
'06' => array(128, 0, 128),
'07' => array(255, 165, 0),
'08' => array(255, 255, 0),
'09' => array(50, 205, 50),
'10' => array(0, 128, 128),
'11' => array(173, 216, 230),
'12' => array(0, 0, 255),
'13' => array(255, 105, 180),
'14' => array(128, 128, 128),
'15' => array(211, 211, 211),
);
$color_rgb = array(255, 255, 128);
$color_delta_e = new color_difference($color_rgb);
$match_index = $color_delta_e->getClosestMatch($palette);
$color = $palette[$match_index];
I am pretty happy with this solution and smaller amount of overhead. Thanks for the suggestions guys.
来源:https://stackoverflow.com/questions/26225594/php-convert-24-bit-colors-to-4-bit