Java使用imageio 讀寫影象
阿新 • • 發佈:2019-02-04
Java中進行影象I/O(即讀圖片和寫圖片,不涉及到複雜影象處理)有三個方法:
Java Image I/O API,支援常見圖片,從Java 2 version 1.4.0開始就內建了。 主頁:http://java.sun.com/javase/6/docs/technotes/guides/imageio/index.html
JAI 中的 Image I/O Tools,支援更多圖片型別,例如JPEG-LS, JPEG2000, 和 TIFF。 主頁:https://jai-imageio.dev.java.net/。JAI 是一個關於影象處理的框架,很龐大, 其中僅僅jai-imageio是關於影象I/O的,其他的可以不看。
JAI的com.sun.media.jai.codec 也有一定的影象解碼能力
當然,還有眾多的java開源工具包可以讀寫影象,例如JIMI, JMagic等,但JDK目前本身能 夠讀寫圖片,就用JDK的,開發和部署方便,不需要額外下載jar包。
由於JAI是Java新加入的,很多元件不是正式規範,JDK不自帶,因此開發和部署需要額外 安裝,安裝檔案在官網https://jai.dev.java.net/下載得到。
如果你僅僅想讀取常見格式的圖片,不需要用JAI這麼高階這麼龐大的東西, 用Java Image I/O API即可。
下面重點介紹 Java Image I/O API。
Java Image I/O API 主要在 javax.imageio 下面。JDK已經內建了常見圖片格式的外掛, 但它提供了外掛體系結構,第三方也可以開發外掛支援其他圖片格式。
下面這段程式碼可以展示,JDK內建支援的圖片格式。
主頁上有一個文件,Java Image I/O API Guide,很通俗易懂,可以讓你快速上手。以下 內容主要來自這個文件的第3章。
第3章 編寫影象I/O程式
##3.1 讀寫圖片 javax.imageio.ImageIO類提供了一組靜態方法進行最簡單的影象I/O操作。 讀取一個標準格式(GIF, PNG, or JPEG)的圖片很簡單:
寫圖片同樣簡單:
3.2 更進一步
上一節談到的方法對於簡單程式已經足夠了。不過,Java Image I/O API 提供了為編寫復 雜程式的能力。為了利用API的高階特性,應用程式應當直接使用類ImageReader 和 ImageWriter。
3.3 ImageReader 類
與其用ImageIO類來進行所有的解碼操作,不如用ImageIO類去得到一個ImageReader物件, 再用這個物件去進行讀操作:
ImageReader物件也可以基於檔案內容、檔案字尾或MIME型別獲得。這個用於查詢和初始 化ImageReader物件的機制用到了javax.imageio.spi.ImageReaderSpi類,它可以在不用初 始化外掛的情況下獲得外掛的資訊。”service provider interfaces” (SPIs)將會在下一 章詳細討論。一旦獲得了一個ImageReader物件,必須給它是指一個輸入源。大部分 ImageReader物件可以從ImageInputStream類輸入源讀取資料,ImageInputStream是Image I/O API定義的專用輸入源。
獲得一個ImageInputStream 是簡單的。給定一個File或InputStream,一個 ImageInputStream物件可以通過呼叫如下函式產生:
為讀取圖片,可以呼叫reader.read(imageIndex), imageIndex是檔案(當包含多張圖片時) 中圖片的索引。這與上一節呼叫ImageIO.read()產生的結果相同。
3.3.1 ImageReadParam
如果需要更多的控制,可以向read()方法傳遞一個ImageReadParam型別的引數。一個 ImageReadParam物件可以讓程式更好的利用記憶體。它不僅允許指定一個感興趣的區域,還 可以指定一個抽樣因子,用於向下取樣。
例如,為了只解碼圖片的左上角的1/4,程式可以先獲取一個合適的ImageReadParam物件:
最後,讀取圖片:
另一個例子,為了讀取每三個畫素中的一個,產生一個原圖片1/9大小的圖片,可以用 ImageReadParam指定抽樣因子:
3.3.2 IIOParamController
外掛有時會提供一個IIOParamController類,這是可選的。略。
3.3.3 讀多圖片檔案
ImageReader 中所有與圖片打交道的方法都有一個imageIndex 引數,這個引數用於讀取多 圖片檔案中的一張。
ImageReader.getNumImages()返回多圖片檔案中的圖片個數。這個方法有一個boolean引數, allowSearch。有的圖片格式,典型的GIF,沒有提供任何獲取檔案中的圖片個數方法,除 非讀取整個進行解析。這樣代價很高,因此設定allowSearch為false可以讓方法直接返回 -1,而不是實際的圖片個數。如果此引數是true,則該方法總會返回檔案中實際的圖片個 數。
即使在不知道檔案中圖片個數的情況下,仍可以呼叫read(imageIndex); 如果索引值過大, 該方法會丟擲IndexOutOfBoundsException異常。因此,程式可以遞增索引去獲取圖片, 直到異常。
3.3.4 讀縮圖
有的圖片格式允許一個(或多個)小的預覽圖,與主圖片一起儲存在檔案中。這些 “縮圖”對於快速識別圖片很有用,不用解碼整個圖片。
程式可以呼叫如下程式碼,探測一張圖片有多少張縮圖: reader.getNumThumbnails(imageIndex);
如果存在縮圖,可以呼叫如下程式碼獲取:
3.4.1 寫多圖片檔案
IIOImage類用於儲存圖片,縮圖或元資訊的引用。下一節將討論Metadata,目前,我們 簡單地給Metadata相關引數傳遞null。 ImageWriter 類有一個方法write(),用於從IIOImage建立一個新檔案,還有一個方法 writeInsert(),用於向一個已存在檔案新增一個IIOImage物件。通過呼叫這兩者,可以創 建一個多圖片檔案:
3.5 處理 Metadata
所有與畫素無關的資訊,都屬於在Metadata。javax.imageio.metadata 包含了用於訪問 Metadata的類和介面。
Image I/O API 將stream metadata 和image metadata區別對待。stream metadata與一個 檔案中儲存了多張圖片有關,image metadata只與單個圖片有關。如果一個檔案只包含一張 圖片,那麼就只存在image metadata。
可以通過呼叫ImageReader.getStreamMetadata 和 getImageMetadata(int imageIndex)來 獲取metadata。這些方法會返回一個實現了IIOMetadata介面的物件,該物件會被向上轉化 為ImageReader型別,
3.6 編碼轉換
略
3.7 事件監聽
Java Image I/O API,支援常見圖片,從Java 2 version 1.4.0開始就內建了。 主頁:http://java.sun.com/javase/6/docs/technotes/guides/imageio/index.html
JAI 中的 Image I/O Tools,支援更多圖片型別,例如JPEG-LS, JPEG2000, 和 TIFF。 主頁:https://jai-imageio.dev.java.net/。JAI 是一個關於影象處理的框架,很龐大, 其中僅僅jai-imageio是關於影象I/O的,其他的可以不看。
JAI的com.sun.media.jai.codec 也有一定的影象解碼能力
當然,還有眾多的java開源工具包可以讀寫影象,例如JIMI, JMagic等,但JDK目前本身能 夠讀寫圖片,就用JDK的,開發和部署方便,不需要額外下載jar包。
由於JAI是Java新加入的,很多元件不是正式規範,JDK不自帶,因此開發和部署需要額外 安裝,安裝檔案在官網https://jai.dev.java.net/下載得到。
如果你僅僅想讀取常見格式的圖片,不需要用JAI這麼高階這麼龐大的東西, 用Java Image I/O API即可。
下面重點介紹 Java Image I/O API。
Java Image I/O API 主要在 javax.imageio 下面。JDK已經內建了常見圖片格式的外掛, 但它提供了外掛體系結構,第三方也可以開發外掛支援其他圖片格式。
下面這段程式碼可以展示,JDK內建支援的圖片格式。
import javax.imageio.*; import java.util.Arrays; public class HelloWorld { public static void main(String args[]) { String readFormats[] = ImageIO.getReaderFormatNames(); String writeFormats[] = ImageIO.getWriterFormatNames(); System.out.println(“Readers: ” + Arrays.asList(readFormats)); System.out.println(“Writers: ” + Arrays.asList(writeFormats)); } }
主頁上有一個文件,Java Image I/O API Guide,很通俗易懂,可以讓你快速上手。以下 內容主要來自這個文件的第3章。
第3章 編寫影象I/O程式
##3.1 讀寫圖片 javax.imageio.ImageIO類提供了一組靜態方法進行最簡單的影象I/O操作。 讀取一個標準格式(GIF, PNG, or JPEG)的圖片很簡單:
File f = new File(“c:imagesmyimage.gif”); BufferedImage bi = ImageIO.read(f); Java Image I/O API 會自動探測圖片的格式並呼叫對應的外掛進行解碼,當安裝了一個新 外掛,新的格式會被自動理解,程式程式碼不需要改變。
寫圖片同樣簡單:
BufferedImage bi;
File f = new File(“c:imagesmyimage.png”);
ImageIO.write(im, “png”, f);
3.2 更進一步
上一節談到的方法對於簡單程式已經足夠了。不過,Java Image I/O API 提供了為編寫復 雜程式的能力。為了利用API的高階特性,應用程式應當直接使用類ImageReader 和 ImageWriter。
3.3 ImageReader 類
與其用ImageIO類來進行所有的解碼操作,不如用ImageIO類去得到一個ImageReader物件, 再用這個物件去進行讀操作:
Iterator readers = ImageIO.getImageReadersByFormatName(“gif”); ImageReader reader = (ImageReader)readers.next();
ImageReader物件也可以基於檔案內容、檔案字尾或MIME型別獲得。這個用於查詢和初始 化ImageReader物件的機制用到了javax.imageio.spi.ImageReaderSpi類,它可以在不用初 始化外掛的情況下獲得外掛的資訊。”service provider interfaces” (SPIs)將會在下一 章詳細討論。一旦獲得了一個ImageReader物件,必須給它是指一個輸入源。大部分 ImageReader物件可以從ImageInputStream類輸入源讀取資料,ImageInputStream是Image I/O API定義的專用輸入源。
獲得一個ImageInputStream 是簡單的。給定一個File或InputStream,一個 ImageInputStream物件可以通過呼叫如下函式產生:
Object source; // File or InputStream
ImageInputStream iis = ImageIO.createImageInputStream(source);
一旦有了輸入源,可以把它與一個ImageReader物件關聯起來:
reader.setInput(iis, true);
如果輸入原始檔包含多張圖片,而程式不保證按順序讀取時,第二個引數應該設定為 false。對於那些只允許儲存一張圖片的檔案格式,永遠傳遞true是合理的。
當ImageReader物件有了輸入源後,我們就可以獲取圖片資訊而不用把整張圖片資料都讀入 記憶體。例如,呼叫reader.getImageWidth(0)可以讓我們獲得檔案中第一張圖片的寬度。一 個好的外掛會試圖解碼檔案的必要部分,去獲得圖片的寬度,而不用讀取任何一個畫素。為讀取圖片,可以呼叫reader.read(imageIndex), imageIndex是檔案(當包含多張圖片時) 中圖片的索引。這與上一節呼叫ImageIO.read()產生的結果相同。
3.3.1 ImageReadParam
如果需要更多的控制,可以向read()方法傳遞一個ImageReadParam型別的引數。一個 ImageReadParam物件可以讓程式更好的利用記憶體。它不僅允許指定一個感興趣的區域,還 可以指定一個抽樣因子,用於向下取樣。
例如,為了只解碼圖片的左上角的1/4,程式可以先獲取一個合適的ImageReadParam物件:
reader.setInput(iis, true);
接下來,指定圖片區域:import java.awt.Rectangle;
int imageIndex = 0;
int half_width = reader.getImageWidth(imageIndex)/2;
int half_height = reader.getImageHeight(imageIndex)/2;
Rectangle rect = new Rectangle(0, 0, half_width, half_height);
param.setSourceRegion(rect);
最後,讀取圖片:
BufferedImage bi = reader.read(imageIndex, param);
結果是一張新圖片,寬和高都只有原圖片的一半。另一個例子,為了讀取每三個畫素中的一個,產生一個原圖片1/9大小的圖片,可以用 ImageReadParam指定抽樣因子:
param = reader.getDefaultImageParam();
param.setSourceSubsampling(3, 3, 0, 0);
BufferedImage bi3 = reader.read(0, param);
3.3.2 IIOParamController
外掛有時會提供一個IIOParamController類,這是可選的。略。
3.3.3 讀多圖片檔案
ImageReader 中所有與圖片打交道的方法都有一個imageIndex 引數,這個引數用於讀取多 圖片檔案中的一張。
ImageReader.getNumImages()返回多圖片檔案中的圖片個數。這個方法有一個boolean引數, allowSearch。有的圖片格式,典型的GIF,沒有提供任何獲取檔案中的圖片個數方法,除 非讀取整個進行解析。這樣代價很高,因此設定allowSearch為false可以讓方法直接返回 -1,而不是實際的圖片個數。如果此引數是true,則該方法總會返回檔案中實際的圖片個 數。
即使在不知道檔案中圖片個數的情況下,仍可以呼叫read(imageIndex); 如果索引值過大, 該方法會丟擲IndexOutOfBoundsException異常。因此,程式可以遞增索引去獲取圖片, 直到異常。
3.3.4 讀縮圖
有的圖片格式允許一個(或多個)小的預覽圖,與主圖片一起儲存在檔案中。這些 “縮圖”對於快速識別圖片很有用,不用解碼整個圖片。
程式可以呼叫如下程式碼,探測一張圖片有多少張縮圖: reader.getNumThumbnails(imageIndex);
如果存在縮圖,可以呼叫如下程式碼獲取:
int thumbailIndex = 0;
BufferedImage bi;
bi = reader.readThumbnail(imageIndex, thumbnailIndex);
3.4 ImageWriter 類
就像我們可以用ImageIO 的一個方法獲取某種圖片格式的ImageReader物件一樣,我們也可 以獲取ImageWriter物件:
Iterator writers = ImageIO.getImageWritersByFormatName(“png”);
ImageWriter writer = (ImageWriter)writers.next();
一旦獲取了一個ImageWriter物件,必須給它設定一個輸出源ImageOutputStream。File f = new File(“c:imagesmyimage.png”);
ImageOutputStream ios = ImageIO.createImageOutputStream(f);
writer.setOutput(ios);
最後,可以把圖片寫入到輸出源:BufferedImage bi;
writer.write(bi);
3.4.1 寫多圖片檔案
IIOImage類用於儲存圖片,縮圖或元資訊的引用。下一節將討論Metadata,目前,我們 簡單地給Metadata相關引數傳遞null。 ImageWriter 類有一個方法write(),用於從IIOImage建立一個新檔案,還有一個方法 writeInsert(),用於向一個已存在檔案新增一個IIOImage物件。通過呼叫這兩者,可以創 建一個多圖片檔案:
BufferedImage first_bi, second_bi;
IIOImage first_IIOImage = new IIOImage(first_bi, null, null);
IIOImage second_IIOImage = new IIOImage(second_bi, null, null);
writer.write(null, first_IIOImage, null);
if (writer.canInsertImage(1)) {
writer.writeInsert(1, second_IIOImage, null);
} else {
System.err.println(“Writer can’t append a second image!”);
}
3.5 處理 Metadata
所有與畫素無關的資訊,都屬於在Metadata。javax.imageio.metadata 包含了用於訪問 Metadata的類和介面。
Image I/O API 將stream metadata 和image metadata區別對待。stream metadata與一個 檔案中儲存了多張圖片有關,image metadata只與單個圖片有關。如果一個檔案只包含一張 圖片,那麼就只存在image metadata。
可以通過呼叫ImageReader.getStreamMetadata 和 getImageMetadata(int imageIndex)來 獲取metadata。這些方法會返回一個實現了IIOMetadata介面的物件,該物件會被向上轉化 為ImageReader型別,
3.6 編碼轉換
略
3.7 事件監聽
略
3.8案例
package com.test.image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
/**
* 讀寫圖片
* @author taoww
* 參考:http://www.360doc.com/content/16/0224/16/12500151_537069462.shtml
*
*/
public class RWImage {
public static void main(String[] args) {
//simpleRWImage();
complexRWImage();
}
/**
* 讀寫圖片簡單方式
*/
public static void simpleRWImage(){
try {
//讀取圖片
File f1 = new File("C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg");
BufferedImage bi=ImageIO.read(f1);
//將讀取的圖片寫到本地
File f2 = new File("C:\\Users\\Public\\Pictures\\Sample Pictures\\lihua.png");
if(!f2.exists()){
f2.createNewFile();
}
ImageIO.write(bi, "png", f2);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Java Image I/O API 提供了為編寫復 雜程式的能力。
* 為了利用API的高階特性,應用程式應當直接使用類ImageReader和 ImageWriter讀寫圖片
*/
public static void complexRWImage(){
try {
/**********************讀取圖片*********************************/
File f = new File("C:\\Users\\Public\\Pictures\\Sample Pictures\\Chrysanthemum.jpg");
Iterator readers = ImageIO.getImageReadersByFormatName("jpg");
ImageReader reader = (ImageReader)readers.next();
/*
* 獲得了一個ImageReader物件,必須給它是指一個輸入源。
* 大部分 ImageReader物件可以從ImageInputStream類輸入源讀取資料,
* ImageInputStream是Image I/O API定義的專用輸入源
*/
ImageInputStream iis = ImageIO.createImageInputStream(f);
/*
* 一旦有了輸入源,可以把它與一個ImageReader物件關聯起來.
* 如果輸入原始檔包含多張圖片,而程式不保證按順序讀取時,第二個引數應該設定為 false。
* 對於那些只允許儲存一張圖片的檔案格式,永遠傳遞true是合理的
*/
reader.setInput(iis, true);
/*
* 如果需要更多的控制,可以向read()方法傳遞一個ImageReadParam型別的引數。
* 一個 ImageReadParam物件可以讓程式更好的利用記憶體。
* 它不僅允許指定一個感興趣的區域,還 可以指定一個抽樣因子,用於向下取樣.
* */
ImageReadParam param=reader.getDefaultReadParam();
int imageIndex=0;
int halfWidth=reader.getWidth(imageIndex)/2;
int halfHegiht=reader.getHeight(imageIndex)/2;
Rectangle rectangle=new Rectangle(0,0,halfWidth,halfHegiht);
param.setSourceRegion(rectangle);
BufferedImage bi=reader.read(0, param);
/**********************寫圖片*********************************/
Iterator writes=ImageIO.getImageWritersByFormatName("png");
ImageWriter imageWriter=(ImageWriter)writes.next();
f=new File("C:\\Users\\Public\\Pictures\\Sample Pictures\\lihua.png");
ImageOutputStream iops=ImageIO.createImageOutputStream(f);
imageWriter.setOutput(iops);
imageWriter.write(bi);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
參考地址:http://www.360doc.com/content/16/0224/16/12500151_537069462.shtml