Initial commit
This commit is contained in:
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
*.mp4
|
||||||
|
*.png
|
||||||
|
*.mp3
|
||||||
|
*.gif
|
||||||
|
converted-ss/
|
||||||
|
tmp-ss/
|
||||||
|
node_modules/
|
||||||
63
convertToAscii.js
Normal file
63
convertToAscii.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
module.exports = convertToAscii = async (file, dotSize = 24, verticalSpacinModifier = 4, output = __dirname + '/tmp.img.png') => {
|
||||||
|
const hobbitImageFile = file;
|
||||||
|
const density = 'Ñ@#W$9876543210?!abc;:+=-,._ ';
|
||||||
|
|
||||||
|
const { createCanvas } = require('canvas')
|
||||||
|
const ImageDataURI = require('image-data-uri');
|
||||||
|
var sizeOf = require('image-size');
|
||||||
|
var dimensions = sizeOf(hobbitImageFile);
|
||||||
|
|
||||||
|
const hobbit = {
|
||||||
|
width: dimensions.width,
|
||||||
|
height: dimensions.height,
|
||||||
|
pixels: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
function clamp(input, min, max) {
|
||||||
|
return input < min ? min : input > max ? max : input;
|
||||||
|
}
|
||||||
|
|
||||||
|
function map(current, in_min, in_max, out_min, out_max) {
|
||||||
|
const mapped = ((current - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min;
|
||||||
|
return clamp(mapped, out_min, out_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise((res, rej) => {
|
||||||
|
var PNG = require('png-js');
|
||||||
|
PNG.decode(hobbitImageFile, function(pixels) {
|
||||||
|
|
||||||
|
const canvas = createCanvas(hobbit.width * dotSize, hobbit.height * dotSize);
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
|
||||||
|
hobbit.pixels = pixels;
|
||||||
|
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillRect(0, 0, hobbit.width * dotSize, hobbit.height * dotSize);
|
||||||
|
|
||||||
|
for(let x = 0; x < hobbit.width; x++) {
|
||||||
|
for(let y = 0; y < hobbit.height; y++) {
|
||||||
|
const pixelPosition = (x + y*hobbit.width)*4;
|
||||||
|
const r = hobbit.pixels[pixelPosition + 0];
|
||||||
|
const g = hobbit.pixels[pixelPosition + 1];
|
||||||
|
const b = hobbit.pixels[pixelPosition + 2];
|
||||||
|
const a = hobbit.pixels[pixelPosition + 3];
|
||||||
|
|
||||||
|
const avg = Math.floor((r+g+b)/ 3);
|
||||||
|
|
||||||
|
const gray = map(255 - avg, 0, 255, 0, density.length);
|
||||||
|
|
||||||
|
ctx.font = (dotSize + verticalSpacinModifier) + "px Courier";
|
||||||
|
ctx.textAlign = 'center';
|
||||||
|
ctx.textBaseline = 'middle';
|
||||||
|
ctx.fillStyle = `white`;
|
||||||
|
ctx.fillText(density.charAt(gray), x*dotSize + dotSize/2, y*dotSize + dotSize/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageDataURI.outputFile(canvas.toDataURL(), output);
|
||||||
|
console.log(output, 'converted');
|
||||||
|
res(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
70
index.js
Normal file
70
index.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
PREREQUISITES:
|
||||||
|
- ffmpeg installed and added to the PATH
|
||||||
|
|
||||||
|
COMMANDS TO PREPARE VIDEO FOR CONVERSION:
|
||||||
|
- scale video and lower fps
|
||||||
|
ffmpeg.exe -i .\original-video.mp4 -vf "scale=120:-2, fps=30" scaled-video.mp4
|
||||||
|
|
||||||
|
COMMANDS TO BUILD VIDEO AFTER CONVERSION:
|
||||||
|
- extract audio from video
|
||||||
|
ffmpeg -i .\original-video.mp4 extracted-audio.mp3
|
||||||
|
|
||||||
|
- combine video with audio
|
||||||
|
ffmpeg -i .\converted-video.mp4 -i extracted-audio.mp3 -c:v copy -c:a aac finished-video.mp4
|
||||||
|
|
||||||
|
- convert video to gif (no audio)
|
||||||
|
ffmpeg -i .\converted-video.mp4 -f gif .\converted-video.gif
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
const extractFrames = require('ffmpeg-extract-frames')
|
||||||
|
const convertToAscii = require('./convertToAscii');
|
||||||
|
const fs = require('fs');
|
||||||
|
const { exec } = require("child_process");
|
||||||
|
const fsExtra = require('fs-extra')
|
||||||
|
|
||||||
|
fsExtra.emptyDirSync(__dirname + '/converted-ss')
|
||||||
|
fsExtra.emptyDirSync(__dirname + '/tmp-ss')
|
||||||
|
|
||||||
|
if (!fs.existsSync(__dirname + '/converted-ss')) {
|
||||||
|
fs.mkdirSync(__dirname + '/converted-ss');
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(__dirname + '/tmp-ss')) {
|
||||||
|
fs.mkdirSync(__dirname + '/tmp-ss');
|
||||||
|
}
|
||||||
|
|
||||||
|
const PATH_TO_VIDEO_TO_BE_CONVERTED = __dirname + '/sponge-bob-mrs-puff-scaled.mp4';
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
await extractFrames({
|
||||||
|
input: PATH_TO_VIDEO_TO_BE_CONVERTED,
|
||||||
|
output: __dirname + '/tmp-ss/%d.png'
|
||||||
|
});
|
||||||
|
|
||||||
|
let files = fs.readdirSync(__dirname + '/tmp-ss');
|
||||||
|
|
||||||
|
files = files.filter(name => name.endsWith('.png'));
|
||||||
|
|
||||||
|
for (let file of files) {
|
||||||
|
await convertToAscii(__dirname + '/tmp-ss/' + file, 12, 0, __dirname + '/converted-ss/' + file);
|
||||||
|
fs.rmSync(__dirname + '/tmp-ss/' + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
exec('ffmpeg -framerate 10 -i ./converted-ss/%d.png -c:v libx264 -r 30 -pix_fmt yuv420p output.mp4 -y', (error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
console.log(`error: ${error.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (stderr) {
|
||||||
|
console.log(`stderr: ${stderr}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log(`stdout: ${stdout}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('done');
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
||||||
1404
package-lock.json
generated
Normal file
1404
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
package.json
Normal file
19
package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "virtualcanvas",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"canvas": "^2.9.0",
|
||||||
|
"ffmpeg-extract-frames": "^2.0.2",
|
||||||
|
"fs-extra": "^10.0.0",
|
||||||
|
"image-data-uri": "^2.0.1",
|
||||||
|
"image-size": "^1.0.1",
|
||||||
|
"png-js": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user