我希望你騎著>機車離開這裡,沿著這條河一直到大海邊。
已經連續寫了五篇zxing的學習筆記了,剛開始寫的時候,只是想簡簡單單的記錄下自己在學習android過程積累的點滴,卻沒想到寫著寫著變成了好像在向某人訴說自己一點淺薄的理解似的。回頭來看這些稚嫩的筆記,發現思維邏輯有點混亂,講述的雜亂無章,沒達要點。不求全面,但求透徹。在寫這些隨筆的過程,又更多的理解了Barcode scanner的設計,弄懂了之前很多的一知半解,尤其是理所當然的潛在錯誤認知,所謂的眼高手低。View,Camera,thread,looper我都再次認真的查閱資料,謹慎的看了多遍,當心自己寫錯,新年我願慢慢進步。
言歸正傳。
在使用Barcode Scanner掃描GB2312編碼的qr碼,掃描結果會出現亂碼,無法正常顯示。之所以會出現這個問題,我通過跟蹤調試後找到在DecodedBitStreamParser類裡面完成了對原始的bytes進行瞭解析,這個代碼有很多沒明白,通過打日誌知道了代碼啟動並執行軌跡。通過對二十多張不同編碼方式的qr圖掃描分析的結果,發現大部分都通過調用decodeByteSegment進行解析,其中會調用函數StringUtils.guessEncoding(byte[] bytes, Hashtable hints)來對編碼方式進行猜測,hits中可以指定使用的編碼方式,如果沒有指定則猜測。
1 // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS,
2 // which should be by far the most common encodings. ISO-8859-1
3 // should not have bytes in the 0x80 - 0x9F range, while Shift_JIS
4 // uses this as a first byte of a two-byte character. If we see this
5 // followed by a valid second byte in Shift_JIS, assume it is Shift_JIS.
6 // If we see something else in that second byte, we'll make the risky guess
7 // that it's UTF-8.
這部分是代碼中對編碼方式猜測的基本方法。缺少對GB2312的猜測。GB2312使用兩個位元組來進行編碼。第一個位元組的範圍在(0xB0,0xF7),緊接著的第二個位元組的範圍在(0xA0,0xF7)。根據GB2312的這個編碼規則,可以進行一個簡單的判斷,解決掃描GB2312編碼的qr圖亂碼問題。
1 for (int i = 0; i < length; i++) {
2 int value = bytes[i] & 0xFF;
3 if (value > 0x7F)// 如果大於127,則可能是GB2312,就開始判斷該位元組,和下一個位元組
4 {
5 if (value > 0xB0 && value <= 0xF7)// 第一個位元組再此範圍內,則開始判斷第二個自己
6 {
7 int value2 = bytes[i + 1] & 0xFF;
8 if (value2 > 0xA0 && value2 <= 0xF7)
9 {
10 return true;
11 }
12 }
13 }
14 }
以上是一個簡單的判斷,通過加入到guesscoding中後可以正確的識別出GB2312編碼的qr圖。但感覺這樣的方法還是比較低效率的,沒有真正融合到zxing的源碼中。需要再一步的思考。
前面有一篇關於camera旋轉的問題,如果將拍照轉為豎屏,除了在manifest中指定該activity的方向外,還需要camera.setDisplayOrientation(90),調整預覽時的方向。但是camera取的資料還是原來的橫屏的朝向,如果在對圖片進行分析前沒有對圖片做一個旋轉的操作,則圖片最後儲存下來,會發現它是橫的,並且那些ResultPoint也無法正確的標記出qr圖上的特徵點。今天看到一個文章,解決了這個問題,看這個文章請點這裡。
其中最關鍵的代碼是再DecodeHandler.java中得decode函數調用buildLuminanceSource函數前進行如下的一個旋轉。
1 byte[] rotatedData = new byte[data.length];
2 for (int y = 0; y < height; y++) {
3 for (int x = 0; x < width; x++)
4 rotatedData[x * height + height - y - 1] = data[x + y * width];
5 }
這樣就解決了ResultPoint點標記的不正確的問題,當然除了設定方向,旋轉資料,還需要調整下view的布局,使掃描框看上去更協調。
今天是年前最後一天上班了,關於zxing的學習筆記也暫告一個段落,來年再更新。
願新年龍行天下。