commit 4cfc00e64b7d4a11f6cce9e7b859d714ddc6a9a5 Author: Matt Date: Fri Dec 18 08:46:44 2015 -0500 Project as was hacked together diff --git a/package.json b/package.json new file mode 100644 index 0000000..6499901 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "video_to_page", + "version": "1.0.0", + "description": "Turn a video into a page of stills 16mm size", + "main": "video_to_page.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "mmcwilliams", + "license": "MIT", + "nexe" : { + "output" : "../video_to_page_nexe/video_to_page", + "runtime": { + "ignoreFlags": true, + "framework" : "nodejs", + "version" : "5.0.0" + } + } +} diff --git a/video_to_page.js b/video_to_page.js new file mode 100755 index 0000000..d85a056 --- /dev/null +++ b/video_to_page.js @@ -0,0 +1,152 @@ +var exec = require('child_process').exec, + fs = require('fs'), + _tmp = './temp'; + +//var frame_height = 7.61; +//var frame_height = 7.49; +var frame_height = 7.62; +var frame_padding = 0; + +var frame_dimensions = function (dpi) { + var h = Math.round(frame_height * (dpi / 25.4)), + w = Math.round(10.5 * (dpi / 25.4)), + o = Math.round(16 * (dpi / 25.4)); + return {h: h, w: w, o: o, dpi: dpi}; +}; + +/* +convert() - Turn video into sheet of images + +@param: path - file path (absolute) +@param: dpi - target printing dpi +@param: length - strip length in frames + +*/ +var convert = function (path, dpi) { + 'use strict'; + var dim = frame_dimensions(dpi), + file = path.split('/').pop(), + loc = _tmp + '/', + execStr = 'avconv -i "' + path + '" -s ' + dim.w + 'x' + dim.h + ' -qscale 1 "' + loc + 'sequence_%04d.jpg"'; + + console.log('Converting ' + file + '...'); + console.log('Exporting all frames with aspect ratio: ' + (dim.w / dim.h) + '...'); + + fs.mkdirSync(_tmp); + + exec(execStr, function (ste, std) { + if (ste) { + return errorHandle(ste); + } + console.log('Frames exported successfully!'); + stitch(loc.substring(0, loc.length - 1), dim); + }); +}; + +var stitch = function (loc, dim) { + 'use strict'; + var length = Math.floor((11 * dim.dpi) / dim.h) - 1, + width = Math.floor((8.5 * dim.dpi / dim.o)) - 1, + page = 0, + pageCount = 0, + cmd = 'find "' + loc + '" -type f -name "sequence_*.jpg"', + find_cb = function (ste, std) { + if (ste) { + return errorHandle(ste); + } + var frames = std.split('\n'), + execStr = 'montage ', + montage_cb = function (stee, stdd) { + if (stee) { + return errorHandle(ste); + } + + console.log('Created page_' + pageCount + '.jpg!'); + pageCount++; + if (pageCount === page) { + console.log('Cleaning up...'); + setTimeout(function () { + exec('find "' + loc + '" -type f -name "sequence_*.jpg" -delete', function () { + fs.rmdirSync(_tmp); + console.log('Done!'); + }); + }, 1000); + } + }; + for (var i = 0; i < frames.length; i++) { + execStr += frames[i] + ' '; + if ((i + 1) % (width * length) === 0 || i === frames.length - 1) { + execStr += '\ -tile 1x' + length + ' -geometry ' + dim.w + 'x' + dim.h + '+' + Math.round((dim.o - dim.w) / 2) + '+0 miff:- |\ \nmontage - -geometry +0+0 -tile ' + width + 'x1 -density ' + dim.dpi + ' "./page_' + page + '.jpg"'; + exec(execStr, montage_cb); + execStr = 'montage '; + page++; + } + } + }; + + loc = _tmp; + + console.log('Stitching frames into sheets...'); + console.log('Sheets will contain ' + width + 'x' + length + ' frames...'); + exec(cmd, find_cb); +}; +var errorHandle = function (err) { + 'use strict'; + if (process.argv.indexOf('-v') !== -1 || process.argv.indexOf('--verbose') !== -1){ + console.error(err); + } else { + console.error('Error running program. Run in verbose mode for more info (-v,--verbose)'); + } + process.exit(1); +}; + +process.on('uncaughtException', function (err) { + errorHandle(err); +}); + + +if (typeof process.argv[2] === 'undefined') { + console.error('No path to video defined'); + process.exit(1); +} + +if (typeof process.argv[3] === 'undefined') { + process.argv[3] = 300; + console.log('Using default 300dpi'); +} + +convert(process.argv[2], process.argv[3]); + +/* + + INSTALLATION AND RUNNING + +*/ + +//Install in this order to satisfy requirements: GCC required by MacPorts, etc. + +//Install Node http://nodejs.org/dist/v0.10.22/node-v0.10.22.pkg +//Install GCC https://github.com/kennethreitz/osx-gcc-installer#option-1-downloading-pre-built-binaries +//Install MacPorts http://www.macports.org/install.php +//Install ImageMagick in terminal type "sudo port install ImageMagick" +//Install avconv -see below + +/* +Download and unzip http://libav.org/releases/libav-9.6.tar.gz +in terminal type "cd " and drag in unzipped folder and hit enter +in terminal copy "sudo port install yasm zlib bzip2 faac lame speex libogg libvorbis libtheora libvpx x264 XviD openjpeg15 opencore-amr freetype" (without quotes) hit enter +in terminal copy "./configure \ --enable-gpl --enable-libx264 --enable-libxvid \ --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb \ --enable-nonfree --enable-libfaac \ --enable-libmp3lame --enable-libspeex --enable-libvorbis --enable-libtheora --enable-libvpx \ --enable-libopenjpeg --enable-libfreetype --enable-doc --enable-gnutls --enable-shared" hit enter +(if that gives errors just use "./configure" and hit enter) +in terminal copy "make && sudo make install" hit enter + + that will install it +*/ + +//run by going to terminal typing "node " dragging this script into the terminal, dragging the video into the terminal and adding a DPI value and hitting enter +//the command should look something like this: +//node /Users/stenzel/Desktop/video_to_page.js /Users/stenzel/Desktop/PaulRobeson/Paul\ Robeson\ discusses\ Othello.mp4 600 + + +//Get the absolute path of any file by dragging it into terminal and copying the results +//Must be enclosed by '' +//Will generate pages and frames in same folder as source video