0

好吧,在将图像从 TIFF 转换为 PNG 格式的过程中,我真的希望最终图像尽可能小,因此我将位深度设置为 1(黑白),我正在处理签名图像。我的问题是我“丢失”了一些像素,因为在原始图像中“太白”并且转换过程忽略了它们。

我想要的是一种告诉 PNG 编码器在图像中应用阈值的方法,例如,如果灰度级大于 240,则为白色,否则为黑色。或者也许任何其他方式图像不会丢失太多像素,因为图像是签名,我必须在浏览器中显示它。这是一个示例:

样本签名

这是我用来将图像从 TIFF 转换为 PNG 格式的代码:

public byte[]tiffToPng(byte[]tiffBytes) throws IOException {

    SeekableStream stream = new ByteArraySeekableStream(tiffBytes);
    ImageDecoder decoder = ImageCodec.createImageDecoder("tiff", stream, null);
    RenderedImage renderedImage = decoder.decodeAsRenderedImage(0);

    PNGEncodeParam pngEncodeParam = PNGEncodeParam.getDefaultEncodeParam(renderedImage);
    pngEncodeParam.setBitDepth(1);

    ByteArrayOutputStream pngBytesStream = new ByteArrayOutputStream();
    ImageEncoder encoder = ImageCodec.createImageEncoder("png", pngBytesStream, pngEncodeParam);
    encoder.encode(renderedImage);
    pngBytesStream.flush();
    return pngBytesStream.toByteArray();
}
4

2 回答 2

1

好吧,过了一段时间,我首先将 RenderedImage 转换为 BufferedImage,然后对 RGB 值进行循环并完成阈值处理。最后,我将生成的图像编码为 PNG(位深度=1)。就是这个:

public byte[]tiffToPng(byte[]tiffBytes) throws IOException {
    SeekableStream stream = new ByteArraySeekableStream(tiffBytes);
    ImageDecoder decoder = ImageCodec.createImageDecoder("tiff", stream, null);
    RenderedImage tiffRenderedImage = decoder.decodeAsRenderedImage(0);

    BufferedImage tiffBufferedImage = toBufferedImage(tiffRenderedImage);
    for (int y = 0; y < tiffBufferedImage.getHeight(); y++) {
        for (int x = 0; x < tiffBufferedImage.getWidth(); x++) {
            int rgb = tiffBufferedImage.getRGB(x, y);
            int a = (rgb>>24)&0xFF;
            int r = (rgb>>16)&0xFF;
            int g = (rgb>>8)&0xFF;
            int b = (rgb>>0)&0xFF;
            if(a == 0xFF && r == g && g == b) {
                if(r < 254) {
                    tiffBufferedImage.setRGB(x, y, 0xFF000000);
                } else {
                    tiffBufferedImage.setRGB(x, y, 0xFFFFFFFF);
                }
            }
        }
    }

    PNGEncodeParam pngEncodeParam = PNGEncodeParam.getDefaultEncodeParam(tiffBufferedImage);
    pngEncodeParam.setBitDepth(1);
    ByteArrayOutputStream pngBytesStream = new ByteArrayOutputStream();
    ImageEncoder encoder = ImageCodec.createImageEncoder("png", pngBytesStream, pngEncodeParam);
    encoder.encode(tiffBufferedImage);
    pngBytesStream.flush();
    return pngBytesStream.toByteArray();
}

public BufferedImage toBufferedImage(RenderedImage img) {
        if (img instanceof BufferedImage) {
            return (BufferedImage) img;
        }
        ColorModel cm = img.getColorModel();
        int width = img.getWidth();
        int height = img.getHeight();
        WritableRaster raster = cm.createCompatibleWritableRaster(width, height);
        boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
        Hashtable properties = new Hashtable();
        String[] keys = img.getPropertyNames();
        if (keys != null) {
            for (int i = 0; i < keys.length; i++) {
                properties.put(keys[i], img.getProperty(keys[i]));
            }
        }
        BufferedImage result = new BufferedImage(cm, raster, isAlphaPremultiplied, properties);
        img.copyData(raster);
        return result;
    }

这是最终的图像:

签名成功转换 PNG 1 位深度

于 2013-10-24T23:30:13.597 回答
0

您想要做的更多的是图像预处理,我不希望编码器允许这样做。只需预处理图像(亮度/对比度和/或伽玛)并保存。

于 2013-10-24T22:21:35.910 回答