├── .gitignore ├── README.md ├── examples ├── http.js └── total.js ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.jpg 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # selfie 2 | 3 | Take selfies with your webcam. 4 | 5 | npm install selfie -g 6 | selfie > selfie.jpg 7 | selfie --out selfie.jpg 8 | selfie --timer 2 --out selfie.jpg 9 | 10 | Currently works (for me) on OS X. [Patches welcome](https://github.com/zaach/node-webcam-capture). 11 | 12 | ## photoshoot 13 | 14 | Have a photoshoot: 15 | 16 | selfie --total 4 --out photoshoot.jpg 17 | 18 | This will take a sequence of 4 photos, `photoshoot1.jpg`, ..., `photoshoot4.jpg`. 19 | 20 | Combine that with the timer for webcam time-lapse photography: 21 | 22 | selfie --timer 10 --total 200 --out timelapse.jpg 23 | 24 | ## cli 25 | 26 | ``` 27 | Usage: selfie [--timer N] [--total N] [--out FILE] 28 | 29 | --timer, -t The number of seconds to wait before a capture. 30 | --total, -n Total number of shots to take in sequence. 31 | --out, -o The file to write the image to. 32 | --help, -h Display this help message. 33 | ``` 34 | 35 | ## node module 36 | 37 | var selfie = require('selfie'); 38 | 39 | selfie({ out: 'smexy.jpg' }); 40 | 41 | Leave out the file name if you want to handle the streams yourself. selfie returns an `EventEmitter`. 42 | 43 | var fs = require('fs'); 44 | var selfie = require('selfie'); 45 | 46 | // equivalent to `selfie -n 3 -o example.jpg` 47 | selfie({ total: 3 }) 48 | .on('capture', function(camera, number) { 49 | var output_file = fs.createWriteStream('example' + number +'.jpg', {encoding: 'binary'}); 50 | camera.stdout.pipe(output_file); 51 | }); 52 | 53 | ## License 54 | 55 | MIT 56 | -------------------------------------------------------------------------------- /examples/http.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var http = require('http'); 3 | var url = require('url'); 4 | var selfie = require('../'); 5 | 6 | http.createServer(function(req, res){ 7 | if (req.url === '/' && !req.headers.referer) { 8 | selfie() 9 | .on('capture', function(camera) { 10 | res.writeHead(200, {'Content-Type': 'image/jpeg' }); 11 | camera.stdout.pipe(res); 12 | }); 13 | } 14 | }).listen(8080); 15 | -------------------------------------------------------------------------------- /examples/total.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var selfie = require('../'); 3 | 4 | // equivalent to `selfie -n 3 -o example.jpg` 5 | selfie({ total: 3 }) 6 | .on('capture', function(camera, number) { 7 | var output_file = fs.createWriteStream('example' + number +'.jpg', {encoding: 'binary'}); 8 | camera.stdout.pipe(output_file); 9 | }); 10 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const path = require('path'); 4 | const EventEmitter = require('events').EventEmitter; 5 | const nopt = require('nopt'); 6 | const usage = require('nopt-usage'); 7 | const capture = require('webcam-capture'); 8 | 9 | const knownOpts = { 'timer' : Number 10 | , 'total' : Number 11 | , 'out' : path 12 | , 'help' : Boolean 13 | }; 14 | const shortHands = { 't' : ['--timer'] 15 | , 'n' : ['--total'] 16 | , 'o' : ['--out'] 17 | , 'h' : ['--help'] 18 | }; 19 | const descriptions = { 'timer' : 'The number of seconds to wait before a capture.' 20 | , 'total' : 'Total number of shots to take in sequence.' 21 | , 'out' : 'The file to write the image to.' 22 | , 'help' : 'Display this help message.' 23 | }; 24 | 25 | function selfie(options) { 26 | if (!options) options = {}; 27 | 28 | const emitter = new EventEmitter(); 29 | const delay = (options.timer || 0) * 1000; 30 | var i = 0; 31 | var out; 32 | 33 | if (options.help) { 34 | console.log('Usage: selfie [--timer N] [--amount N] [--out FILE]\n'); 35 | console.log(usage(knownOpts, shortHands, descriptions)); 36 | return; 37 | } 38 | 39 | if (options.total) { 40 | if (options.out) out = options.out.split('.'); 41 | 42 | setTimeout(function shoot() { 43 | process.stderr.write('Taking photo ' + ++i + '\n'); 44 | if (out) options.out = out[0] + i + (out[1] ? '.' + out[1] : ''); 45 | var spawned = capture(options); 46 | emitter.emit('capture', spawned, i); 47 | spawned.on('exit', function() { 48 | if (i < options.total) { 49 | setTimeout(shoot, delay); 50 | } 51 | }); 52 | }, delay); 53 | 54 | } else { 55 | setTimeout(function() { 56 | var spawned = capture(options); 57 | emitter.emit('capture', spawned); 58 | }, delay); 59 | } 60 | 61 | return emitter; 62 | } 63 | 64 | module.exports = selfie; 65 | 66 | // CLI mode 67 | if (require.main === module) { 68 | var parsed = nopt(knownOpts, shortHands); 69 | 70 | // Add defaults to make the CLI (possibly) more sane 71 | if (!parsed.out && parsed.total) { 72 | // ensure we save to a file when taking multiple shots 73 | parsed.out = 'selfie.jpg'; 74 | } else if (!parsed.out) { 75 | parsed.stdio = [null, process.stdout, process.stderr]; 76 | } 77 | 78 | selfie(parsed); 79 | } 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "selfie", 3 | "version": "0.0.3", 4 | "description": "Take selfies with your webcam.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/zaach/selfie.git" 8 | }, 9 | "main": "index.js", 10 | "bin": "index.js", 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "author": "Zach Carter (http://zaa.ch)", 15 | "license": "MIT", 16 | "dependencies": { 17 | "webcam-capture": "~0.1.1", 18 | "nopt": "~2.1.2", 19 | "nopt-usage": "~0.1.0" 20 | } 21 | } 22 | --------------------------------------------------------------------------------