加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 如何使用Floyd-Steinberg抖动将24位PNG转换为3位PNG?

发布时间:2020-12-14 17:44:42 所属栏目:Java 来源:网络整理
导读:如何使用 Floyd–Steinberg dithering将24位PNG转换为3位PNG?应该使用java.awt.image.BufferedImage来获取和设置RGB值. 在维基百科上,给出了如何将16位转换为8位图像的示例: find_closest_palette_color(oldpixel) = (oldpixel + 128) / 256 基于此,有没有
如何使用 Floyd–Steinberg dithering将24位PNG转换为3位PNG?应该使用java.awt.image.BufferedImage来获取和设置RGB值.

在维基百科上,给出了如何将16位转换为8位图像的示例:

find_closest_palette_color(oldpixel) = (oldpixel + 128) / 256

基于此,有没有想到如何适应上面的例子来实现目标?

解决方法

使用 image.getRGB(x,y)image.setRGB(x,y,color),并从 wikipedia article使用 pseudocode.请注意,维基上的代码不会说如何“减”,“添加”和“乘”颜色. (下面的T3类处理“颜色”操作.)

下面的代码将会产生这个截图:

class Test {
  private static BufferedImage floydSteinbergDithering(BufferedImage img) {

    C3[] palette = new C3[] {
        new C3(  0,0),new C3(  0,255),255,new C3(255,255)
    };

    int w = img.getWidth();
    int h = img.getHeight();

    C3[][] d = new C3[h][w];

    for (int y = 0; y < h; y++) 
      for (int x = 0; x < w; x++) 
        d[y][x] = new C3(img.getRGB(x,y));

    for (int y = 0; y < img.getHeight(); y++) {
      for (int x = 0; x < img.getWidth(); x++) {

        C3 oldColor = d[y][x];
        C3 newColor = findClosestPaletteColor(oldColor,palette);
        img.setRGB(x,newColor.toColor().getRGB());

        C3 err = oldColor.sub(newColor);

        if (x+1 < w)         d[y  ][x+1] = d[y  ][x+1].add(err.mul(7./16));
        if (x-1>=0 && y+1<h) d[y+1][x-1] = d[y+1][x-1].add(err.mul(3./16));
        if (y+1 < h)         d[y+1][x  ] = d[y+1][x  ].add(err.mul(5./16));
        if (x+1<w && y+1<h)  d[y+1][x+1] = d[y+1][x+1].add(err.mul(1./16));
      }
    }

    return img;
  }

  private static C3 findClosestPaletteColor(C3 c,C3[] palette) {
    C3 closest = palette[0];

    for (C3 n : palette) 
      if (n.diff(c) < closest.diff(c))
        closest = n;

    return closest;
  }

  public static void main(String[] args) throws IOException {

    final BufferedImage normal  = ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png")).getSubimage(100,100,300,300);
    final BufferedImage dietered = floydSteinbergDithering(ImageIO.read(new URL("http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png"))).getSubimage(100,300);

    JFrame frame = new JFrame("Test");
    frame.setLayout(new GridLayout(1,2));

    frame.add(new JComponent() {
      @Override
      protected void paintComponent(Graphics g) {
         super.paintComponent(g);
         g.drawImage(normal,this);
      }
    });
    frame.add(new JComponent() {
      @Override
      protected void paintComponent(Graphics g) {
         super.paintComponent(g);
         g.drawImage(dietered,this);
      }
    });

    frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400,400);
    frame.setVisible(true);
  }


  static class C3 {
    int r,g,b;

    public C3(int c) {
      Color color = new Color(c);
      this.r = color.getRed();
      this.g = color.getGreen();
      this.b = color.getBlue();
    }
    public C3(int r,int g,int b) {
      this.r = r;
      this.g = g;
      this.b = b;
    }

    public C3 add(C3 o) {
      return new C3(r + o.r,g + o.g,b + o.b);
    }
    public C3 sub(C3 o) {
      return new C3(r - o.r,g - o.g,b - o.b);
    }
    public C3 mul(double d) {
      return new C3((int) (d * r),(int) (d * g),(int) (d * b));
    }
    public int diff(C3 o) {
      return Math.abs(r - o.r) +  Math.abs(g - o.g) +  Math.abs(b - o.b);
    }

    public int toRGB() {
      return toColor().getRGB();
    }
    public Color toColor() {
      return new Color(clamp(r),clamp(g),clamp(b));
    }
    public int clamp(int c) {
      return Math.max(0,Math.min(255,c));
    }
  }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读