简体   繁体   English

ImageIO写入特定的TIFF

[英]ImageIO write specific tiff

I try to convert (with ImageIO -> https://github.com/haraldk/TwelveMonkeys ) a image into a specific tiff, like imagemagick does. 我尝试将图像转换(使用ImageIO-> https://github.com/haraldk/TwelveMonkeys )到特定的tiff,就像imagemagick一样。 I have a input image and want to write a specific tiff with following: 我有一个输入图像,并想用以下内容写一个特定的tiff:

PLANAR_CONFIGURATION = 1
SAMPLES_PER_PIXEL = 1
BITS_PER_SAMPLE = 1
Y_RESOLUTION = 196
X_RESOLUTION = 204
IMAGE_WIDTH = 1728

Any idea how to render the inputstream? 任何想法如何呈现输入流? Currently the image is just converted into tiff. 当前,图像只是转换为tiff。

BufferedImage image = ImageIO.read(inputstream)
ImageIO.write( image, "tiff", outputstream );

As @fmw42 says, making the image 1-bit you have do yourself. 正如@ fmw42所说,将图像设置为1位就可以自己做。 The TIFFImageWriter plugin will write the image it is passed as-is. TIFFImageWriter插件将按TIFFImageWriter编写传递的图像。 Fortunately, this is not difficult to do. 幸运的是,这并不难做到。

Here's an easy (but not very sophisticated) way to convert the image to binary: 这是一种将图像转换为二进制的简单(但不是很复杂)的方法:

private static BufferedImage toBinary(BufferedImage original) {
    if (original.getType() == BufferedImage.TYPE_BYTE_BINARY) {
        return original;
    }

    // Quick and unsophisticated way to convert to B/W binary, using default dither and threshold (fixed, 50% I think)
    BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
    Graphics2D g = image.createGraphics();
    try {
        g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        g.setComposite(AlphaComposite.Src);
        g.drawImage(original, 0, 0, null);
    }
    finally {
        g.dispose();
    }

    return image;
}

I'll leave it as an exercise to write more advanced solutions, using adaptive thresholding, error-diffusion dithering etc. 我将保留使用自适应阈值,错误扩散抖动等功能来编写更高级的解决方案的练习。

Now you can use the following code, and you're nearly there: 现在,您可以使用以下代码,您将要使用它了:

public static void main(String[] args) throws IOException {
    BufferedImage original = ImageIO.read(new File(args[0]));
    ImageIO.write(toBinary(original), "TIFF", new File("out.tif"));
}

Unfortunately, this will not set the X and Y Resolution tags. 不幸的是,这不会设置X和Y分辨率标签。 If you need that as well, you have to dig a little deeper into the ImageIO API, and figure out how to use the metadata to control the output. 如果还需要这样做,则必须更深入地研究ImageIO API,并弄清楚如何使用元数据来控制输出。 Note that only some of the values in the metadata may be set in this way. 注意,仅元数据中的某些值可以以此方式设置。 Other values will be computed from the image data passed in, and some may be filled in with default values by the writer. 其他值将从传入的图像数据中计算得出,并且某些值可由编写器填充为默认值。

You can use the following code (the toBinary method is the same as above): 您可以使用以下代码( toBinary方法与上面的方法相同):

public static void main(String[] args) throws IOException {
    BufferedImage original = ImageIO.read(new File(args[0]));

    BufferedImage image = toBinary(original);

    ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next();

    try (ImageOutputStream stream = ImageIO.createImageOutputStream(new File("out.tif"))) {
        // You may use the param to control compression
        ImageWriteParam param = writer.getDefaultWriteParam();

        IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
        Node root = metadata.getAsTree("com_sun_media_imageio_plugins_tiff_image_1.0"); // "javax_imageio_tiff_image_1.0" will work in later versions
        Node ifd = root.getFirstChild();
        // Add X and Y resolution tags
        ifd.appendChild(createResTag("282", "XResolution", "204/1"));
        ifd.appendChild(createResTag("283", "YResolution", "196/1"));

        // Merge changes back to metadata
        metadata.mergeTree("com_sun_media_imageio_plugins_tiff_image_1.0", root);

        // Write full image, with metadata
        writer.setOutput(stream);
        writer.write(null, new IIOImage(image, null, metadata), param);
    }
    finally {
        writer.dispose();
    }
}

private static IIOMetadataNode createResTag(String tagNumber, String tagName, String tagValue) {
    IIOMetadataNode res = new IIOMetadataNode("TIFFField");
    res.setAttribute("number", tagNumber);
    res.setAttribute("name", tagName); // Tag name is optional

    IIOMetadataNode value = new IIOMetadataNode("TIFFRational");
    value.setAttribute("value", tagValue);

    IIOMetadataNode rationals = new IIOMetadataNode("TIFFRationals");
    rationals.appendChild(value);
    res.appendChild(rationals);

    return res;
}

PS: The TwelveMonkeys TIFF plugin currently don't write PlanarConfiguration: 1 , as this is the default value, and there's no way to force it. PS:TwelveMonkeys TIFF插件当前不编写PlanarConfiguration: 1 ,因为这是默认值,无法强制使用。 But it should not matter, as all compliant TIFF software must use the default value in this case. 但这无关紧要,因为在这种情况下,所有兼容的TIFF软件都必须使用默认值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM