ด้วยการอัปโหลดรูปภาพในขนาดที่เหมาะสม ผู้ใช้สามารถดูตัวอย่างเอฟเฟกต์ที่คล้ายกับสไลด์โชว์ได้โดยเลือกเอฟเฟกต์และเพลงของภาพเคลื่อนไหวที่เรนเดอร์ และสุดท้ายคลิกเพื่อยืนยันเพื่อสร้างวิดีโอ ซึ่งสามารถเล่นบนพาดหัวข่าวหรือ Douyin ได้
แนวทางแก้ไขที่เป็นไปได้สำหรับการสร้างวิดีโอการแปลงการเข้ารหัสวิดีโอส่วนหน้าอย่างแท้จริง (เช่น WebM Encoder Whammy)
ส่งแต่ละเฟรมของรูปภาพไปยังแบ็กเอนด์เพื่อนำไปใช้งาน และแบ็กเอนด์จะเรียก FFmpeg สำหรับการแปลงรหัสวิดีโอ
การสร้างภาพสามารถทำได้ผ่านอินเทอร์เฟซดั้งเดิมของ Canvas ไปที่ DataURL และส่งคืนข้อมูลภาพในรูปแบบ base64 ในท้ายที่สุด
function GeneratePng() { var canvas = document.createElement('canvas'); ให้ icavas = '#canvas' //Canvas id สำหรับการแสดงภาพเคลื่อนไหว 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(รูปภาพ/png); วิธีถ่ายภาพหน้าจอแอนิเมชั่นแคนวาสใช้ setInterval เพื่อดำเนินการวิธีการสร้างภาพเป็นประจำ แน่นอนว่าคุณสามารถใช้ requestAnimationFrame ได้เช่นกัน
setInterval(function() { imgsTemp.push(generatePng())}, 1,000/60) วิธีรับภาพแต่ละเฟรมในแบ็กเอนด์โซลูชันที่ 1: เบราว์เซอร์ที่ไม่มีส่วนหัวจะรัน Canvas Animation js ส่วนหน้า จากนั้นจึงจับภาพหน้าจอของ js
ความคิดเริ่มต้น:
ภาพหน้าจอจะถูกพิมพ์โดยใช้ console.log ภาพหน้าจอแคนวาสอยู่ในรูปแบบ base64 ซึ่งเป็นภาพเคลื่อนไหว 15 วินาที และมีภาพหน้าจอมากกว่า 100 ภาพ ซึ่งทำให้เซิร์ฟเวอร์ขัดข้องโดยตรง (ถูกปฏิเสธ)
แผนการทดลองวิ่ง:
ภาพหน้าจอถูกเก็บไว้ในตัวแปร js หลังจากเล่นภาพเคลื่อนไหวแล้ว โลโก้จะถูกเพิ่มลงในเพจ จากนั้นแบ็กเอนด์จะได้รับตัวแปรดังนี้:
หน้า const = { imageZoomOut: import ('./image_zoom_inout.js'), //Zoom imageArt: import ('./image_art.js'), //Erase imageGrid: import ('./image_grid.js'), / /Grid imageRotate: import ('./image_rotate.js'), //เปิดและปิด imageFlash: import ('./image_flash.js'), // รูปภาพและข้อความแฟลช imageVerticalArt: นำเข้า ('./image_vertical_art.js'), // ลบแนวตั้ง imageVerticalGrid: นำเข้า ('./image_vertical_grid.js'), // ตารางแนวตั้ง imageVerticalRotate: นำเข้า ('. /image_vertical_rotate.js '), // การเปิดและปิดแนวตั้ง imageVerticalFlash: นำเข้า ('./image_vertical_flash.js'), // รูปภาพแนวตั้งและแฟลชข้อความ imageVerticalZoomOut: นำเข้า ('./image_vertical_zoom_inout.js'), // ซูมแนวตั้ง imageVertical: นำเข้า ('./image_vertical.js'), // เวอร์ชันแนวตั้งทั่วไป};var isShow = falsevar imgsBase64 = []var imgsTemp = []var cutInter = nullvar imgsTimeLong = 0function getQuerys(tag) { ให้ queryStr = window.location.search.slice(1); ให้ queryArr = queryStr.split('&'); ให้ query = []; ให้ spec = {} สำหรับ (ให้ i = 0, len = queryArr.length; i < len ; i++) { la queryItem = queryArr[i].split('='); ให้ qitem = decodeURIComponent(queryItem[1]) ถ้า (queryItem[0] == tag) { query.push(qitem); } else { spec[queryItem[0]] = qitem } } return { list: query, spec: spec };}var getQuerys('images')var effectTag = getQuery.spec. tidvar wrapWidth = getQuery.spec.templateTypelet num = 0let imgArr = []function creatImg() { var image = getQuery.list ให้ newImg = [] ให้ vh = wrapWidth == 1 ? 360 : 640 ให้ vw = wrapWidth == 1 ? 640 : 360 if (effectTag.indexOf('Flash') > -1) { images.map(function (รายการ, ดัชนี) { ถ้า (11 === ดัชนี || 13 === ดัชนี || 16 === ดัชนี) { var temp = รูปภาพใหม่ (vw, vh) temp.setAttribute('crossOrigin', 'anonymous'); temp.src = item; newImg.push(temp) } else { newImg.push(item) } }) imgArr = newImg renderAnimate( effectTag) } else { images.map (ฟังก์ชั่น (รายการ) { var temp = รูปภาพใหม่ (vw, vh) temp.setAttribute('crossOrigin', 'anonymous'); temp.src = item; temp.onload = function() { num ++ if (num == images.length) { renderAnimate (เอฟเฟกต์แท็ก) } } newImg.push (temp) }) imgArr = newImg }}ฟังก์ชัน async renderAnimate(page) { //await creatImg() ให้ฉัน = const pageA นี้ = รอหน้า [หน้า]; ให้ oldDate = new Date().getTime() ให้ icavas = '#canvas' if (wrapWidth == 2) { icavas = '#verticalCanvas' } ให้ innerCanvas = document.querySelector(icavas) isShow = false pageA [หน้า] .render (null, { canvas: innerCanvas, รูปภาพ: imgArr }, function () { // หลังจากเล่นภาพเคลื่อนไหวแล้ว isShow = จริง; imgsTemp.push(generatePng()) imgsBase64.push(imgsTemp) ให้ตอนนี้ = วันที่ใหม่ ().getTime() window.imgsTimeLong = ตอนนี้ - oldDate clearInterval(cutInter) document.getElementById('cutImg').innerHTML = ' เสร็จสิ้น'//การระบุหน้า}) 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'); ให้ icavas = '#canvas' ถ้า (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 (รูปภาพ / PNG); ส่งคืน imgData;} window.imgsBase64 = imgsBase64 // ตัวแปรพื้นที่เก็บข้อมูลภาพหน้าจอ creatImg ()ข้อเสียของแผนปฏิบัติการทดลอง:
var temp = รูปภาพใหม่ (vw, vh) temp.setAttribute ('crossOrigin', 'ไม่ระบุชื่อ'); วิธีแก้ปัญหาสุดท้าย: เรียกใช้แอนิเมชั่นทางฝั่ง NODE ใช้ node-canvas เพื่อเขียนภาพหน้าจอแต่ละเฟรมไปยังโฟลเดอร์ที่ระบุโดยใช้ fs.writeFile
const { createCanvas, loadImage} = need(canvas); const Page = { imageZoomOut: need('./image_zoom_inout.js'), //Zoom imageArt: need('./image_art.js'), //Erase imageGrid : ต้องการ('./image_grid.js'), //Grid imageRotate: need('./image_rotate.js'), //เปิดและปิด imageFlash: need('./image_flash.js'), //รูปภาพและข้อความ flash imageVerticalArt: need('./image_vertical_art.js'), // ลบแนวตั้ง imageVerticalGrid: need('./image_vertical_grid js'), // ตารางแนวตั้ง imageVerticalRotate: need ('./image_vertical_rotate.js'), // ตารางแนวตั้ง imageVerticalFlash: need('./image_vertical_flash.js'), // ภาพแนวตั้งและข้อความแฟลช imageVerticalZoomOut: need('./image_vertical_zoom_inout.js'), // ซูมแนวตั้ง imageVertical: need('./image_vertical.js'), // ทั่วไปสำหรับเวอร์ชันแนวตั้ง};const fs = need(fs);const querystring = need('querystring');let args = process.argv && process.argv[2]let parse = querystring.parse(args)let vh = parse.templateType == 1 ? 720 : 1280 // ความสูงของผ้าใบ ให้ vw = parse.templateType == 1 ? 1280 : 720 // ความกว้างของผ้าใบ ให้ imgSrcArray = parse.images // อาร์เรย์รูปภาพ ให้ effectTag = parse.tid // เอฟเฟกต์ภาพเคลื่อนไหว ให้ saveImgPath = process.argv && process.argv[3]let loadArr = []imgSrcArray.forEach(element => { if (//.(jpg|jpeg|png|JPG|PNG)$/.test(element)) { loadArr.push (loadImage (องค์ประกอบ)) } else { loadArr.push (องค์ประกอบ) }}); const canvas = createCanvas(vw, vh);const ctx = canvas.getContext(2d);Promise.all(loadArr) .then((images) => { //เตรียมใช้งานแอนิเมชัน console.log('เริ่มแอนิเมชั่น') ให้ oldDate = new Date ().getTime() หน้า [ effectTag] .render (null, { canvas: canvas, รูปภาพ: รูปภาพ }, function() { clearInterval(interval) ให้ตอนนี้ = ใหม่ Date().getTime() console.log(now - oldDate, 'Animation end') }) const range = setInterval( (function() { la x = 0; return () => { x += 1; ctx. canvas.toDataURL('image/jpeg', function(err, png) { if (err) { console.log(err); return; } ให้ data = png.replace(/^data:image///w+;base64,/, ''); ให้ buf = new Buffer(data, 'base64'); `, buf, {}, (ผิดพลาด) => { console.log(x, }); }); 1,000/60 }) .catch(e => { console.log(e); });ดำเนินการคำสั่งต่อไปนี้ภายใต้ iterm
โหนด 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 =../ตูด 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/'
คำอธิบายพารามิเตอร์:
1) tid คือชื่อแอนิเมชัน
2) templateType คือขนาด: 1:1280*720; 2:720*1280
3) รูปภาพคือที่อยู่ของรูปภาพ
4) ตัวแปร './images/' คือที่อยู่สำหรับบันทึกภาพหน้าจอ
ข้อเสียของการรันในสภาพแวดล้อม NODEภาพวาดต่อไปนี้จะวนซ้ำทุกๆ 13 วินาที:
สำหรับ (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(); สำหรับ (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();
เนื่องจากโมเดลลูปเหตุการณ์ของ Node.js การใช้ Node.js จะต้องให้แน่ใจว่าวงจรของ Node.js สามารถทำงานได้ตลอดเวลา หากมีฟังก์ชันที่ใช้เวลานานมากปรากฏขึ้น ลูปเหตุการณ์จะค้างและไม่สามารถจัดการได้ งานอื่นๆ ได้ทันเวลา ดังนั้น ส่งผลให้แอนิเมชั่นบางส่วนยังช้าอยู่
ความเป็นไปได้ของการเพิ่มประสิทธิภาพในภายหลังลองใช้ภาษา Go เพื่อจับภาพหน้าจอ
เขียนแอนิเมชั่นแคนวาสใหม่
พิเศษ อัตราบิตของวิดีโออัตราบิตของวิดีโอคือจำนวนบิตข้อมูลที่ส่งต่อหน่วยเวลาระหว่างการส่งข้อมูล โดยทั่วไปหน่วยที่เราใช้คือ kbps ซึ่งก็คือหลายพันบิตต่อวินาที ความเข้าใจง่ายๆ คืออัตราการสุ่มตัวอย่าง ยิ่งอัตราการสุ่มตัวอย่างต่อหน่วยเวลามากเท่าใด ความแม่นยำก็จะยิ่งสูงขึ้น และไฟล์ที่ประมวลผลก็จะยิ่งใกล้เคียงกับไฟล์ต้นฉบับมากขึ้นเท่านั้น ตัวอย่างเช่น สำหรับเสียง ยิ่งอัตราบิตสูง อัตราการบีบอัดก็จะน้อยลง คุณภาพเสียงที่สูญเสียก็จะน้อยลง และคุณภาพเสียงก็จะยิ่งใกล้กับแหล่งกำเนิดเสียงมากขึ้นเท่านั้น
เฟรม FPS ต่อวินาที (เฟรมต่อวินาที)
FPS เป็นคำจำกัดความในด้านกราฟิก ซึ่งหมายถึงจำนวนเฟรมที่ส่งต่อวินาที โดยทั่วไปแล้วจะหมายถึงจำนวนเฟรมของภาพเคลื่อนไหวหรือวิดีโอ FPS คือการวัดปริมาณข้อมูลที่ใช้ในการบันทึกและแสดงวิดีโอแบบไดนามิก ยิ่งเฟรมต่อวินาทีมากเท่าใด การเคลื่อนไหวก็จะยิ่งราบรื่นมากขึ้นเท่านั้น โดยปกติขั้นต่ำเพื่อหลีกเลี่ยงการเคลื่อนไหวกระตุกคือ 30 ตัวอย่างเช่น ภาพยนตร์จะเล่นด้วยความเร็ว 24 เฟรมต่อวินาที ซึ่งหมายความว่า 24 เฟรมจะถูกฉายอย่างต่อเนื่องบนหน้าจอในหนึ่งวินาที
ข้างต้นคือเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการศึกษาของทุกคน ฉันหวังว่าทุกคนจะสนับสนุน VeVb Wulin Network