rename - work.

This commit is contained in:
Christopher Jeffrey 2015-07-12 05:19:00 -07:00
parent aa9a85be9d
commit abdd0a8c89
5 changed files with 34 additions and 902 deletions

View File

@ -94,11 +94,12 @@ var box = blessed.box({
// Append our box to the screen.
screen.append(box);
// Add a PNG icon to the box (X11 only)
// Add a png icon to the box
var icon = blessed.image({
parent: box,
top: 0,
left: 0,
itype: 'overlay',
width: 'shrink',
height: 'shrink',
file: __dirname + '/my-program-icon.png',
@ -172,8 +173,8 @@ screen.render();
- [Special Elements](#special-elements)
- [Terminal](#terminal-from-box)
- [Image](#image-from-box)
- [PNG](#png-from-box)
- [W3MImage](#w3mimage-from-box)
- [ANSIImage](#ansiimage-from-box)
- [OverlayImage](#overlayimage-from-box)
- [Video](#video-from-box)
- [Layout](#layout-from-element)
@ -1395,43 +1396,43 @@ manager. Requires term.js and pty.js to be installed. See
#### Image (from Box)
Display an image in the terminal (jpeg, png, gif) using either blessed's
internal png/gif-to-terminal renderer (using a [PNG element](#png-from-box)) or
using `w3mimgdisplay` (using a [W3MImage element](#w3mimage-from-box)).
internal png/gif-to-terminal renderer (using a [ANSIImage element](#ansiimage-from-box)) or
using `w3mimgdisplay` (using a [OverlayImage element](#overlayimage-from-box)).
##### Options:
- Inherits all from Box.
- __file__ - Path to image.
- __itype__ - `ansi` or `w3m`. Whether to render the file as ANSI art or using
`w3m` to overlay Internally uses the PNG element. See the [PNG
element](#png-from-box) for more information/options. (__default__: `ansi`).
- __itype__ - `ansi` or `overlay`. Whether to render the file as ANSI art or
using `w3m` to overlay. See the [ANSIImage element](#ansiimage-from-box) for
more information/options. (__default__: `ansi`).
##### Properties:
- Inherits all from Box.
- See [PNG element](#png-from-box)
- See [W3MImage element](#w3mimage-from-box)
- See [ANSIImage element](#ansiimage-from-box)
- See [OverlayImage element](#overlayimage-from-box)
##### Events:
- Inherits all from Box.
- See [PNG element](#png-from-box)
- See [W3MImage element](#w3mimage-from-box)
- See [ANSIImage element](#ansiimage-from-box)
- See [OverlayImage element](#overlayimage-from-box)
##### Methods:
- Inherits all from Box.
- See [PNG element](#png-from-box)
- See [W3MImage element](#w3mimage-from-box)
- See [ANSIImage element](#ansiimage-from-box)
- See [OverlayImage element](#overlayimage-from-box)
#### PNG (from Box)
#### ANSIImage (from Box)
Convert any `.png` file (or `.gif`, see below) to an ANSI image and display it
as an element. This differs from the `Image` element in that it uses blessed's
internal PNG parser and does not require external dependencies.
internal PNG/GIF parser and does not require external dependencies.
Blessed uses an internal from-scratch PNG reader because no other javascript
Blessed uses an internal from-scratch PNG/GIF reader because no other javascript
PNG reader supports Adam7 interlaced images (much less pass the png test
suite).
@ -1452,12 +1453,12 @@ installed.
##### Options:
- Inherits all from Box.
- __file__ - URL or path to PNG file. Can also be a buffer.
- __file__ - URL or path to PNG/GIF file. Can also be a buffer.
- __scale__ - Scale cellmap down (`0-1.0`) from its original pixel width/height
(Default: `1.0`).
- __width/height__ - This differs from other element's `width` or `height` in
that only one of them is needed: blessed will maintain the aspect ratio of
the image as it scales down to the proper number of cells. __NOTE__: PNG's
the image as it scales down to the proper number of cells. __NOTE__: PNG/GIF's
are always automatically shrunken to size (based on scale) if a `width` or
`height` is not given.
- __ascii__ - Add various "density" ASCII characters over the rendering to give
@ -1494,7 +1495,7 @@ installed.
- __clearImage()__ - Clear the image.
#### W3MImage (from Box)
#### OverlayImage (from Box)
Display an image in the terminal (jpeg, png, gif) using w3mimgdisplay. Requires
w3m to be installed. X11 required: works in xterm, urxvt, and possibly other
@ -1505,7 +1506,7 @@ terminals.
- Inherits all from Box.
- __file__ - Path to image.
- __ansi__ - Render the file as ANSI art instead of using `w3m` to overlay
Internally uses the PNG element. See the [PNG element](#png-from-box) for
Internally uses the ANSIImage element. See the [ANSIImage element](#ansiimage-from-box) for
more information/options. (Default: `true`).
- __w3m__ - Path to w3mimgdisplay. If a proper `w3mimgdisplay` path is not
given, blessed will search the entire disk for the binary.

View File

@ -37,8 +37,8 @@ widget.classes = [
'ListTable',
'Terminal',
'Image',
'PNG',
'W3MImage',
'ANSIImage',
'OverlayImage',
'Video',
'Layout'
];

View File

@ -29,25 +29,25 @@ function Image(options) {
Box.call(this, options);
if (options.itype === 'ansi' && this.type !== 'png') {
var PNG = require('./png');
Object.getOwnPropertyNames(PNG.prototype).forEach(function(key) {
if (options.itype === 'ansi' && this.type !== 'ansiimage') {
var ANSIImage = require('./ansiimage');
Object.getOwnPropertyNames(ANSIImage.prototype).forEach(function(key) {
if (key === 'type') return;
Object.defineProperty(this, key,
Object.getOwnPropertyDescriptor(PNG.prototype, key));
Object.getOwnPropertyDescriptor(ANSIImage.prototype, key));
}, this);
PNG.call(this, options);
ANSIImage.call(this, options);
return this;
}
if (options.itype === 'w3m' && this.type !== 'w3mimage') {
var W3MImage = require('./w3mimage');
Object.getOwnPropertyNames(W3MImage.prototype).forEach(function(key) {
if (options.itype === 'overlay' && this.type !== 'overlayimage') {
var OverlayImage = require('./overlayimage');
Object.getOwnPropertyNames(OverlayImage.prototype).forEach(function(key) {
if (key === 'type') return;
Object.defineProperty(this, key,
Object.getOwnPropertyDescriptor(W3MImage.prototype, key));
Object.getOwnPropertyDescriptor(OverlayImage.prototype, key));
}, this);
W3MImage.call(this, options);
OverlayImage.call(this, options);
return this;
}
}

View File

@ -1,144 +0,0 @@
/**
* png.js - render PNGs as ANSI
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var cp = require('child_process')
, path = require('path')
, fs = require('fs');
var helpers = require('../helpers');
var colors = require('../colors');
var Node = require('./node');
var Box = require('./box');
var tng = require('../../vendor/tng');
/**
* PNG
*/
function PNG(options) {
var self = this;
if (!(this instanceof Node)) {
return new PNG(options);
}
options = options || {};
options.shrink = true;
Box.call(this, options);
this.scale = this.options.scale || 1.0;
this.options.animate = this.options.animate !== false;
this._noFill = true;
if (this.options.file) {
this.setImage(this.options.file);
}
this.screen.on('prerender', function() {
var lpos = self.lpos;
if (!lpos) return;
// prevent image from blending with itself if there are alpha channels
self.screen.clearRegion(lpos.xi, lpos.xl, lpos.yi, lpos.yl);
});
}
PNG.prototype.__proto__ = Box.prototype;
PNG.prototype.type = 'png';
PNG.curl = function(url) {
try {
return cp.execFileSync('curl',
['-s', '-A', '', url],
{ stdio: ['ignore', 'pipe', 'ignore'] });
} catch (e) {
;
}
try {
return cp.execFileSync('wget',
['-U', '', '-O', '-', url],
{ stdio: ['ignore', 'pipe', 'ignore'] });
} catch (e) {
;
}
throw new Error('curl or wget failed.');
};
PNG.prototype.setImage = function(file) {
var self = this;
this.file = typeof file === 'string' ? file : null;
if (/^https?:/.test(file)) {
file = PNG.curl(file);
}
var width = this.position.width;
var height = this.position.height;
if (width != null) {
width = this.width;
}
if (height != null) {
height = this.height;
}
try {
this.setContent('');
this.img = tng(file, {
colors: colors,
width: width,
height: height,
scale: this.scale,
ascii: this.options.ascii,
speed: this.options.speed,
filename: this.file
});
if (width == null || height == null) {
this.width = this.img.cellmap[0].length;
this.height = this.img.cellmap.length;
}
if (this.img.frames && this.options.animate) {
this.img.play(function(bmp, cellmap) {
self.cellmap = cellmap;
self.screen.render();
});
} else {
self.cellmap = self.img.cellmap;
}
} catch (e) {
this.setContent('PNG Error: ' + e.message);
this.img = null;
this.cellmap = null;
}
};
PNG.prototype.clearImage = function() {
this.setContent('');
this.img = null;
this.cellmap = null;
};
PNG.prototype.render = function() {
var self = this;
var coords = this._render();
if (!coords) return;
if (this.img) {
this.img.renderElement(this.cellmap, this);
}
return coords;
};
/**
* Expose
*/
module.exports = PNG;

View File

@ -1,725 +0,0 @@
/**
* w3mimage.js - w3m image element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var fs = require('fs')
, cp = require('child_process');
var helpers = require('../helpers');
var Node = require('./node');
var Box = require('./box');
/**
* W3MImage
* Good example of w3mimgdisplay commands:
* https://github.com/hut/ranger/blob/master/ranger/ext/img_display.py
*/
function W3MImage(options) {
var self = this;
if (!(this instanceof Node)) {
return new W3MImage(options);
}
options = options || {};
Box.call(this, options);
if (options.w3m) {
W3MImage.w3mdisplay = options.w3m;
}
if (W3MImage.hasW3MDisplay == null) {
if (fs.existsSync(W3MImage.w3mdisplay)) {
W3MImage.hasW3MDisplay = true;
} else if (options.search !== false) {
var file = helpers.findFile('/usr', 'w3mimgdisplay')
|| helpers.findFile('/lib', 'w3mimgdisplay')
|| helpers.findFile('/bin', 'w3mimgdisplay');
if (file) {
W3MImage.hasW3MDisplay = true;
W3MImage.w3mdisplay = file;
} else {
W3MImage.hasW3MDisplay = false;
}
}
}
this.on('hide', function() {
self._lastFile = self.file;
self.clearImage();
});
this.on('show', function() {
if (!self._lastFile) return;
self.setImage(self._lastFile);
});
this.on('detach', function() {
self._lastFile = self.file;
self.clearImage();
});
this.on('attach', function() {
if (!self._lastFile) return;
self.setImage(self._lastFile);
});
this.onScreenEvent('resize', function() {
self._needsRatio = true;
});
// Get images to overlap properly. Maybe not worth it:
// this.onScreenEvent('render', function() {
// self.screen.program.flush();
// if (!self._noImage) return;
// function display(el, next) {
// if (el.type === 'w3mimage' && el.file) {
// el.setImage(el.file, next);
// } else {
// next();
// }
// }
// function done(el) {
// el.children.forEach(recurse);
// }
// function recurse(el) {
// display(el, function() {
// var pending = el.children.length;
// el.children.forEach(function(el) {
// display(el, function() {
// if (!--pending) done(el);
// });
// });
// });
// }
// recurse(self.screen);
// });
this.onScreenEvent('render', function() {
self.screen.program.flush();
if (!self._noImage) {
self.setImage(self.file);
}
});
if (this.options.file || this.options.img) {
this.setImage(this.options.file || this.options.img);
}
}
W3MImage.prototype.__proto__ = Box.prototype;
W3MImage.prototype.type = 'w3mimage';
W3MImage.w3mdisplay = '/usr/lib/w3m/w3mimgdisplay';
W3MImage.prototype.spawn = function(file, args, opt, callback) {
var screen = this.screen
, opt = opt || {}
, spawn = require('child_process').spawn
, ps;
ps = spawn(file, args, opt);
ps.on('error', function(err) {
if (!callback) return;
return callback(err);
});
ps.on('exit', function(code) {
if (!callback) return;
if (code !== 0) return callback(new Error('Exit Code: ' + code));
return callback(null, code === 0);
});
return ps;
};
W3MImage.prototype.setImage = function(img, callback) {
var self = this;
if (this._settingImage) {
this._queue = this._queue || [];
this._queue.push([img, callback]);
return;
}
this._settingImage = true;
var reset = function(err, success) {
self._settingImage = false;
self._queue = self._queue || [];
var item = self._queue.shift();
if (item) {
self.setImage(item[0], item[1]);
}
};
if (W3MImage.hasW3MDisplay === false) {
reset();
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
if (!img) {
reset();
if (!callback) return;
return callback(new Error('No image.'));
}
this.file = img;
return this.getPixelRatio(function(err, ratio) {
if (err) {
reset();
if (!callback) return;
return callback(err);
}
return self.renderImage(img, ratio, function(err, success) {
if (err) {
reset();
if (!callback) return;
return callback(err);
}
if (self.shrink || self.options.autofit) {
delete self.shrink;
delete self.options.shrink;
self.options.autofit = true;
return self.imageSize(function(err, size) {
if (err) {
reset();
if (!callback) return;
return callback(err);
}
if (self._lastSize
&& ratio.tw === self._lastSize.tw
&& ratio.th === self._lastSize.th
&& size.width === self._lastSize.width
&& size.height === self._lastSize.height
&& self.aleft === self._lastSize.aleft
&& self.atop === self._lastSize.atop) {
reset();
if (!callback) return;
return callback(null, success);
}
self._lastSize = {
tw: ratio.tw,
th: ratio.th,
width: size.width,
height: size.height,
aleft: self.aleft,
atop: self.atop
};
self.position.width = size.width / ratio.tw | 0;
self.position.height = size.height / ratio.th | 0;
self._noImage = true;
self.screen.render();
self._noImage = false;
reset();
return self.renderImage(img, ratio, callback);
});
}
reset();
if (!callback) return;
return callback(null, success);
});
});
};
W3MImage.prototype.renderImage = function(img, ratio, callback) {
var self = this;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.renderImageSync(img, ratio));
} catch (e) {
return callback(e);
}
}
if (W3MImage.hasW3MDisplay === false) {
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
if (!ratio) {
if (!callback) return;
return callback(new Error('No ratio.'));
}
// clearImage unsets these:
var _file = self.file;
var _lastSize = self._lastSize;
return self.clearImage(function(err) {
if (err) return callback(err);
self.file = _file;
self._lastSize = _lastSize;
var opt = {
stdio: 'pipe',
env: process.env,
cwd: process.env.HOME
};
var ps = self.spawn(W3MImage.w3mdisplay, [], opt, function(err, success) {
if (!callback) return;
return err
? callback(err)
: callback(null, success);
});
var width = self.width * ratio.tw | 0
, height = self.height * ratio.th | 0
, aleft = self.aleft * ratio.tw | 0
, atop = self.atop * ratio.th | 0;
var input = '0;1;'
+ aleft + ';'
+ atop + ';'
+ width + ';'
+ height + ';;;;;'
+ img
+ '\n4;\n3;\n';
self._props = {
aleft: aleft,
atop: atop,
width: width,
height: height
};
ps.stdin.write(input);
ps.stdin.end();
});
};
W3MImage.prototype.clearImage = function(callback) {
var self = this;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.clearImageSync());
} catch (e) {
return callback(e);
}
}
if (W3MImage.hasW3MDisplay === false) {
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
if (!this._props) {
if (!callback) return;
return callback(null);
}
var opt = {
stdio: 'pipe',
env: process.env,
cwd: process.env.HOME
};
var ps = this.spawn(W3MImage.w3mdisplay, [], opt, function(err, success) {
if (!callback) return;
return err
? callback(err)
: callback(null, success);
});
var width = this._props.width + 2
, height = this._props.height + 2
, aleft = this._props.aleft
, atop = this._props.atop;
if (this._drag) {
aleft -= 10;
atop -= 10;
width += 10;
height += 10;
}
var input = '6;'
+ aleft + ';'
+ atop + ';'
+ width + ';'
+ height
+ '\n4;\n3;\n';
delete this.file;
delete this._props;
delete this._lastSize;
ps.stdin.write(input);
ps.stdin.end();
};
W3MImage.prototype.imageSize = function(callback) {
var self = this;
var img = this.file;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.imageSizeSync());
} catch (e) {
return callback(e);
}
}
if (W3MImage.hasW3MDisplay === false) {
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
if (!img) {
if (!callback) return;
return callback(new Error('No image.'));
}
var opt = {
stdio: 'pipe',
env: process.env,
cwd: process.env.HOME
};
var ps = this.spawn(W3MImage.w3mdisplay, [], opt);
var buf = '';
ps.stdout.setEncoding('utf8');
ps.stdout.on('data', function(data) {
buf += data;
});
ps.on('error', function(err) {
if (!callback) return;
return callback(err);
});
ps.on('exit', function() {
if (!callback) return;
var size = buf.trim().split(/\s+/);
return callback(null, {
raw: buf.trim(),
width: +size[0],
height: +size[1]
});
});
var input = '5;' + img + '\n';
ps.stdin.write(input);
ps.stdin.end();
};
W3MImage.prototype.termSize = function(callback) {
var self = this;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.termSizeSync());
} catch (e) {
return callback(e);
}
}
if (W3MImage.hasW3MDisplay === false) {
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
var opt = {
stdio: 'pipe',
env: process.env,
cwd: process.env.HOME
};
var ps = this.spawn(W3MImage.w3mdisplay, ['-test'], opt);
var buf = '';
ps.stdout.setEncoding('utf8');
ps.stdout.on('data', function(data) {
buf += data;
});
ps.on('error', function(err) {
if (!callback) return;
return callback(err);
});
ps.on('exit', function() {
if (!callback) return;
if (!buf.trim()) {
// Bug: w3mimgdisplay will sometimes
// output nothing. Try again:
return self.termSize(callback);
}
var size = buf.trim().split(/\s+/);
return callback(null, {
raw: buf.trim(),
width: +size[0],
height: +size[1]
});
});
ps.stdin.end();
};
W3MImage.prototype.getPixelRatio = function(callback) {
var self = this;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.getPixelRatioSync());
} catch (e) {
return callback(e);
}
}
// XXX We could cache this, but sometimes it's better
// to recalculate to be pixel perfect.
if (this._ratio && !this._needsRatio) {
return callback(null, this._ratio);
}
return this.termSize(function(err, dimensions) {
if (err) return callback(err);
self._ratio = {
tw: dimensions.width / self.screen.width,
th: dimensions.height / self.screen.height
};
self._needsRatio = false;
return callback(null, self._ratio);
});
};
W3MImage.prototype.renderImageSync = function(img, ratio) {
var self = this;
if (W3MImage.hasW3MDisplay === false) {
throw new Error('W3M Image Display not available.');
}
if (!ratio) {
throw new Error('No ratio.');
}
// clearImage unsets these:
var _file = this.file;
var _lastSize = this._lastSize;
this.clearImageSync();
this.file = _file;
this._lastSize = _lastSize;
var width = this.width * ratio.tw | 0
, height = this.height * ratio.th | 0
, aleft = this.aleft * ratio.tw | 0
, atop = this.atop * ratio.th | 0;
var input = '0;1;'
+ aleft + ';'
+ atop + ';'
+ width + ';'
+ height + ';;;;;'
+ img
+ '\n4;\n3;\n';
this._props = {
aleft: aleft,
atop: atop,
width: width,
height: height
};
try {
cp.execFileSync(W3MImage.w3mdisplay, [], {
env: process.env,
encoding: 'utf8',
input: input,
timeout: 1000
});
} catch (e) {
;
}
return true;
};
W3MImage.prototype.clearImageSync = function() {
if (W3MImage.hasW3MDisplay === false) {
throw new Error('W3M Image Display not available.');
}
if (!this._props) {
return false;
}
var width = this._props.width + 2
, height = this._props.height + 2
, aleft = this._props.aleft
, atop = this._props.atop;
if (this._drag) {
aleft -= 10;
atop -= 10;
width += 10;
height += 10;
}
var input = '6;'
+ aleft + ';'
+ atop + ';'
+ width + ';'
+ height
+ '\n4;\n3;\n';
delete this.file;
delete this._props;
delete this._lastSize;
try {
cp.execFileSync(W3MImage.w3mdisplay, [], {
env: process.env,
encoding: 'utf8',
input: input,
timeout: 1000
});
} catch (e) {
;
}
return true;
};
W3MImage.prototype.imageSizeSync = function() {
var img = this.file;
if (W3MImage.hasW3MDisplay === false) {
throw new Error('W3M Image Display not available.');
}
if (!img) {
throw new Error('No image.');
}
var buf = '';
var input = '5;' + img + '\n';
try {
buf = cp.execFileSync(W3MImage.w3mdisplay, [], {
env: process.env,
encoding: 'utf8',
input: input,
timeout: 1000
});
} catch (e) {
;
}
var size = buf.trim().split(/\s+/);
return {
raw: buf.trim(),
width: +size[0],
height: +size[1]
};
};
W3MImage.prototype.termSizeSync = function(_, recurse) {
if (W3MImage.hasW3MDisplay === false) {
throw new Error('W3M Image Display not available.');
}
var buf = '';
try {
buf = cp.execFileSync(W3MImage.w3mdisplay, ['-test'], {
env: process.env,
encoding: 'utf8',
timeout: 1000
});
} catch (e) {
;
}
if (!buf.trim()) {
// Bug: w3mimgdisplay will sometimes
// output nothing. Try again:
recurse = recurse || 0;
if (++recurse === 5) {
throw new Error('Term size not determined.');
}
return this.termSizeSync(_, recurse);
}
var size = buf.trim().split(/\s+/);
return {
raw: buf.trim(),
width: +size[0],
height: +size[1]
};
};
W3MImage.prototype.getPixelRatioSync = function() {
var self = this;
// XXX We could cache this, but sometimes it's better
// to recalculate to be pixel perfect.
if (this._ratio && !this._needsRatio) {
return this._ratio;
}
this._needsRatio = false;
var dimensions = this.termSizeSync();
this._ratio = {
tw: dimensions.width / this.screen.width,
th: dimensions.height / this.screen.height
};
return this._ratio;
};
W3MImage.prototype.displayImage = function(callback) {
return this.screen.displayImage(this.file, callback);
};
/**
* Expose
*/
module.exports = W3MImage;