ユニアプリのビデオスクリーンショット
この記事では WeChat ミニ プログラムのみに焦点を当てており、他のプラットフォームではテストされていないため、実現可能性は不明です。
WeChat は、ビデオを再生するための 2 つのコンポーネントを提供します。
live-player
: リアルタイムのオーディオとビデオの再生に使用される限り (ポリシーとコンプライアンスの考慮事項により、WeChat は<live-player>
すべてのミニ プログラムでのタグのサポートをまだリリースしていません。詳細については公式ドキュメントを確認してください)。video
: 動画を再生します。
コンポーネントを使用してlive-player
スクリーンショットを撮る
インスタンスには、スクリーンショットを撮るために呼び出すことができるLivePlayerContext
メソッドがありますsnapshot
。
疑似コードの例:
<live-player id="myVideo" src="xxxx" :autoplay="isPlay" mode="live"></live-player>
// 获取live-player上下文对象
const ctx = wx.createLivePlayerContext('#myVideo');
ctx.play({
success: () => {
// 确保视频播放成功才进行截图
ctx.snapshot({
success: res => {
wx.saveImageToPhotosAlbum({
filePath: res.tempImagePath,
success: () => {
console.log('save success');
},
fail: () => {
console.log('save fail');
},
})
},
fail: () => {
console.log('snapshot fail');
}
})
}
});
上記の疑似コードは、スクリーンショットを撮り、携帯電話にスクリーンショットを保存する方法を説明しています。
コンポーネントを使用してvideo
スクリーンショットを撮る
video
コンポーネント自体は、show-snapshot-button
スクリーンショットを撮るのに役立つコントロール ( ) を提供しますが、このコントロールは全画面モードでのみ表示されます。公式ドキュメントを確認してください。
<video id="myVideo" style="width: 100%;height: 200px"
src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400"
object-fit="fill" show-snapshot-button controls />
下の写真からわかるように、右側にカメラのアイコンがあるので、クリックしてスクリーンショットを撮り、携帯電話にダウンロードします。
ただし、非全画面状態では、スクリーンショット コントロールは表示されず、VideoContext
オブジェクトはスクリーンショット メソッドを公開しません。
キャンバスを使用する
このオブジェクトはスクリーンショット メソッドを提供しておらずVideoContext
、非全画面状態で取得することはできませんが、これを使用してcanvas
スクリーンショット メソッドを手動で実装することもできます。
<video id="myVideo" style="width: 100%;height: 200px"
src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400"
object-fit="fill" show-snapshot-button controls />
<canvas id="hiddenCanvas" style="width: 100%; height: 200px;" type="2d" canvas-id="circleCanvas"></canvas>
<button @tap="snapshot">截图</button>
このときのページ効果は以下の通りです
// 获取video上下文
const getVideoContext = (id, instance) => {
const query = uni.createSelectorQuery().in(instance);
const queryVideo = query.select(`#${
id}`).context();
return new Promise((resolve, reject) => {
queryVideo.exec(res => {
resolve(res);
});
});
}
async record() {
const query = wx.createSelectorQuery()
query.select('#hiddenCanvas')
.fields({
node: true,
size: true
})
.exec(async (res) => {
const canvas = res[0].node;
const dpr = uni.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr // 获取宽
canvas.height = res[0].height * dpr // 获取高
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr)
const video = await getVideoContext('myVideo', this);
console.log(video)
ctx.drawImage(video[0].context, 0, 0);
})
}
保存する方法を追加します
async record() {
const query = wx.createSelectorQuery()
query.select('#hiddenCanvas')
.fields({
node: true,
size: true
})
.exec(async (res) => {
const canvas = res[0].node;
const dpr = uni.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr // 获取宽
canvas.height = res[0].height * dpr // 获取高
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr)
const video = await getVideoContext('myVideo', this);
console.log(video)
ctx.drawImage(video[0].context, 0, 0);
// 从canvas获取图片像素数据
const imgData = canvas.toDataURL('image/png');
this.saveImage(imgData);
})
}
function saveImage(url) {
let base64 = url.replace(/^data:image\/\w+;base64,/, ""); //去掉data:image/png;base64,
let filePath = wx.env.USER_DATA_PATH + '/video.png';
uni.getFileSystemManager().writeFile({
filePath: filePath, //创建一个临时文件名
data: base64, //写入的文本或二进制数据
encoding: 'base64', //写入当前文件的字符编码
success: res => {
console.log(res);
uni.saveImageToPhotosAlbum({
filePath: filePath,
success: () => {
console.log('保存成功')
},
fail: err => {
console.log('保存失败')
}
})
}
})
}
次に、スクリーンショットをクリックして携帯電話に直接保存します。
ページ上に表示する必要はないかもしれません。非表示にcanvas
直接設定するとエラーが発生します。このとき、絶対位置を指定した後、ビュー レイヤー全体をビュー レイヤーの外に移動するために使用できます (たとえば、表示が画面範囲を超えるように比較的大きな値を指定します。)。display:none
saveImageToPhotosAlbum:fail save fail:Error Domain=PHPhotosErrorDomain Code=3302 "(null)"
position:absolute;
canvas
left
canvas