1. 程式人生 > >使用 Java 進行影象處理

使用 Java 進行影象處理

通常我們使用Java 編碼輸出影象預設的影象解析度是72dpi(關於影象解析度可以看我轉載的一篇文章《圖片解析度介紹》),PC顯示器的裝置解析度一般在60~120dpi之間,而熟悉印刷行業的朋友都知道,印刷一張影象需要的影象解析度一般是300dpi,就是說這樣的影象在顯示器上顯示可能很細膩但是印刷輸出的效果卻非常粗糙。那麼我們針對印刷或者其他需要高解析度的應用場合,就需要輸出更高解析度的影象,可是縱觀Java SE 中標準的ImageIO 庫並沒有提供設定DPI值的方法,那麼怎麼使用Java生成適合印刷或者更高解析度的影象呢?

幸好,JAI_ImageIO 為我們解決了這個難題,或者只能說部分解決。目前JAI_ImageIO_1.1 對於設定DPI 資訊的支援僅限於TIFF格式,我並沒有在JAI_ImageIO_1.1 中找到針對其他影象格式(例如常見的JPEG)設定DPI 的方法。

JAI_ImageIO_1.1 中對於的TIFF 格式提供了2種途徑(DOM 和 API)可以在影象編碼時將DPI 資訊設定進Meatadata。下面是一段建立影象並且以300dpi 編碼輸出的樣例程式,它分別就這兩種方法都做了實現,可以提供大家學習參考。編譯執行需要引用JAI_ImageIO_1.1,可以從https://jai-imageio.dev.java.net/下載。

import com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet;
import com.sun.media.imageio.plugins.tiff.TIFFDirectory;
import com.sun.media.imageio.plugins.tiff.TIFFField;
import com.sun.media.imageio.plugins.tiff.TIFFTag;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.FileImageOutputStream;

/**
 * 設定自定義dpi值到TIFF格式影象的樣例程式。
 * 需要 JAI_ImageIO_1.1 提供支援。
 
*/

publicclass SetDPI4TIFF {

    
privatestatic String METADATA_NAME ="com_sun_media_imageio_plugins_tiff_image_1.0";
    
privatestaticint DPI_X =300;
    
privatestaticint DPI_Y =300;

    
publicstaticvoid main(String[] args) throws Throwable {
        
// Create sample image.
        RenderedImage image =new BufferedImage(256256, BufferedImage.TYPE_3BYTE_BGR);

        
// Get TIFF writer.
        Iterator writers = ImageIO.getImageWritersByFormatName("TIFF");
        
if (writers ==null||!writers.hasNext()) {
            
thrownew IllegalStateException("No TIFF writers!");
        }

        ImageWriter writer 
= (ImageWriter) writers.next();

        
// Get the default image metadata.
        ImageTypeSpecifier imageType = ImageTypeSpecifier.createFromRenderedImage(image);
        IIOMetadata imageMetadata 
= writer.getDefaultImageMetadata(imageType, null);

        
// Set DPI.
        String fileName;
        String methodology;
        
if (args.length ==0|| args[0].equalsIgnoreCase("DOM")) {
            fileName 
="dpi_dom.tif";
            setDPIViaDOM(imageMetadata);
            methodology 
="DOM";
        }
else{
            fileName 
="dpi_api.tif";
            imageMetadata 
= setDPIViaAPI(imageMetadata);
            methodology 
="API";
        }


        System.out.println(
" Writing "+ fileName +" using "+ methodology +" methodology ");

        
// Write image.
        writer.setOutput(new FileImageOutputStream(new File(fileName)));
        writer.write(
new IIOImage(image, null, imageMetadata));
    }


    
/**
     * Set DPI using DOM nodes.
     
*/

    
privatestaticvoid setDPIViaDOM(IIOMetadata imageMetadata) throws IIOInvalidTreeException {
        
// Get the DOM tree.
        IIOMetadataNode root = (IIOMetadataNode) imageMetadata.getAsTree(METADATA_NAME);

        
// Get the IFD.
        IIOMetadataNode ifd = (IIOMetadataNode) root.getElementsByTagName("TIFFIFD").item(0);

        
// Get {X,Y}Resolution tags.
        BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
        TIFFTag tagXRes 
= base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
        TIFFTag tagYRes 
= base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);

        
// Create {X,Y}Resolution nodes.
        IIOMetadataNode nodeXRes = createRationalNode(tagXRes.getName(), tagXRes.getNumber(), DPI_X, 1);
        IIOMetadataNode nodeYRes 
= createRationalNode(tagYRes.getName(), tagYRes.getNumber(), DPI_Y, 1);

        
// Append {X,Y}Resolution nodes to IFD node.
        ifd.appendChild(nodeXRes);
        ifd.appendChild(nodeYRes);

        
// Set metadata from tree.
        imageMetadata.setFromTree(METADATA_NAME, root);
    }


    
/**
     * Creates a node of TIFF data type RATIONAL.
     
*/

    
privatestatic IIOMetadataNode createRationalNode(String tagName, int tagNumber, int numerator, int denominator) {
        
// Create the field node with tag name and number.
        IIOMetadataNode field =new IIOMetadataNode("TIFFField");
        field.setAttribute(
"name", tagName);
        field.setAttribute(
"number"""+ tagNumber);

        
// Create the RATIONAL node.
        IIOMetadataNode rational =new IIOMetadataNode("TIFFRational");
        rational.setAttribute(
"value", numerator +"/"+ denominator);

        
// Create the RATIONAL node and append RATIONAL node.
        IIOMetadataNode rationals =new IIOMetadataNode("TIFFRationals");
        rationals.appendChild(rational);

        
// Append RATIONALS node to field node.
        field.appendChild(rationals);

        
return field;
    }


    
/**
     * Set DPI using API.
     
*/

    
privatestatic IIOMetadata setDPIViaAPI(IIOMetadata imageMetadata) throws IIOInvalidTreeException {
        
// Derive the TIFFDirectory from the metadata.
        TIFFDirectory dir = TIFFDirectory.createFromMetadata(imageMetadata);

        
// Get {X,Y}Resolution tags.
        BaselineTIFFTagSet base = BaselineTIFFTagSet.getInstance();
        TIFFTag tagXRes 
= base.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION);
        TIFFTag tagYRes 
= base.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION);

        
// Create {X,Y}Resolution fields.
        TIFFField fieldXRes =new TIFFField(tagXRes, TIFFTag.TIFF_RATIONAL, 1newlong[][]{{DPI_X, 1}});
        TIFFField fieldYRes 
=new TIFFField(tagYRes, TIFFTag.TIFF_RATIONAL, 1newlong[][]{{DPI_Y, 1}});

        
// Append {X,Y}Resolution fields to directory.
        dir.addTIFFField(fieldXRes);
        dir.addTIFFField(fieldYRes);

        
// Convert to metadata object and return.
return dir.getAsMetadata();
    }

}