2013-11-20 91 views
2

我有一個TIFF圖像已讀入我的應用程序並存儲在BufferedImage對象中。如何使用Java Advanced Imaging(JAI)API確定圖像的水平和垂直DPI?我一直在環顧四周,無法找到實現這一目標的簡單方法。確定Java中的圖像的DPI

+0

如果你已經是一個' BufferedImage',你運氣不好。如果你有一個文件,流或類似的參考,我建議看看t他的ImageIO API,尤其是'ImageReader.getImageMetadata()',從那裏獲得DPI應該是相當直接的。 – haraldK

+0

數據以Web服務調用的字節數組的形式出現。我想我可以回到最初從字節數組中讀取它來嘗試一個'ImageReader'的地步。然後將DPI信息傳遞到我需要的地方。我的下一個絆腳石似乎是,當我嘗試執行'ImageIO.getImageReadersByFormatName(「tiff」)'加載讀者時,它說它無法找到該類型的讀者。仍試圖找出如何解決這個問題。 – Michael

+0

我總是發現Java圖像API有多複雜,我對它們知道得有多麼... – Michael

回答

5

這裏的一個完整的例子中提取DPI(井,每毫米的像素,真的)使用標準的ImageIO API和標準元數據格式。複雜性,我們來了...... :-P

public class DPITest { 
    public static void main(String[] args) throws IOException { 
     File input = new File(args[0]); 

     ImageInputStream stream = ImageIO.createImageInputStream(input); 
     Iterator<ImageReader> readers = ImageIO.getImageReaders(stream); 

     if (readers.hasNext()) { 
      ImageReader reader = readers.next(); 
      reader.setInput(stream); 

      IIOMetadata metadata = reader.getImageMetadata(0); 
      IIOMetadataNode standardTree = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName); 
      IIOMetadataNode dimension = (IIOMetadataNode) standardTree.getElementsByTagName("Dimension").item(0); 
      float horizontalPixelSizeMM = getPixelSizeMM(dimension, "HorizontalPixelSize"); 
      float verticalPixelSizeMM = getPixelSizeMM(dimension, "VerticalPixelSize"); 

      // TODO: Convert pixelsPerMM to DPI left as an exercise to the reader.. ;-) 

      System.err.println("horizontalPixelSizeMM: " + horizontalPixelSizeMM); 
      System.err.println("verticalPixelSizeMM: " + verticalPixelSizeMM); 
     } 
     else { 
      System.err.printf("Could not read %s\n", input); 
     } 
    } 

    private static float getPixelSizeMM(final IIOMetadataNode dimension, final String elementName) { 
     // NOTE: The standard metadata format has defined dimension to pixels per millimeters, not DPI... 
     NodeList pixelSizes = dimension.getElementsByTagName(elementName); 
     IIOMetadataNode pixelSize = pixelSizes.getLength() > 0 ? (IIOMetadataNode) pixelSizes.item(0) : null; 
     return pixelSize != null ? Float.parseFloat(pixelSize.getAttribute("value")) : -1; 
    } 
} 

一些消息來源爲:

+0

哇,他們絕對不會讓JAI容易弄清楚......我真的覺得我有時候會在我的腦海中(而且我並不是Java的新手) 。所以,看起來我可以將'InputStream'傳遞給'ImageIO.createImageInputStream'而不是'File',它應該適用於我正在做的事情。當我星期一回到辦公室時會試試這個。謝謝(你的)信息! – Michael

+0

我很好奇,是否有一些資源可以用來解決如何完成某些事情,或者它真的只是「試錯」,通過API文檔挖掘來弄清楚事情的真相嗎? – Michael

+0

@Michael這只是ImageIO API,而不是JAI特有的(但jai-imageio提供了實現此API的TIFF ImageReader插件),因此請嘗試使用Google搜索。但不知道是否有一個「權威指南」在那裏...'InputStream'應該可以。我會用一些指針更新答案。 – haraldK

3

Apache Commons Sanselan圖書館獲取圖像信息:http://commons.apache.org/imaging/index.html

final ImageInfo imageInfo = Sanselan.getImageInfo(file); 

final int physicalWidthDpi = imageInfo.getPhysicalWidthDpi(); 
final int physicalHeightDpi = imageInfo.getPhysicalHeightDpi(); 
+0

沒有使用Commons Imaging的方法嗎?我不想爲這個任務包含一個額外的庫。另外,要使用這種方法,我必須將其編碼回字節數組中。如果我這樣做而不指定'TIFFEncodeParam'中的DPI設置,則上面的代碼將爲這兩個值返回-1。如果我給編碼器指定了DPI設置,我確實得到了一個值,但顯然它將是我指定的DPI,而不是圖像的原始值。 – Michael

+0

我會更新嘗試一些東西 – constantlearner