使用Floyd-Steinberg抖动算法处理价签图片

Floyd-Steinberg抖动算法简直量身为价签这种低颜色呈现设备准备的。由于价签的墨水屏能够呈现的色彩非常有限,根据型号不同,有的只能显示黑白,有的只能显示黑白红,有的只能显示黑白黄,所以对于一张普通图片,需要将其转换为两色或者三色才能比较好地在价签上展示出来。

核心代码如下:

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}; }
}

原始图片:

黑白红价签的显示效果:

黑白价签的显示效果:

 

转载于:https://my.oschina.net/u/4042451/blog/3058233

  • 0
    点赞
  • 0
    评论
  • 6
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值