YUV 400 格式圖像轉換成 ARGB 格式圖像中犯的一個低級 Bug

一、背景

    最近在做 Android 巴槍項目,藉助巴槍上面的二維掃描頭拍照,然後去做 OCR。這屬於定製需求,只能去和各個巴槍廠家去對接。後來廠家陸續暴露給了我們這個能力,但是接口都不一樣(領教了 Android 的碎片化)。這個 Bug 就出在我適配一款巴槍的過程中。

二、Bug

    這個廠家的 SDK 設計是通過回調的方式把圖片數據返回給我。只有一個 byte 數組,不知道寬、高,不知道格式(ARGB、YUV),沒有文檔,只能去問他們的開發,溝通成本很高。最後問得寬是 1280,高是 960,格式是 YUV 400(只有 Y 通道數據)。我需要把這個數據轉成 jpeg 格式的數據,上傳到雲端,識別並留底。問題來了,我轉成 jpeg 格式之後先存儲到了本地,驗證格式轉換這一步是成功的。發現存儲的圖片是無法打開的,一直報錯“文件格式不支持”。我的轉換代碼如下:

// data 是 yuvData
int[] pixels = new int[width * height];
for (int y = 0; y < height; y++)
{
    for (int x = 0; x < width; x++)
    {
        int index = y * width + x;
        // !!! Y 到 ARGB 的快速轉換
        int grey = data[index] & 0xff;
        pixels[index] = 0xFF000000 | (grey * 0x00010101);
    }
}

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

Bitmap bitmap = Bitmap.createBitmap(width, height,
        Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);

byte[] jpegData = byteArrayOutputStream.toByteArray();
try {
    byteArrayOutputStream.close();
} catch (IOException e) {
    e.printStackTrace();
}

    grey * 0x00010101 等同於 grey << 16 | grey << 8 | grey,效果是灰度值是 120 的話,轉化成的 rgb 值是(120,120,120)。

三、調試

    開始懷疑廠家給的 yuvData 有問題。yuvData 數組確實多了 20 個字節的數據,1280*960=1228800,而數組長度是 1228820,值得懷疑。不過和對方的開發溝通,說後 20 個字節是空的,不會影響。分析一下數組只要長度不短,長度更長或者內容不對應該都不會導致圖片打不開,內容不對只會導致圖片打開之後看起來不對。

    單步調試,查看中間結果,沒有發現問題。其中 bitmap 這個中間結果用 ImageView 展示出來看也是正常的。(把中間結果輸出出來、展示出來,二分法定位問題所在,很有用。白盒調試。而不是黑盒的在那裏猜猜猜。)

    寫文件這裏門板代碼,出問題的概率不大。

    最後不知道怎麼想起來的,懷疑是不是這個巴槍打不開而已,文件本身是沒問題。

    事實證明確實是這個問題。而是隻是文件管理 App 打不開而已,下載個 Google Photo 是可以打開的。也是我先入爲主,適配的上一款巴槍文件管理 App 是可以打開的。到了這款巴槍,打不開了,我馬上懷疑是文件損壞了。

    總結:越難解的 Bug 可能越低級

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章