可以分享下你的toB64吗?
我的好像有问题,转出来的特别大而且没法还原成图片
这个解决了吗
用楼上大哥的方法可以
不用canvas 可以截屏吗 document.createElement(‘canvas’); 不用这个
大佬有demo吗?
原生版怎么截屏呢
请问,renderTex在哪里赋值的哈?有点懵
就new一下就行,随便哪里赋值。
new RenderTexture()
/**截屏base64格式 */
public static capture(): string {
if (xdSys.platform == xdPlatform.WEB ||
xdSys.platform == xdPlatform.XQWEB ||
xdSys.platform == xdPlatform.JSB) {
let node = xdUIUtil.getUICanvas();
let renderTex: RenderTexture = new RenderTexture();
let winSize = xdUIUtil.getViewSize();
renderTex.initialize({
width: Math.floor(winSize.width),
height: Math.floor(winSize.height),
})
let camera = node.getComponent(Canvas);
camera.targetTexture = renderTex;
director.root.pipeline.render([camera.camera.view]);
let data = this.copyRenderTex(renderTex);
camera.targetTexture = null;
return data;
}
return null;
}
private static copyRenderTex(renderTex: RenderTexture): string {
let arrayBuffer = new ArrayBuffer(renderTex.width * renderTex.height * 4);
let region = new GFXBufferTextureCopy();
region.texOffset.x = 0;
region.texOffset.y = 0;
region.texExtent.width = renderTex.width;
region.texExtent.height = renderTex.height;
director.root.device.copyFramebufferToBuffer(renderTex.window.framebuffer, arrayBuffer, [region]);
if (xdSys.platform == xdPlatform.JSB) {
let path = xdfile.getWritablePath() + 'capture.jpg';
this.saveImageData(arrayBuffer, renderTex.width, renderTex.height, path);
return path;
} else {
return this.toB64(arrayBuffer);
}
}
private static saveImageData(arrayBuffer: ArrayBuffer, w: number, h: number, path: string) {
let imageU8Data = new Uint8Array(arrayBuffer);
//翻转图片
let picData = new Uint8Array(w * h * 4);
let rowBytes = w * 4;
for (let row = 0; row < h; row++) {
let srow = h - 1 - row;
let start = srow * w * 4;
let reStart = row * w * 4;
// save the piexls data
for (let i = 0; i < rowBytes; i++) {
picData[reStart + i] = imageU8Data[start + i];
}
}
jsb.saveImageData(picData, w, h, path);
}
private static toB64(arrayBuffer: ArrayBuffer): string {
let canvas = document.createElement('canvas');
let winSize = xdUIUtil.getViewSize();
let width = canvas.width = Math.floor(winSize.width);
let height = canvas.height = Math.floor(winSize.height);
let ctx = canvas.getContext('2d');
let imageU8Data = new Uint8Array(arrayBuffer);
let rowBytes = width * 4;
let rowBytesh = height * 4;
for (let row = 0; row < rowBytesh; row++) {
let sRow = height - 1 - row;
let imageData = ctx.createImageData(width, 1);
let start = sRow * rowBytes;
for (let i = 0; i < rowBytes; i++) {
imageData.data[i] = imageU8Data[start + i];
}
ctx.putImageData(imageData, 0, row);
}
var base64 = canvas.toDataURL("image/jpeg", 0.7); //压缩语句
return base64;
}
2赞
请问这个 API 是你们自定义的 jsb 吗?
this.saveImageData(arrayBuffer, renderTex.width, renderTex.height, path);
另外在 3.x 版本构建的,放在原生上运行报错如下
arrayBuffer CCMTLDevice {__object_id__: 363, __native_class_name__: "CCMTLDevice", cachedUboOffsetAlignment: 256}
jsb-adapter/jsb-engine.js:2092 (see stack) Uncaught TypeError: i.device.copyFramebufferToBuffer is not a function - [0]copyRenderTex@assets/main/index.js:3
同问,这个原生截屏的功能解决了吗
是的。我们目前通过定制引擎解决了,官方 3.4 版本会支持
spriteframe.texture=rendertexture,这样的话当屏幕变化时,sprite也会跟着变化吧
能否分享一下在3.3.2上如何实现原生截屏的吗?
具体定制需要做什么操作呢?
引擎部分改动还好,新增 API,调用原生能力即可。大概是以下几步
- 通过 RT 获取到对应原生的实例
- 原生 iOS 对应 Metal、Android 对应 GLES3 或者其他
- 双端基于此使用原生代码做转图片的操作就好
注意点
- Android 在 GLES3 上的多线程问题,可考虑关闭多线程。否则获取到的图片不符合预期 参考:再不解决就要被炒鱿鱼:3.3.1 GLES3Texture getPixelBytes 获取到的结果是花屏
- 安卓端通过 GLES3 获取图片耗时卡顿的问题,需要在子线程完成处理,主线程回调
- iOS 15 上 Metal 获取到的图片,透明背景会存在异常颜色,可通过代码处理成透明色
其他目前倒没有太大的问题
GFXBufferTextureCopy
为啥我3.6.2没这个类呢
为啥我3.6也没看到官方支持呢????