使用Floyd-Steinberg抖動算法處理價籤圖片

Floyd-Steinberg抖動算法簡直量身爲價籤這種低顏色呈現設備準備的。因爲價籤的墨水屏可以呈現的色彩很是有限,根據型號不一樣,有的只能顯示黑白,有的只能顯示黑白紅,有的只能顯示黑白黃,因此對於一張普通圖片,須要將其轉換爲兩色或者三色才能比較好地在價簽上展現出來。java

核心代碼以下:算法

public class BMPConverter {

    public static RGBTriple[] getPalette(int deviceType) {
        final RGBTriple[] palette;

        if (deviceType == 0) {
            //黑白價籤
            palette = new RGBTriple[]{
                    new RGBTriple(0, 0, 0),
                    new RGBTriple(255, 255, 255)
            };
        } else if (deviceType == 1) {
            //黑白紅價籤
            palette = new RGBTriple[]{
                    new RGBTriple(0, 0, 0),
                    new RGBTriple(255, 255, 255),
                    new RGBTriple(255, 0, 0)
            };

        } else {
            //黑白黃價籤
            palette = new RGBTriple[]{
                    new RGBTriple(0, 0, 0),
                    new RGBTriple(255, 255, 255),
                    new RGBTriple(255, 255, 0)
            };
        }
        return palette;
    }

    public static byte[][] floydSteinbergDither(RGBTriple[][] image, RGBTriple[] palette)
    {
        byte[][] result = new byte[image.length][image[0].length];


        for (int y = 0; y < image.length; y++) {
            for (int x = 0; x < image[y].length; x++) {
                RGBTriple currentPixel = image[y][x];
                byte index = findNearestColor(currentPixel, palette);
                result[y][x] = index;

                for (int i = 0; i < 3; i++)
                {
                    int error = (currentPixel.channels[i] & 0xff) - (palette[index].channels[i] & 0xff);
                    if (x + 1 < image[0].length) {
                        image[y+0][x+1].channels[i] =
                                plus_truncate_uchar(image[y+0][x+1].channels[i], (error*7) >> 4);
                    }
                    if (y + 1 < image.length) {
                        if (x - 1 > 0) {
                            image[y+1][x-1].channels[i] =
                                    plus_truncate_uchar(image[y+1][x-1].channels[i], (error*3) >> 4);
                        }
                        image[y+1][x+0].channels[i] =
                                plus_truncate_uchar(image[y+1][x+0].channels[i], (error*5) >> 4);
                        if (x + 1 < image[0].length) {
                            image[y+1][x+1].channels[i] =
                                    plus_truncate_uchar(image[y+1][x+1].channels[i], (error*1) >> 4);
                        }
                    }

                }

            }
        }

        return result;
    }

    private static byte plus_truncate_uchar(byte a, int b) {
        if ((a & 0xff) + b < 0) {
            return 0;
        } else if ((a & 0xff) + b > 255) {
            return (byte) 255;
        } else {
            return (byte) (a + b);
        }
    }


    private static byte findNearestColor(RGBTriple color, RGBTriple[] palette) {
        int minDistanceSquared = 255*255 + 255*255 + 255*255 + 1;
        byte bestIndex = 0;
        for (byte i = 0; i < palette.length; i++) {
            int Rdiff = (color.channels[0] & 0xff) - (palette[i].channels[0] & 0xff);
            int Gdiff = (color.channels[1] & 0xff) - (palette[i].channels[1] & 0xff);
            int Bdiff = (color.channels[2] & 0xff) - (palette[i].channels[2] & 0xff);
            int distanceSquared = Rdiff*Rdiff + Gdiff*Gdiff + Bdiff*Bdiff;
            if (distanceSquared < minDistanceSquared) {
                minDistanceSquared = distanceSquared;
                bestIndex = i;
            }
        }
        return bestIndex;
    }

}

public class  RGBTriple {
    public final byte[] channels;
    public RGBTriple() { channels = new byte[3]; }
    public RGBTriple(int R, int G, int B)
    { channels = new byte[]{(byte)R, (byte)G, (byte)B}; }
}

原始圖片:rest

黑白紅價籤的顯示效果:code

黑白價籤的顯示效果:blog

相關文章
相關標籤/搜索