java - ImageIO 写具体的 tiff
问题描述
我尝试将(使用 ImageIO -> https://github.com/haraldk/TwelveMonkeys)图像转换为特定的 tiff,就像 imagemagick 一样。我有一个输入图像,想用以下内容编写一个特定的 tiff:
PLANAR_CONFIGURATION = 1
SAMPLES_PER_PIXEL = 1
BITS_PER_SAMPLE = 1
Y_RESOLUTION = 196
X_RESOLUTION = 204
IMAGE_WIDTH = 1728
知道如何渲染输入流吗?目前,图像只是转换为 tiff。
BufferedImage image = ImageIO.read(inputstream)
ImageIO.write( image, "tiff", outputstream );
解决方案
正如@fmw42 所说,将图像制作为您自己的 1 位。该TIFFImageWriter
插件将按原样写入它传递的图像。幸运的是,这并不难做到。
这是将图像转换为二进制的一种简单(但不是很复杂)的方法:
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;
}
我将把它作为一个练习来编写更高级的解决方案,使用自适应阈值、误差扩散抖动等。
现在你可以使用下面的代码,你就快到了:
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"));
}
不幸的是,这不会设置 X 和 Y 分辨率标签。如果您也需要它,您必须更深入地研究 ImageIO API,并弄清楚如何使用元数据来控制输出。请注意,只有元数据中的一些值可以以这种方式设置。其他值将根据传入的图像数据计算,有些可能由作者用默认值填充。
可以使用如下代码(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:TwelveMonkeys TIFF 插件目前不写PlanarConfiguration: 1
,因为这是默认值,没有办法强制。但这无关紧要,因为在这种情况下,所有兼容的 TIFF 软件都必须使用默认值。
推荐阅读
- c# - 如何在 Windows 窗体中用 C# 中的公共 Id 加入不同数据库的两个 MS 访问表
- java - 是否允许在 Xtext 验证器中访问另一个资源?
- mongodb - MongoDB $push 聚合不会保持正确的顺序
- python - 结合来自两个数据帧的热编码
- windows - 如何使用“nsis-web”包创建科尔多瓦电子构建?
- c# - .NET core Semaphore 和 SemaphoreSlim 在 linux 服务器上工作
- ansible - 从每个库存主机的多个项目中循环注册变量
- c# - .Net Core 中的异步委托
- c# - 玩家在 Unity 3D 中穿过墙壁
- sql - MS SQL - 加入多个枢轴