隻好自個 encode
了。
事由是這樣的,接到一個截圖需求(以
base64
輸出),但是在某個環境下,
Canvas.toDataURL
這個接口傳回的資料是錯誤的。
為此,寫一篇文章記錄一下,如何繞過
Canvas.toDataURL
,生成
base64
字元串。
以下為 Cocos官網文檔中給出的截圖事例代碼。https://docs.cocos.com/creator/manual/zh/render/camera.html#%E6%88%AA%E5%9B%BE

官網中的截圖代碼
幸運的是
readPixels()
能讀到位圖的像素資訊。
程式就是處理輸入和輸出的過程,為此,明确我們的輸入輸出。
- 輸入:
位圖資訊 和 圖檔寬高。data: Uint8Array
- 輸出:帶有圖檔資訊的
字元串。(可将該字元串放浏覽器中的位址欄,會傳回一張圖檔)base64
經思考?一番,決定采用以下幾步實作:
- 像素資料 -> 轉
資料 -> 轉JPG
base64
如何轉
JPG
格式?按照廠裡的方法,應該去了解其檔案格式如何生成,需要什麼頭檔案資訊,關于
JPEG
相關内容可參考wiki : https://en.wikipedia.org/wiki/JPEG
但?,在思考前,可以考慮是否有前任?的輪子。畢竟時間也是一種成本。
很快,很有型地在大型交友網站
github
中找到了前人留下的輪子。
https://github.com/jpeg-js/jpeg-js/blob/master/lib/encoder.js
這是
JavaScript
的代碼,白玉無冰這裡操作的是直接拷貝出來,放到一個
TypeScript
代碼中,導出
encodeJPG
方法。
搬運與改造 jpeg-js
再參考
jpeg-js
中的執行個體代碼,組織一下,很快就生成了
JPEG
的資料。
像素資料 轉 JPEG 資料
再把
JPEG
的資料中
Uint8Array
轉
base64
。
Uint8Array 轉 base64
但發現截圖反了。
截圖反了
最後,再對原來的資料翻轉一下,完整的核心代碼如下:
// 這樣我們就能從 RenderTexture 中擷取到資料了
let data = texture.readPixels();
let width = texture.width;
let height = texture.height;
// 接下來翻轉y的資料
const flipYData = new Uint8Array(width * height * 4);
let rowBytes = width * 4;
for (let row = 0; row < height; row++) {
let startRow = height - 1 - row;
let start = startRow * width * 4;
for (let i = 0; i < rowBytes; i++) {
flipYData[row * width * 4 + i] = data[start + i];
}
}
// 準備生成 jpegImageData
const rawImageData = {
data: flipYData,
width: width,
height: height,
};
const jpegImageData = encodeJPG(rawImageData, 50);
// jpeg -> base64
function uint8ToString(buf) {
var i, length, out = '';
for (i = 0, length = buf.length; i < length; i += 1) {
out += String.fromCharCode(buf[i]);
}
return out;
}
const base64 = btoa(uint8ToString(jpegImageData.data));
cc.warn('base64', "data:image/jpg;base64," + base64);
複制
完整代碼工程:https://github.com/baiyuwubing/cocos-creator-examples/tree/master/2.4.x/assets/demo06
以上為白玉無冰使用
Cocos Creator 2.4
實作
"截圖生成 base64"
的過程分享。