1. 程式人生 > >java:構建ImageInputStream利用ImageReader對記憶體位元組流進行影象解碼

java:構建ImageInputStream利用ImageReader對記憶體位元組流進行影象解碼

java提供了一個非常方便的影象工具類javax.imageio.ImageIO,用它的javax.imageio.ImageIO.read方法可以很方便的將一個影象檔案進行解碼。
javax.imageio.ImageIO.read方法有多個過載方法,支援File,InputStream,URL等引數,但這些方法有可能會在解碼過程中使用檔案系統做cache,具體原因這裡不展開講了,好長,你要研究java原始碼。
有了磁碟IO勢必會影響解碼效率,這在效能敏感的應用環境是不能容忍的,
如果要實現完全基於記憶體的影象解碼,就不能簡單使用javax.imageio.ImageIO.read方法。需要利用javax.imageio.stream.MemoryCacheImageInputStream

來實現記憶體cache。來實現完全的記憶體解碼,以下是完整的程式碼,

package test;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import
javax.imageio.stream.ImageInputStream; import javax.imageio.stream.MemoryCacheImageInputStream; import org.junit.Test; public class TestReadMemoryImage { @Test public final void testreadMemoryImage() throws IllegalArgumentException, IOException { // 將影象檔案加讀取到記憶體成為位元組陣列 byte[] imgBytes = readBytes(TestReadMemoryImage.class.getResourceAsStream("/images/he049.jpg"
)); BufferedImage bufImg = readMemoryImage(imgBytes); System.out.printf("decode success,width=%d,heigh=%d\n", bufImg.getWidth(),bufImg.getHeight()); } @Test public final void testreadMemoryImage1() throws IllegalArgumentException, IOException { // 將影象檔案加讀取到記憶體成為位元組陣列 byte[] imgBytes = readBytes(TestReadMemoryImage.class.getResourceAsStream("/images/he049.jpg")); BufferedImage bufImg = readMemoryImage1(imgBytes); System.out.printf("decode success,width=%d,heigh=%d\n", bufImg.getWidth(),bufImg.getHeight()); } /** * 從記憶體位元組陣列中讀取影象 * * @param imgBytes * 未解碼的影象資料 * @return 返回 {@link BufferedImage} * @throws IOException * 當讀寫錯誤或不識別的格式時丟擲 */ public static final BufferedImage readMemoryImage(byte[] imgBytes) throws IOException { if (null == imgBytes || 0 == imgBytes.length) throw new NullPointerException("the argument 'imgBytes' must not be null or empty"); // 將位元組陣列轉為InputStream,再轉為MemoryCacheImageInputStream ImageInputStream imageInputstream = new MemoryCacheImageInputStream(new ByteArrayInputStream(imgBytes)); // 獲取所有能識別資料流格式的ImageReader物件 Iterator<ImageReader> it = ImageIO.getImageReaders(imageInputstream); // 迭代器遍歷嘗試用ImageReader物件進行解碼 while (it.hasNext()) { ImageReader imageReader = it.next(); // 設定解碼器的輸入流 imageReader.setInput(imageInputstream, true, true); // 影象檔案格式字尾 String suffix = imageReader.getFormatName().trim().toLowerCase(); // 影象寬度 int width = imageReader.getWidth(0); // 影象高度 int height = imageReader.getHeight(0); System.out.printf("format %s,%dx%d\n", suffix, width, height); try { // 解碼成功返回BufferedImage物件 // 0即為對第0張影象解碼(gif格式會有多張影象),前面獲取寬度高度的方法中的引數0也是同樣的意思 return imageReader.read(0, imageReader.getDefaultReadParam()); } catch (Exception e) { imageReader.dispose(); // 如果解碼失敗嘗試用下一個ImageReader解碼 } } imageInputstream.close(); // 沒有能識別此資料的影象ImageReader物件,丟擲異常 throw new IOException("unsupported image format"); } public static final BufferedImage readMemoryImage1(byte[] imgBytes) throws IOException { if (null == imgBytes || 0 == imgBytes.length) throw new NullPointerException("the argument 'imgBytes' must not be null or empty"); // 將位元組陣列轉為InputStream,再轉為MemoryCacheImageInputStream ImageInputStream imageInputstream = new MemoryCacheImageInputStream(new ByteArrayInputStream(imgBytes)); // 直接呼叫ImageIO.read方法解碼 BufferedImage bufImg = ImageIO.read(imageInputstream); if(null==bufImg) // 沒有能識別此資料的影象ImageReader物件,丟擲異常 throw new IOException("unsupported image format"); return bufImg; } /** * 從{@link InputStream}讀取位元組陣列<br> * 結束時會關閉{@link InputStream}<br> * {@code in}為{@code null}時丟擲{@link NullPointerException} * * @param in * @return 位元組陣列 * @throws IOException */ public static final byte[] readBytes(InputStream in) throws IOException { if (null == in) throw new NullPointerException("the argument 'in' must not be null"); try { int buffSize = Math.max(in.available(), 1024 * 8); byte[] temp = new byte[buffSize]; ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize); int size = 0; while ((size = in.read(temp)) != -1) { out.write(temp, 0, size); } return out.toByteArray(); } finally { in.close(); } } }

程式碼中提供了兩個方法來實現記憶體解碼(readMemoryImagereadMemoryImage1),共同點就是都要基於byte陣列構建一個MemoryCacheImageInputStream物件作為 ImageInputStream
不同點就是readMemoryImage1方法直接使用javax.imageio.ImageIO.read(ImageInputStream stream)方法來解碼。
readMemoryImage則是尋找合適的ImageReader來實現解碼,
其實邏輯上與javax.imageio.ImageIO.read(ImageInputStream stream)方法實現程式碼也差不多,你可以自己選擇。最終的結果都是一樣的。

相關推薦

java:構建ImageInputStream利用ImageReader記憶體位元組進行影象解碼

java提供了一個非常方便的影象工具類javax.imageio.ImageIO,用它的javax.imageio.ImageIO.read方法可以很方便的將一個影象檔案進行解碼。 javax.imageio.ImageIO.read方法有多個過載方法,支援F

Java利用JNI呼叫FFMpegh264碼進行解碼

前期配置工作: 使用JNI呼叫: java端: package com.recon.action; public class Decode { public native String loadfile(String s); //

GA:利用GA一元函數進行優化過程,求x∈(0,10)中y的最大值——Jason niu

title variable ati 過程 優化 mea ... http [] x = 0:0.01:10; y = x + 10*sin(5*x)+7*cos(4*x); figure plot(x, y) xlabel(‘independent variable

利用python2012美國大選進行資料分析(四,時間處理)

1,str轉datetime 我們可以使用pd.to_datetime(series,format='%Y%m%d')將字元轉化為日期,格式為年月日。 data_vs['time'] = pd.to_datetime(data_vs['contb_receipt_dt']

Java基礎知識複習(五)-- 位元組 && 字元

一、位元組流 InputStream位元組輸入流 ,OutputStream位元組輸出流 ,用於以位元組的形式讀取和寫入資料 所有的資料存放在計算機中都是以數字的形式存放的。 所以字母就需要轉換為數字才能夠存放。 比如A就對應的數字65,a對應的數字97. 不同的字母和符號對應不

JAVA陣列學習之一:一維陣列進行逆序排列

Java中的陣列必須先初始化,然後才能使用。所謂初始化,就是為陣列中的元素分配記憶體空間,併為元素賦值。 陣列的初始化方式: 動態初始化:初始化時只指定陣列長度,由系統為陣列分配初始值。 靜態初始化:

利用PythonQQ空間資料進行分析,瞭解你的QQ好友

對如下內容進行了分析: 好友發說說月份統計 好友所屬星座統計 好友手機裝置統計 好友發說說小時統計 對好友的好友進行統計 本人對於Python學習建立了一個小小的學習圈子,為各位提供了一個平臺,大家一起來討論學習Python。歡迎各位到來Python學習群:96041

EL之RF(RFC):利用RF二分類問題進行建模並評估

EL之RF(RFC):利用RF對二分類問題進行建模並評估 輸出結果   設計思路   核心程式碼 auc = [] nTreeList = range(50, 2000, 50) for iTrees in nTreeList:

EL之RF(RFC):利用RF多分類問題進行建模並評估(六分類+分層抽樣)

EL之RF(RFC):利用RF對多分類問題進行建模並評估(六分類+分層抽樣) 輸出結果 設計思路   核心程式碼 missCLassError = [] nTreeList = range(50, 2000, 50) for iTrees in n

EL之GB(GBC):利用GB二分類問題進行建模並評估

EL之GB(GBC):利用GB對二分類問題進行建模並評估 輸出結果 T1、純GB演算法 T2、以RF為基學習器的GB演算法         設計思路   核心程式碼

[作業系統設定]利用IPSec指定的ip進行訪問限制

以win2003系統為例: 操作(看圖): 1.任務:現在192.168.2.200可訪問;目的;本地禁止對其訪問 2.進入:管理工具->本地安全設定->IP安全策略 3.右鍵建立IP安全策略 4.彈出嚮導,如下圖:(一直選擇[是]或者[下一步]直至完成,

利用junitspringMVC的Controller進行測試

java.lang.NoClassDefFoundError: javax/servlet/SessionCookieConfigat org.springframework.test.context.web.AbstractGenericWebContextLoader.configureWebResou

使用java語言,利用多執行緒呼叫WebService進行資料處理

因工作原因,需要將一個表(tbA)中的所有資料,根據user_id,去請求webserive獲取相關的資料,然後插入到另外的一張表(tbB)中,供他人使用。不過這個表中的資料不少有78萬條左右,而這樣的大批量資料操作,還不能白天執行。只能在夜裡,等伺服器負荷低的時候進

利用tcpdump安卓機頂盒進行抓包

最近遇到一個問題,詳情如下:同一檯安卓機頂盒(海思晶片 Android4.4)在同一樓層的不同位置播放同一個視訊流,結果一個能播放另一個不能播放。最終原因:不能播放的區域網路物理鏈路不一樣,符合防火牆的規則,導致機頂盒的請求被攔截了。解決思路:抓包分析步驟2、利用adb命令將

利用echartspm2.5資料進行視覺化處理

echarts是百度提供的資料視覺化js外掛,功能強大,提供各種基本的圖表(尤其世界以及中國各種地圖,方便時空資料的視覺化);具體看參考http://echarts.baidu.com/ 。 本文主要嘗試了四個功能 1.      滑鼠放在地圖某個區上時顯示該區在所給資料

java向檔案中寫入內容,位元組,字元,緩衝,複製檔案,設定字元編碼 例項

package com.liuxin.test; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.

利用metasploitms10-018漏洞進行攻擊例項

攻擊機:VMware 環境下Kali-liunx靶機:VMware環境下Windows xp1、首先進入metasploit2、用search命令來尋找ms10-018的可用攻擊模組3、我們使用第一個使用use命令,複製模組名稱4、使用show options 命令來檢視可用

教你如何利用threejs3D模型面板進行DIY

一步一步教你如何利用threejs載入gltf模型來實現DIY換膚功能。 ### 模型準備 - ***模型製作*** 模型可以通過網上下載,也可以自己通過c4d、maya、blender等模型製作軟體得到。這裡就不敘述有關模型製作的問題,本文中會在blender進行模型的有關設定。 - ***模型

C#字符串進行編碼解碼

odin div 字符串 編碼解碼 odi encode cnblogs 進行 viewbag 以UTF8編碼格式為例: 1 //編碼 2 ViewBag.FileURL = HttpUtility.UrlEncode(UriString, Encoding.UTF8);

JavaWeb基礎 URLDecoder.decode 字符串進行URL解碼

clip logs system java.net chrom block ide cnblogs .com 禮悟:   好好學習多思考,尊師重道存感恩。葉見尋根三二一,江河湖海同一體。 虛懷若谷良心主,願行無悔給最苦。讀書鍛煉強身心,誠勸且行且珍惜。