En téléchargeant des images de tailles appropriées, les utilisateurs peuvent prévisualiser l'effet similaire à un diaporama en sélectionnant l'effet et la musique de l'animation de rendu, et enfin cliquer pour confirmer pour générer une vidéo, qui peut être lue sur les titres ou sur Douyin.
Solutions possibles pour générer des vidéosConversion d'encodage vidéo frontal pur (comme WebM Encoder Whammy)
Transmettez chaque image d'image au backend pour l'implémentation, et le backend appelle FFmpeg pour le transcodage vidéo.
La génération d'images peut être réalisée via l'interface native du canevas toDataURL et renvoie finalement les données d'image sous forme base64.
function generatePng() { var canvas = document.createElement('canvas'); let icavas = '#canvas' //Identifiant du canevas pour le rendu de l'animation if (wrapWidth == 2) { icavas = '#verticalCanvas' } var canvasNode = document .querySelector(icavas) toile.width = toileNode.width; toile.hauteur = toileNode.hauteur var ctx = canvas.getContext('2d'); ctx.drawImage(canvasNode, 0, 0); var imgData = canvas.toDataURL(image/png);Comment prendre des captures d'écran d'une animation sur toile
Utilisez setInterval pour exécuter régulièrement la méthode de génération d'image. Bien sûr, vous pouvez également utiliser requestAnimationFrame.
setInterval(function() { imgsTemp.push(generatePng())}, 1000/60)Comment obtenir chaque image d'image dans le backend
Solution 1 : le navigateur sans tête exécute l'animation de canevas frontal js, puis prend une capture d'écran du js
Idée initiale :
Les captures d'écran sont imprimées à l'aide de console.log. Les captures d'écran du canevas sont au format base64, une animation de 15 secondes, et il y a plus de 100 captures d'écran, ce qui a directement provoqué le crash du serveur (rejeté) ;
Plan d'essai :
La capture d'écran est stockée dans une variable js. Une fois l'animation jouée, un logo est ajouté à la page, puis le backend obtient la variable. Le code est le suivant :
const pages = { imageZoomOut : importer ('./image_zoom_inout.js'), //Zoomer imageArt : importer ('./image_art.js'), //Effacer imageGrid : importer ('./image_grid.js'), / /Grille imageRotate : importer ('./image_rotate.js'), //Ouvrir et fermer imageFlash : importer ('./image_flash.js'), //Image et texte flash imageVerticalArt : import ('./image_vertical_art.js'), //Effacement vertical imageVerticalGrid : import ('./image_vertical_grid.js'), //Grille verticale imageVerticalRotate : import ('. /image_vertical_rotate.js '), //Ouverture et fermeture verticales imageVerticalFlash : import ('./image_vertical_flash.js'), //Image verticale et texte flash imageVerticalZoomOut : import ('./image_vertical_zoom_inout.js'), //Zoom vertical imageVertical : import ('./image_vertical.js'), //Version verticale générale};var isShow = falsevar imgsBase64 = []var imgsTemp = []var cutInter = nullvar imgsTimeLong = 0function getQuerys(tag) { 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] == tag) { query.push(qitem); } else { spec[queryItem[0]] = qitem } } return { list: query, spec: spec };}var getQuery = getQuerys('images')var effectTag = getQuery.spec. tidvar wrapWidth = getQuery.spec.templateTypelet num = 0let imgArr = []function creatImg() { var images = getQuery.list let newImg = [] let vh = wrapWidth == 1 ? 360 : 640 let vw = wrapWidth == 1 640 : 360 if (effectTag.indexOf('Flash') > -1) { images.map(function (élément, index) { if (11 === index || 13 === index || 16 === index) { var temp = new Image(vw, vh) temp.setAttribute('crossOrigin', 'anonymous'); temp.src = item; newImg.push(temp) } else { newImg.push(item) } }) imgArr = newImg renderAnimate( effectTag) } else { images.map(function(item) { var temp = new Image(vw, vh) temp.setAttribute('crossOrigin', 'anonymous'); temp.src = item; temp.onload = function() { num++ if (num == images.length) { renderAnimate(effectTag) } } newImg.push(temp) }) imgArr = newImg }}fonction asynchrone renderAnimate(page) { //attendre creatImg() laissez-moi = cette const pageA = wait pages[page]; let oldDate = new Date().getTime() let icavas = '#canvas' if (wrapWidth == 2) { icavas = '#verticalCanvas' } let innerCanvas = document.querySelector(icavas) isShow = false pageA[page].render(null, { canvas: innerCanvas, images: imgArr }, function() { //Après la lecture de l'animation isShow = true; imgsTemp.push(generatePng()) imgsBase64.push(imgsTemp) let now = new Date().getTime() window.imgsTimeLong = now - oldDate clearInterval(cutInter) document.getElementById('cutImg').innerHTML = ' done'//Identification de la page}) cutInter = setInterval(function() { imgsTemp.push(generatePng()) if (imgsTemp.length >= 50) { imgsBase64.push(imgsTemp) imgsTemp = [] } }, 130)}fonction getImgs() { return imgsBase64}fonction generatePng() { var canvas = document.createElement('canvas'); laissez icavas = '#canvas' si (wrapWidth == 2) { icavas = '#verticalCanvas' } var canvasNode = document.querySelector(icavas) canvas.width = canvasNode.width; canvas.height = canvasNode.height; ; ctx.drawImage(canvasNode, 0, 0); canvas.toDataURL(image/png); return imgData;}window.imgsBase64 = imgsBase64 //Variable de stockage de capture d'écran creatImg()
Inconvénients du plan d’opération d’essai :
var temp = new Image(vw, vh)temp.setAttribute('crossOrigin', 'anonymous');Solution finale : exécuter l'animation côté NODE
Utilisez node-canvas pour écrire chaque capture d'écran d'image dans le dossier spécifié à l'aide de fs.writeFile
const { createCanvas, loadImage} = require(canvas); const pages = { imageZoomOut: require('./image_zoom_inout.js'), //Zoom imageArt: require('./image_art.js'), //Effacer imageGrid : require('./image_grid.js'), //Grille imageRotate : require('./image_rotate.js'), //Ouvrir et fermer imageFlash : require('./image_flash.js'), //Image et texte flash imageVerticalArt : require('./image_vertical_art.js'), //Effacement vertical imageVerticalGrid : require('./image_vertical_grid . js'), //grille verticale imageVerticalRotate : require('./image_vertical_rotate.js'), //grille verticale imageVerticalFlash : require('./image_vertical_flash.js'), //image verticale et texte flash imageVerticalZoomOut: require('./image_vertical_zoom_inout.js'), //zoom vertical imageVertical: require('./image_vertical.js'), // Général pour la version verticale};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 //hauteur du canevas let vw = parse.templateType == 1280 : 720 //largeur du canevas let imgSrcArray = parse.images //Tableau d'images let effectTag = parse.tid //Effet d'animation let saveImgPath = process.argv && process.argv[3]let loadArr = []imgSrcArray.forEach(element => { if (//.(jpg|jpeg|png|JPG|PNG)$/.test(element)) { loadArr.push(loadImage(element)) } else { loadArr.push(element) }});const canvas = createCanvas(vw, vh);const ctx = canvas.getContext(2d);Promise.all(loadArr) .then((images) => { //Initialiser l'animation console.log('Démarrer l'animation') let oldDate = new Date ().getTime() pages[effectTag].render(null, { canvas: canvas, images: images }, function() { clearInterval(interval) let now = new Date().getTime() console.log(now - oldDate, 'L'animation se termine') }) const interval = 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, return }) ; 1000 / 60 ); }) .catch(e => { console.log(e); });
Exécutez la commande suivante sous iterm
nœud testCanvas.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 =../cul 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' './images/'
Description du paramètre :
1) tid est le nom de l'animation
2) le type de modèle est la taille : 1 : 1 280 * 720 ; 2 : 720 * 1 280 ;
3) images est l'adresse de l'image
4) La variable './images/' est l'adresse où la capture d'écran est enregistrée,
Inconvénients de l'exécution dans un environnement NODEBouclez le dessin suivant toutes les 13 secondes :
pour (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.hauteur), p.restore(), p.closePath(); pour (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, y.width, y.height), p.restore(), p.closePath();
En raison du modèle de boucle d'événements de Node.js, l'utilisation de Node.js doit garantir que le cycle de Node.js peut s'exécuter à tout moment. Si une fonction très chronophage apparaît, la boucle d'événements restera bloquée et ne pourra pas être gérée. d'autres tâches dans le temps, donc par conséquent, certaines animations sont encore lentes
Possibilité d'optimisation ultérieureEssayez d'utiliser le langage Go pour prendre des captures d'écran ;
Réécrire l'animation du canevas ;
supplémentaire Débit vidéoLe débit vidéo est le nombre de bits de données transmis par unité de temps lors de la transmission de données. Généralement, l'unité que nous utilisons est le kbps, soit des milliers de bits par seconde. Une compréhension simple est le taux d'échantillonnage. Plus le taux d'échantillonnage par unité de temps est élevé, plus la précision est élevée et plus le fichier traité est proche du fichier d'origine. Par exemple, pour un fichier audio, plus le débit binaire est élevé, plus le taux de compression est faible, plus la perte de qualité sonore est faible et plus la qualité sonore est proche de la source audio.
Images FPS par seconde (Frames Per Second))
FPS est une définition dans le domaine du graphisme, qui fait référence au nombre d'images transmises par seconde. De manière générale, il s'agit du nombre d'images d'animation ou de vidéo. Le FPS est une mesure de la quantité d'informations utilisée pour enregistrer et afficher une vidéo dynamique. Plus il y a d’images par seconde, plus l’action affichée est fluide. Généralement, le minimum pour éviter les mouvements saccadés est de 30. Par exemple, un film est lu à une vitesse de 24 images par seconde, ce qui signifie que 24 images fixes sont projetées en continu sur l'écran en une seconde.
Ce qui précède représente l’intégralité du contenu de cet article. J’espère qu’il sera utile à l’étude de chacun. J’espère également que tout le monde soutiendra le réseau VeVb Wulin.