Durch das Hochladen eines Bilds in geeigneter Größe können Benutzer den Effekt ähnlich einer Diashow in der Vorschau anzeigen, indem sie den Effekt und die Musik der Rendering-Animation auswählen und schließlich zur Bestätigung klicken, um ein Video zu erstellen, das in Schlagzeilen oder Douyin abgespielt werden kann.
Mögliche Lösungen zur Erstellung von VideosReine Front-End-Videokodierungskonvertierung (z. B. WebM Encoder Whammy)
Übergeben Sie jedes Bildbild zur Implementierung an das Backend, und das Backend ruft FFmpeg zur Videotranskodierung auf.
Die Bildgenerierung kann über die native Canvas-Schnittstelle toDataURL erreicht werden und liefert letztendlich Bilddaten in Base64-Form.
function genericPng() { var canvas = document.createElement('canvas'); let icavas = '#canvas' //Canvas-ID zum Rendern der Animation if (wrapWidth == 2) { icavas = '#verticalCanvas' } var canvasNode = document .querySelector(icavas) Canvas.width = CanvasNode.width; Canvas.height = CanvasNode.height; canvas.getContext('2d'); ctx.drawImage(canvasNode, 0, 0); var imgData = canvas.toDataURL(image/png); So erstellen Sie Screenshots von LeinwandanimationenVerwenden Sie setInterval, um die Bildgenerierungsmethode regelmäßig auszuführen. Natürlich können Sie auch requestAnimationFrame verwenden.
setInterval(function() { imgsTemp.push(generatePng())}, 1000/60) So erhalten Sie jeden Bildrahmen im BackendLösung 1: Der Headless-Browser führt die Front-End-Canvas-Animation js aus und erstellt dann einen Screenshot der js
Erste Idee:
Die Screenshots werden mit console.log ausgedruckt. Die Canvas-Screenshots sind im Base64-Format, eine 15-sekündige Animation, und es gibt mehr als 100 Screenshots, die direkt zum Absturz des Servers führten (abgelehnt);
Probelaufplan:
Der Screenshot wird in einer js-Variablen gespeichert. Nachdem die Animation abgespielt wurde, wird der Seite ein Logo hinzugefügt, und dann erhält das Backend die Variable.
const page = { imageZoomOut: import ('./image_zoom_inout.js'), //Zoom imageArt: import ('./image_art.js'), //ImageGrid löschen: import ('./image_grid.js'), / /Grid imageRotate: import ('./image_rotate.js'), //imageFlash öffnen und schließen: import ('./image_flash.js'), //Bild- und Text-Flash imageVerticalArt: import ('./image_vertical_art.js'), //Vertikale Löschung imageVerticalGrid: import ('./image_vertical_grid.js'), //Vertikales Raster imageVerticalRotate: import ('. /image_vertical_rotate.js '), // Vertikales Öffnen und Schließen von imageVerticalFlash: import ('./image_vertical_flash.js'), //Vertical Bild und Text flashen imageVerticalZoomOut: import ('./image_vertical_zoom_inout.js'), //Vertical zoom imageVertical: import ('./image_vertical.js'), //Vertical version general};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 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 (Element, 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 }}async function renderAnimate(page) { //await creatImg() let me = this const pageA = Warten Sie auf Seiten[Seite]; 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() { //Nachdem die Animation abgespielt wurde, isShow = true; imgsTemp.push(generatePng()) imgsBase64.push(imgsTemp) let now = new Date().getTime() window.imgsTimeLong = now - oldDate clearInterval(cutInter) document.getElementById('cutImg').innerHTML = ' done'//Seitenidentifikation}) cutInter = setInterval(function() { imgsTemp.push(generatePng()) if (imgsTemp.length >= 50) { imgsBase64.push(imgsTemp) imgsTemp = [] } }, 130)}function getImgs() { return imgsBase64}function genericPng() { var canvas = document.createElement('canvas'); let icavas = '#canvas' if (wrapWidth == 2) { icavas = '#verticalCanvas' } var CanvasNode = document.querySelector(icavas) Canvas.width = CanvasNode.width; Canvas.height = CanvasNode.height; ; ctx.drawImage(canvasNode, 0, 0); var imgData = canvas.toDataURL(image/png); return imgData;}window.imgsBase64 = imgsBase64 //Screenshot-Speichervariable creatImg()Nachteile des Probebetriebsplans:
var temp = new Image(vw, vh)temp.setAttribute('crossOrigin', 'anonymous'); Endgültige Lösung: Animation auf der NODE-Seite ausführen Verwenden Sie node-canvas, um jeden Frame-Screenshot mit fs.writeFile
const { createCanvas, loadImage} = require(canvas); const seiten = { imageZoomOut: require('./image_zoom_inout.js'), //Zoom imageArt: require('./image_art.js'), //ImageGrid löschen: require('./image_grid.js'), //Grid imageRotate: require('./image_rotate.js'), //imageFlash öffnen und schließen: require('./image_flash.js'), //Bild- und Text-Flash imageVerticalArt: require('./image_vertical_art.js'), //Vertikale Löschung imageVerticalGrid: require('./image_vertical_grid . js'), //vertikales Raster imageVerticalRotate: require('./image_vertical_rotate.js'), //vertikales Raster imageVerticalFlash: require('./image_vertical_flash.js'), // Vertikaler Bild- und Text-Flash imageVerticalZoomOut: require('./image_vertical_zoom_inout.js'), // Vertikaler Zoom imageVertical: require('./image_vertical.js'), // Allgemein für vertikale Version};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 //canvas height let vw = parse.templateType == 1 ? let imgSrcArray = parse.images //Bildarray let effectTag = parse.tid //Animationseffekt 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) => { //Animation initialisieren console.log('Animation starten') let oldDate = neues Datum ().getTime() seiten[effectTag].render(null, { Canvas: Canvas, Bilder: Bilder }, function() { clearInterval(interval) let now = new Date().getTime() console.log(now - oldDate, 'Animation endet') }) 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'); fs.writeFile(`${saveImgPath}${x}.jpg `, buf, {}, (err) => { console.log(x })); 1000 / 60 ); }) .catch(e => { console.log(e); });Führen Sie den folgenden Befehl unter iterm aus
Knoten 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 =../ass 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/'
Parameterbeschreibung:
1) tid ist der Name der Animation
2) templateType ist Größe: 1:1280*720; 2:720*1280
3) Bilder ist die Bildadresse
4) Die Variable „./images/“ ist die Adresse, an der der Screenshot gespeichert wird.
Nachteile der Ausführung in der NODE-UmgebungDie folgende Zeichnung wird alle 13 Sekunden wiederholt:
for (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(); for (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();
Aufgrund des Ereignisschleifenmodells von Node.js muss durch die Verwendung von Node.js sichergestellt werden, dass der Zyklus von Node.js jederzeit ausgeführt werden kann. Wenn eine sehr zeitaufwändige Funktion auftritt, bleibt die Ereignisschleife hängen und kann nicht verarbeitet werden Andere Aufgaben werden rechtzeitig ausgeführt, sodass einige Animationen immer noch langsam sind.
Möglichkeit einer späteren OptimierungVersuchen Sie, Screenshots mit der Go-Sprache zu erstellen.
Leinwandanimation neu schreiben;
Extra Video-BitrateDie Videobitrate ist die Anzahl der pro Zeiteinheit während der Datenübertragung übertragenen Datenbits. Im Allgemeinen verwenden wir die Einheit kbps, also Tausende von Bits pro Sekunde. Ein einfaches Verständnis ist die Abtastrate: Je höher die Abtastrate pro Zeiteinheit, desto höher ist die Genauigkeit und desto näher kommt die verarbeitete Datei der Originaldatei. Bei einer Audiodatei gilt beispielsweise: Je höher die Bitrate, desto kleiner das Komprimierungsverhältnis, desto geringer ist der Klangqualitätsverlust und desto näher liegt die Tonqualität an der Audioquelle.
FPS-Bilder pro Sekunde (Frames Per Second)
FPS ist eine Definition im Bereich der Grafik, die sich auf die Anzahl der pro Sekunde übertragenen Bilder bezieht. Im Allgemeinen bezieht sie sich auf die Anzahl der Bilder einer Animation oder eines Videos. FPS ist ein Maß für die Informationsmenge, die zum Speichern und Anzeigen dynamischer Videos verwendet wird. Je mehr Bilder pro Sekunde, desto flüssiger wird die Aktion dargestellt. Normalerweise liegt der Mindestwert zur Vermeidung ruckartiger Bewegungen bei 30. Beispielsweise wird ein Film mit einer Geschwindigkeit von 24 Bildern pro Sekunde abgespielt, was bedeutet, dass in einer Sekunde fortlaufend 24 Standbilder auf die Leinwand projiziert werden.
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er für das Studium aller hilfreich ist. Ich hoffe auch, dass jeder das VeVb Wulin Network unterstützt.