Android5以後的android.hardware.camera被列為「@Deprecated,請改用android.hardware.camera2。」
但就算不提「android.hardware.camera2」的複雜,傳入的照片資料結構本身跟「android.hardware.camera」的差異也非常大,如果要升級,光是改寫相機硬體與權限套件還不夠,還要連照片的轉檔也一併完成。
Android相機預設的檔案格式稱為YUV,它是種「用三種向量的方式來記錄圖片資料」的格式(完全無法理解怎麼實作),一共有420、422和444三種格式。(但也可以指定相機傳入舊格式檔案,但會造成「無法預覽」,自然也無法進行拍照。這格式的檔案在實用上功能有點不明。)
這檔案的格式技術細節未來需要慢慢補完。
Android使用這種格式的檔案奇妙之處在於:View元件本身幾乎都不支援這個格式的檔案,依然支援傳統RGB(Bitmap)或Drawalbe。
「android.hardware.camera」中取得的是YUV圖片的raw資料格式,也就byte矩陣檔。
但「android.hardware.caemra2」中經由「ImageReader」取得的是YUV圖片的資料格式封裝物件「Image」,這東西並不是YUV檔的實體,也無法直接轉成raw資料格式。
一個Image中有三層「Plane」,每一層都可以視為是對應「YUV」中的一種向量資料,因為是向量,所以每一張照片中的每一層Plane資料格式大小其實都不一定,跟RGB格式不一樣,只要知道的圖片長寬和格式,幾乎就可以順利估算出檔案大小或資料長度。
將Image物件格式轉成raw格式的演算法如下。三層ByteBuffer剛好是依序三層Plane的ByteBuffer資料。
但用QRCode Decode的套件:ZXing作測試,它可以接受「android.hardware.camera」的raw資料,但仍無法接收這個格式的資料。所以這個演算法還需要再檢討。
參考連結
https://stackoverflow.com/questions/9325861/converting-yuv-rgbimage-processing-yuv-during-onpreviewframe-in-android
但就算不提「android.hardware.camera2」的複雜,傳入的照片資料結構本身跟「android.hardware.camera」的差異也非常大,如果要升級,光是改寫相機硬體與權限套件還不夠,還要連照片的轉檔也一併完成。
Android相機預設的檔案格式稱為YUV,它是種「用三種向量的方式來記錄圖片資料」的格式(完全無法理解怎麼實作),一共有420、422和444三種格式。(但也可以指定相機傳入舊格式檔案,但會造成「無法預覽」,自然也無法進行拍照。這格式的檔案在實用上功能有點不明。)
這檔案的格式技術細節未來需要慢慢補完。
Android使用這種格式的檔案奇妙之處在於:View元件本身幾乎都不支援這個格式的檔案,依然支援傳統RGB(Bitmap)或Drawalbe。
「android.hardware.camera」中取得的是YUV圖片的raw資料格式,也就byte矩陣檔。
但「android.hardware.caemra2」中經由「ImageReader」取得的是YUV圖片的資料格式封裝物件「Image」,這東西並不是YUV檔的實體,也無法直接轉成raw資料格式。
一個Image中有三層「Plane」,每一層都可以視為是對應「YUV」中的一種向量資料,因為是向量,所以每一張照片中的每一層Plane資料格式大小其實都不一定,跟RGB格式不一樣,只要知道的圖片長寬和格式,幾乎就可以順利估算出檔案大小或資料長度。
將Image物件格式轉成raw格式的演算法如下。三層ByteBuffer剛好是依序三層Plane的ByteBuffer資料。
// nv12: true = NV12, false = NV21
public static byte[] YUV_420_888toNV(ByteBuffer yBuffer, ByteBuffer uBuffer, ByteBuffer vBuffer, boolean nv12) {
byte[] nv;
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
nv = new byte[ySize + uSize + vSize];
yBuffer.get(nv, 0, ySize);
if (nv12) {//U and V are swapped
vBuffer.get(nv, ySize, vSize);
uBuffer.get(nv, ySize + vSize, uSize);
} else {
uBuffer.get(nv, ySize , uSize);
vBuffer.get(nv, ySize + uSize, vSize);
}
return nv;
}
但用QRCode Decode的套件:ZXing作測試,它可以接受「android.hardware.camera」的raw資料,但仍無法接收這個格式的資料。所以這個演算法還需要再檢討。
但奇妙的是:這個演算法獲得的raw格式資料確實可以轉成RGB格式檔案/Bitmap物件。
演算法如下。
public static byte[] NV21toJPEG(byte[] nv21, int width, int height, int quality) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuv = new YuvImage(nv21, ImageFormat.NV21, width, height, null);
yuv.compressToJpeg(new Rect(0, 0, width, height), quality, out);
return out.toByteArray();
}
參考連結
https://stackoverflow.com/questions/9325861/converting-yuv-rgbimage-processing-yuv-during-onpreviewframe-in-android