Al cargar una imagen del tamaño apropiado, los usuarios pueden obtener una vista previa del efecto similar a una presentación de diapositivas seleccionando el efecto y la música de la animación renderizada y, finalmente, hacer clic para confirmar para generar un video, que se puede reproducir en titulares o Douyin.
Posibles soluciones para generar vídeos.Conversión pura de codificación de video front-end (como WebM Encoder Whammy)
Pase cada cuadro de imagen al backend para su implementación, y el backend llama a FFmpeg para la transcodificación de video.
La generación de imágenes se puede lograr a través de la interfaz nativa del lienzo toDataURL y, en última instancia, devuelve datos de imagen en formato base64.
function generatePng() { var canvas = document.createElement('canvas'); let icavas = '#canvas' //Id. del lienzo para representar la animación if (wrapWidth == 2) { icavas = '#verticalCanvas' } var canvasNode = document .querySelector(icavas) lienzo.ancho = lienzoNodo.ancho; lienzo.altura = lienzoNodo.altura var ctx; canvas.getContext('2d'); ctx.drawImage(canvasNode, 0, 0); var imgData = canvas.toDataURL(image/png);Cómo tomar capturas de pantalla de la animación del lienzo
Utilice setInterval para ejecutar el método de generación de imágenes con regularidad. Por supuesto, también puede utilizar requestAnimationFrame.
setInterval(función() { imgsTemp.push(generarPng())}, 1000/60)Cómo obtener cada cuadro de imagen en el backend
Solución 1: el navegador sin cabeza ejecuta el js de animación del lienzo frontal y luego toma una captura de pantalla del js.
Idea inicial:
Las capturas de pantalla se imprimen usando console.log. Las capturas de pantalla del lienzo están en formato base64, una animación de 15 segundos y hay más de 100 capturas de pantalla, lo que provocó directamente que el servidor fallara (rechazado);
Plan de ejecución de prueba:
La captura de pantalla se almacena en una variable js. Después de reproducir la animación, se agrega un logotipo a la página y luego el backend obtiene la variable.
páginas const = { imageZoomOut: import ('./image_zoom_inout.js'), //Zoom imageArt: import ('./image_art.js'), //Borrar imageGrid: import ('./image_grid.js'), / /Grid imageRotate: importar ('./image_rotate.js'), //Abrir y cerrar imageFlash: importar ('./image_flash.js'), //Imagen y texto flash imageVerticalArt: import ('./image_vertical_art.js'), //Borrado vertical imageVerticalGrid: import ('./image_vertical_grid.js'), //Cuadrícula vertical imageVerticalRotate: import ('. /image_vertical_rotate.js '), //Apertura y cierre vertical imageVerticalFlash: import ('./image_vertical_flash.js'), //Imagen vertical y texto flash imageVerticalZoomOut: import ('./image_vertical_zoom_inout.js'), //Zoom vertical imageVertical: import ('./image_vertical.js'), //Versión vertical general};var isShow = falsevar imgsBase64 = []var imgsTemp = []var cutInter = nullvar imgsTimeLong = 0función getQuerys(etiqueta) { let queryStr = window.location.search.slice(1); let queryArr = queryStr.split('&'); let query = []; let spec = {} for (let i = 0, len = queryArr.length; i < len ; i++) { let queryItem = queryArr[i].split('='); let qitem = decodeURIComponent(queryItem[1]) if (queryItem[0] == etiqueta) { consulta.push(qitem); } else { especificación[queryItem[0]] = qitem } } return { lista: consulta, especificación: especificación };}var getQuery = getQuerys('images')var effectTag = getQuery.spec. tidvar wrapWidth = getQuery.spec.templateTypelet num = 0let imgArr = []function creatImg() { var imágenes = getQuery.list let newImg = [] let vh = wrapWidth == 1? 360: 640 let vw = wrapWidth == 1? (elemento, índice) { if (11 === índice || 13 === índice || 16 === índice) { var temp = nueva Imagen(vw, vh) temp.setAttribute('crossOrigin', 'anonymous'); temp.src = item; newImg.push(temp) } else { newImg.push(item) } }) imgArr = newImg renderAnimate( effectTag) } else { imágenes.map(función(elemento) { var temp = nueva Imagen(vw, vh) temp.setAttribute('crossOrigin', 'anonymous'); temp.src = item; temp.onload = function() { num++ if (num == imágenes.length) { renderAnimate(effectTag) } } newImg.push(temp) }) imgArr = newImg }}función asíncrona renderAnimate(página) { //espera creatImg() déjame = esta página constanteA = await páginas[página]; let oldDate = new Date().getTime() let icavas = '#canvas' if (wrapWidth == 2) { icavas = '#verticalCanvas' } let internalCanvas = document.querySelector(icavas) isShow = false pageA[page].render(null, { canvas: insideCanvas, images: imgArr }, function() { //Después de reproducir la animación isShow = true; imgsTemp.push(generatePng()) imgsBase64.push(imgsTemp) let now = new Date().getTime() window.imgsTimeLong = now - oldDate clearInterval(cutInter) document.getElementById('cutImg').innerHTML = ' hecho'//Identificación de página}) cutInter = setInterval(function() { imgsTemp.push(generatePng()) if (imgsTemp.length >= 50) { imgsBase64.push(imgsTemp) imgsTemp = [] } }, 130)}function getImgs() { return imgsBase64}function generatePng() { var canvas = document.createElement('canvas'); let icavas = '#canvas' si (wrapWidth == 2) { icavas = '#verticalCanvas' } var canvasNode = document.querySelector(icavas) canvas.width = canvasNode.width lienzo.height = canvasNode.height var ctx = canvas.getContext('2d') ctx.drawImage(canvasNode, 0, 0); canvas.toDataURL(image/png); return imgData;}window.imgsBase64 = imgsBase64 //Variable de almacenamiento de captura de pantalla creatImg()
Desventajas del plan de operación de prueba:
var temp = nueva Imagen(vw, vh)temp.setAttribute('crossOrigin', 'anonymous');Solución final: ejecutar animación en el lado del NODO
Utilice node-canvas para escribir cada captura de pantalla del cuadro en la carpeta especificada usando fs.writeFile
const { createCanvas, loadImage} = require(canvas); const páginas = { imageZoomOut: require('./image_zoom_inout.js'), //Zoom imageArt: require('./image_art.js'), //Borrar imageGrid: require('./image_grid.js'), //Grid imageRotate: require('./image_rotate.js'), //Abrir y cerrar imageFlash: require('./image_flash.js'), //Imagen y texto flash imageVerticalArt: require('./image_vertical_art.js'), //Borrado vertical imageVerticalGrid: require('./image_vertical_grid . js'), //imagen de cuadrícula verticalVerticalRotate: require('./image_vertical_rotate.js'), //imagen de cuadrícula verticalVerticalFlash: require('./image_vertical_flash.js'), //Imagen vertical y texto flash imageVerticalZoomOut: require('./image_vertical_zoom_inout.js'), //Zoom vertical imageVertical: require('./image_vertical.js'), // General para la versión vertical};const fs = require(fs);const querystring = require('querystring');let args = process.argv && Process.argv[2]let parse = querystring.parse(args)let vh = parse.templateType == 1 ? 720: 1280 //alto del lienzo let vw = parse.templateType == 1 ? let imgSrcArray = parse.images // Matriz de imágenes let effectTag = parse.tid // Efecto de animación let saveImgPath = proceso.argv && proceso.argv[3]let loadArr = []imgSrcArray.forEach(elemento => { if (//.(jpg|jpeg|png|JPG|PNG)$/.test(elemento)) { loadArr.push(loadImage(elemento)) } else { loadArr.push(elemento) }});const lienzo = createCanvas(vw, vh);const ctx = canvas.getContext(2d);Promise.all(loadArr) .then((images) => { //Inicializar animación console.log('Iniciar animación') let oldDate = new Date ().getTime() páginas[effectTag].render(null, { lienzo: lienzo, imágenes: imágenes }, función() { clearInterval(interval) let now = new Date().getTime() console.log(now - oldDate, 'Fin de la animación') }) const intervalo = setInterval( (function() { let x = 0; return () => { x += 1; ctx. canvas.toDataURL('image/jpeg', function(err, png) { if (err) { console.log(err); return; } let data = png.replace(/^data:image///w+;base64,/, ''); let buf = new Buffer(data, 'base64'); `, buf, {}, (err) => { console.log(x, err) } }); 1000/60); }) .catch(e => { console.log(e); });
Ejecute el siguiente comando en iterm
prueba de nodoCanvas.js 'tid=imageArt&templateType=1&images=../assets/imgs/8.png&images=../assets/imgs/6.png&images=../assets/imgs/7.png&images=../assets/imgs/6.png&images =../culo ets/imgs/8.png&images=../assets/imgs/7.png&images=../assets/imgs/4.png&images=../assets/imgs/6.png&images=../assets/imgs/8. png&images=../assets/imgs/7.png' './imágenes/'
Descripción del parámetro:
1) tid es el nombre de la animación
2) el tipo de plantilla es el tamaño: 1:1280*720;
3) imágenes es la dirección de la imagen
4) La variable './images/' es la dirección donde se guarda la captura de pantalla,
Desventajas de ejecutar en entorno NODEEl siguiente dibujo se repite cada 13 segundos:
para (var A = 0; 50 > A; A++) p.beginPath(), p.globalAlpha = 1 - A / 49, p.save(), p.arc(180,320,P + 2 * A, 0, 2 * Math.PI), p.clip(), p.drawImage(x[c], 0, 0, y.width, y.height), p.restore(), p.closePath(); para (var S = 0; 50 > S; S++) p.beginPath(), p.globalAlpha = 1 - S / 49, p.save( ), p.rect(0, 0, d + P + 2 * S, g + b + 2 * S), p.clip(), p.drawImage(x[c], 0, 0, ancho y, altura y), p.restore(), p.closePath();
Debido al modelo de bucle de eventos de Node.js, el uso de Node.js debe garantizar que el ciclo de Node.js pueda ejecutarse en todo momento. Si aparece una función que requiere mucho tiempo, el bucle de eventos se atascará y no podrá manejarse. otras tareas a tiempo, por lo que algunas animaciones siguen siendo lentas.
Posibilidad de optimización posterior.Intente utilizar el idioma Go para realizar capturas de pantalla;
Reescribir la animación del lienzo;
extra Velocidad de bits de vídeoLa velocidad de bits de video es la cantidad de bits de datos transmitidos por unidad de tiempo durante la transmisión de datos. Generalmente, la unidad que utilizamos es kbps, que son miles de bits por segundo. Una comprensión simple es la frecuencia de muestreo. Cuanto mayor sea la frecuencia de muestreo por unidad de tiempo, mayor será la precisión y más cerca estará el archivo procesado del archivo original. Por ejemplo, para un audio, cuanto mayor sea la velocidad de bits, menor será la relación de compresión, menor será la pérdida de calidad del sonido y más cercana estará la calidad del sonido a la fuente de audio.
Cuadros por segundo FPS (Cuadros por segundo)
FPS es una definición en el campo de los gráficos, que se refiere a la cantidad de cuadros transmitidos por segundo. En general, se refiere a la cantidad de cuadros de animación o video. FPS es una medida de la cantidad de información utilizada para guardar y mostrar video dinámico. Cuantos más fotogramas por segundo, más fluida se mostrará la acción. Normalmente, el mínimo para evitar movimientos bruscos es 30. Por ejemplo, una película se reproduce a una velocidad de 24 fotogramas por segundo, lo que significa que se proyectan continuamente 24 fotogramas fijos en la pantalla en un segundo.
Lo anterior es el contenido completo de este artículo. Espero que sea útil para el estudio de todos. También espero que todos apoyen VeVb Wulin Network.