[英]Storing DPI and Paper Size information in a JPEG with Java
我有以下代码:
ImageIO.write(originalImage, OUTPUT_TYPE, resultOutput);
这是对以下javax.imageio.ImageIO
方法的调用:
public static boolean write(RenderedImage im,
String formatName,
File output)
throws IOException
这会将原始BMP图像转换为JGP输出。 是否可以在JPEG中存储DPI和纸张尺寸信息以帮助打印操作?
幸运的是, java image I / O API可以让你做到这一点。 它还允许以与格式无关的方式设置图像元数据。 例如,指定所需的DPI,这是我想要做的。
事实证明,设置dpi并不像预期那么简单......
java image I / O API是基于插件的 ,对于您希望使用的每种文件格式,必须提供适当的插件。 API为编写插件中性代码提供了必要的抽象 ,并且具有可在运行时查询的可用实现的存储库。 从J2SE 6开始,每个JRE都必须提供PNG,JPG和BMP文件格式的插件(以及我尚未尝试过的其他一些插件)。
设置图像元数据的规范是标准(插件中性)元数据格式规范。 奇怪的是,规范是XML模式。 这是正确的,如果你想设置DPI,你必须通过使用IIOMetadataNodes构建DOM -tree 并将其与其余部分合并来实现 ! 叹..
请注意,插件对标准元数据的支持可能不同:
无论如何,当您想要设置DPI时,相关标签是HorizontalPixelSize和VerticalPixelSize:
<!ELEMENT "HorizontalPixelSize" EMPTY>
<!-- The width of a pixel, in millimeters,
as it should be rendered on media -->
<!ATTLIST "HorizontalPixelSize" "value" #CDATA #REQUIRED>
<!-- Data type: Float -->
<!ELEMENT "VerticalPixelSize" EMPTY>
<!-- The height of a pixel, in millimeters,
as it should be rendered on media -->
<!ATTLIST "VerticalPixelSize" "value" #CDATA #REQUIRED>
<!-- Data type: Float -->
请注意,规范明确指出两者都必须以毫米每点表示。 如何忽视自己的规格,Sun风格
Sun已为其PNG和JPG插件实现了此元数据规范,并将其包含在当前的JDK和JRE发行版中。 相关课程是
com.sun.imageio.plugins.png.PNGImageWriter
com.sun.imageio.plugins.jpeg.JPEGImageWriter
您可以从com.sun包中看出它们不是J2SE API的一部分,而是特定于Sun的实现。
还记得每个点的规格要求毫米吗? 那么,看看下表,看看Sun实际上如何实现规范:
plug-in unit bug report date reported
PNGImageWriter dots per millimeter bug 5106305 23 sep 2004
JPEGImageWriter decimeter per dot bug 6359243 05 dec 2005
这些错误已经知道了很长时间,并且它们的修复非常简单。 不幸的是,它们被赋予了低优先级,在撰写本文时(2008年7月)甚至没有被评估过。 大。 怎么办?
好吧,因为解决方法是如此微不足道,我决定坚持使用图像I / O API。 如果你给这些类他们想要的东西,位图就会很好。 要确保您的导出代码也适用于正确实现规范的平台,它必须检查正在使用的实际实现类并补偿错误。
如果您发现自己处于类似情况,请确保您的解决方法代码能够在最终修复错误时应对。 更多关于这一点的文章' J2SE api中的错误如何可以咬你两次 '。
哦,如果你使用instanceof来检查所有平台上不能保证存在的错误类的实例,请务必捕获NoClassDefFoundError;)
这个问题已经部分回答: 用Java编写dpi元数据到jpeg图像
从图像编辑器GIMP我知道.png具有可以保存为元数据的分辨率(DPI)。 有JPEG的EXIF数据,一般的相机信息,包括分辨率。
您可以考虑使用Commons Sanselan而不是ImageIO来完成此任务。
有关详细信息,请参阅http://commons.apache.org/sanselan/whysanselan.html 。
我发现此帖子用于在PNG文件上设置DPI 。 它指出您应该使用'metadata.mergeTree'来正确保存元数据。
考虑到这一点,这里有一些工作的groovy代码,它采用BMP文件并在任意DPI创建JPG文件:
import java.awt.image.BufferedImage
import java.io.File
import java.util.Hashtable
import java.util.Map
import javax.imageio.*
import javax.imageio.stream.*
import javax.imageio.metadata.*
import javax.imageio.plugins.jpeg.*
import org.w3c.dom.*
File sourceFile = new File("sample.bmp")
File destinationFile = new File("sample.jpg")
dpi = 100
BufferedImage sourceImage = ImageIO.read(sourceFile)
ImageWriter imageWriter = ImageIO.getImageWritersBySuffix("jpeg").next();
ImageOutputStream ios = ImageIO.createImageOutputStream(destinationFile);
imageWriter.setOutput(ios);
def jpegParams = imageWriter.getDefaultWriteParam();
IIOMetadata data = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(sourceImage), jpegParams);
Element tree = (Element)data.getAsTree("javax_imageio_jpeg_image_1.0");
Element jfif = (Element)tree.getElementsByTagName("app0JFIF").item(0);
jfif.setAttribute("Xdensity", Integer.toString(dpi));
jfif.setAttribute("Ydensity", Integer.toString(dpi));
jfif.setAttribute("resUnits", "1"); // density is dots per inch
data.mergeTree("javax_imageio_jpeg_image_1.0",tree)
// Write and clean up
imageWriter.write(data, new IIOImage(sourceImage, null, data), jpegParams);
ios.close();
imageWriter.dispose();
在那个OSX的预览应用程序中,我工作得很好,Gimp都报告得到的图像是100 DPI。 至于纸张尺寸......我想这是由DPI直接决定的? 我找不到任何可以设置该特定值的JPEG属性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.