我的 JavaScript 代码中有一个函数,可以从视频流中捕获图像并将其保存为文件。在 mediaRecorder.onstop 事件处理程序中,我将捕获的图像转换为文件格式,然后转换为数据 URL。现在,我想操作该图像文件的元标记,并添加一个带有键“Source”和值“CameraTest”的自定义元标记。然而,我使用“piexif”库的尝试并没有成功。
在 mediaRecorder.onstop 事件处理程序中,将图像转换为文件和数据 URL 后,我尝试使用“piexif”库来操作 EXIF 数据并添加自定义元标记,但遇到了困难。有没有办法在 JavaScript 或任何其他库或方法中实现元标记的这种操作?
任何帮助或见解将不胜感激。谢谢!
功能:
const captureImageManual = async () => {
if (canvasRef && canvasRef.current && mediaStream && !captureTimer) {
/* Record Video */
const blobsRecorded: Blob[] = [];
// Check if mime type is supported by browser
for (let index = 0; index < mimeTypes.length; index += 1) {
const isSupported = MediaRecorder.isTypeSupported(mimeTypes[index].mime);
if (isSupported) {
supportedMimeType.current = mimeTypes[index];
break;
}
}
if (!supportedMimeType?.current?.mime) {
console.log('No valid video mime type supported by browser');
toast.error('This browser is not supported for KYC. Please try again using a different browser.');
Sentry.captureException({
error: new Error('No valid video mime type supported by browser'),
message: 'This browser is not supported for KYC. Please try again using a different browser.',
});
return;
}
// set MIME type of recording as the first supported mime type found
const mediaRecorder = new MediaRecorder(mediaStream, { mimeType: supportedMimeType.current.mime });
// event : new recorded video blob available
mediaRecorder.ondataavailable = (event) => {
console.log('event data: ', event.data);
blobsRecorded.push(event.data);
};
// event : recording stopped & all blobs sent
mediaRecorder.onstop = async () => {
// // create local object URL from the recorded video blobs
// const videoLocal = URL.createObjectURL(new Blob(blobsRecorded, { type: 'video/mp4' }));
// Convert BLOB to File
const recordedVideoFile = new File(blobsRecorded, 'video', { type: supportedMimeType.current?.mime });
setVideoFile(recordedVideoFile);
/* Capture Photo */
// Add to canvas element
// const xMultiplier = videoRef.current.videoWidth / videoRef.current.clientWidth;
// const yMultiplier = videoRef.current.videoHeight / videoRef.current.clientHeight;
canvasRef.current.height = videoRef?.current?.videoHeight;
canvasRef.current.width = videoRef?.current?.videoWidth;
canvasRef?.current
?.getContext('2d')
?.drawImage(videoRef.current, 0, 0, videoRef?.current?.videoWidth, videoRef?.current?.videoHeight);
// const dimension = isDesktop ? (window.innerWidth / 100) * 20 : 260;
// const dimension = holeRef?.current?.clientWidth;
// canvasRef?.current?.getContext('2d')?.drawImage(
// videoRef.current, // image
// (videoRef.current.clientWidth / 2) * xMultiplier - (dimension / 2) * xMultiplier, // sx
// 32 * yMultiplier, // sy
// dimension * xMultiplier, // sWidth
// dimension * yMultiplier, // sHeight
// 0, // dx
// 0, // dy
// canvasRef.current.width, // dWidth
// canvasRef.current.height, // dHeight
// );
const imageDataUrl = canvasRef.current.toDataURL('image/jpeg');
setCapturedImageUrl(imageDataUrl);
// Convert to File
const res: Response = await fetch(imageDataUrl);
const blob: Blob = await res.blob();
const capturedImageFile = new File([blob], 'selfie', { type: 'image/jpeg' });
//
const exifIfd: any = {};
exifIfd[piexif.ExifIFD.DateTimeOriginal] = '2010:10:10 10:10:10';
exifIfd[piexif.ExifIFD.LensMake] = 'Lens Maker';
exifIfd[piexif.ExifIFD.Sharpness] = 777;
exifIfd[piexif.ExifIFD.LensSpecification] = [
[1, 1],
[1, 1],
[1, 1],
[1, 1],
];
// exifIfd['Source'] = 'CameraTestPotlee';
const exifBytes = piexif.dump({ Exif: exifIfd });
const exifModified = piexif.insert(exifBytes, imageDataUrl);
setSrc(exifModified);
console.log({ exifModified });
// const newFile = await writePNGtext(capturedImageFile, 'Source', 'CameraTestPotlee');
// const buffer = new Uint8Array([newFile]);
// const blobx = new Blob([buffer], { type: 'image/png' }); // Specify the file type
// const filex = new File([blobx], 'selfie', { type: 'image/png' }); // Specify filename and type
// const exifrParse = await exifr.parse(filex);
// const metaTags = await EXIF.getAllTags(filex);
// console.log({ metaTags });
setSelfieFile(capturedImageFile);
};
// event : recording started
mediaRecorder.onstart = () => {
// Capture button timer
setCaptureTimer(3);
interval.current = setInterval(() => {
setCaptureTimer((state) => {
if (state > 0) {
return state - 1;
}
return state;
});
}, 1000);
// Stop recording after 3 seconds
setTimeout(() => {
mediaRecorder.stop();
}, 3000);
setNewImage(true);
};
// start recording with each recorded blob having 1 second video
mediaRecorder.start(1000);
}
};
我尝试使用不同的库,例如:piexifjs、exif-js、exifr、image-metadata-editor 但大多数情况下我无法添加任何自定义标签。
是的,您可以使用 JavaScript 将自定义元标记添加到从网络摄像头捕获的图像文件中。然而,需要注意的是,JavaScript 本身并不直接提供操作图像文件元数据的方法。相反,您通常需要结合使用 JavaScript 和服务器端技术来实现此目的。
这是完成此任务的一般方法:
捕获图像:使用 JavaScript 从网络摄像头捕获图像,使用 getUserMedia() 函数等 API 来访问用户的相机和 Canvas 来绘制捕获的图像。
创建元数据:收集要添加到图像的自定义元数据。这可能包括用户姓名、时间戳、位置或任何其他相关数据等信息。
将图像和元数据发送到服务器:使用 JavaScript 将捕获的图像数据以及自定义元数据发送到服务器。您可以使用 AJAX 请求或表单提交等技术来异步发送数据。
服务器端处理:在服务器端(使用Node.js、PHP、Python等服务器端语言)接收图像和元数据。使用库或工具来操作图像文件的元数据。例如,在 Node.js 中,您可以使用 exiftool 或 exifr 等库来添加或修改元数据。
使用元数据保存图像:将元数据添加到图像文件后,将修改后的图像文件保存到您所需的位置,例如数据库或文件系统。
提供带有元数据的图像:最后,如果需要,可以将带有添加的元数据的图像文件提供给请求它的客户端。
请记住,由于安全限制和浏览器 API 的限制,单独在客户端(使用 JavaScript)操作图像元数据可能是不可能的。因此,通常最好在服务器端处理此任务,这样您可以更好地控制和访问适当的图像处理工具和库。