簡體   English   中英

使用Java在JPEG中存儲DPI和紙張尺寸信息

[英]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時,相關標簽是Horizo​​ntalPixelSize和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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM