mirror of
https://github.com/rastapasta/mapscii.git
synced 2024-11-21 23:53:08 +01:00
Decaffeinate BrailleBuffer class
This commit is contained in:
parent
9d9ef31f7b
commit
d27e086758
@ -1,156 +0,0 @@
|
||||
###
|
||||
termap - Terminal Map Viewer
|
||||
by Michael Strassburger <codepoet@cpan.org>
|
||||
|
||||
Simple pixel to barille character mapper
|
||||
|
||||
Implementation inspired by node-drawille (https://github.com/madbence/node-drawille)
|
||||
* added color support
|
||||
* added text label support
|
||||
* general optimizations
|
||||
|
||||
Will either be merged into node-drawille or become an own module at some point
|
||||
###
|
||||
stringWidth = require 'string-width'
|
||||
config = require './config'
|
||||
utils = require './utils'
|
||||
|
||||
module.exports = class BrailleBuffer
|
||||
brailleMap: [[0x1, 0x8],[0x2, 0x10],[0x4, 0x20],[0x40, 0x80]]
|
||||
asciiMap:
|
||||
# "▬": [2+32, 4+64]
|
||||
# "¯": [1+16]
|
||||
"▀": [1+2+16+32]
|
||||
"▄": [4+8+64+128]
|
||||
"■": [2+4+32+64]
|
||||
"▌": [1+2+4+8]
|
||||
"▐": [16+32+64+128]
|
||||
# "▓": [1+4+32+128, 2+8+16+64]
|
||||
"█": [255]
|
||||
|
||||
pixelBuffer: null
|
||||
charBuffer: null
|
||||
foregroundBuffer: null
|
||||
backgroundBuffer: null
|
||||
|
||||
asciiToBraille: []
|
||||
|
||||
globalBackground: null
|
||||
|
||||
termReset: "\x1B[39;49m"
|
||||
|
||||
constructor: (@width, @height) ->
|
||||
size = @width*@height/8
|
||||
@pixelBuffer = new Buffer size
|
||||
@foregroundBuffer = new Buffer size
|
||||
@backgroundBuffer = new Buffer size
|
||||
|
||||
@_mapBraille()
|
||||
@clear()
|
||||
|
||||
clear: ->
|
||||
@pixelBuffer.fill 0
|
||||
@charBuffer = []
|
||||
@foregroundBuffer.fill 0
|
||||
@backgroundBuffer.fill 0
|
||||
|
||||
setGlobalBackground: (@globalBackground) ->
|
||||
|
||||
setBackground: (x, y, color) ->
|
||||
return unless 0 <= x < @width and 0 <= y < @height
|
||||
idx = @_project x, y
|
||||
@backgroundBuffer[idx] = color
|
||||
|
||||
setPixel: (x, y, color) ->
|
||||
@_locate x, y, (idx, mask) =>
|
||||
@pixelBuffer[idx] |= mask
|
||||
@foregroundBuffer[idx] = color
|
||||
|
||||
unsetPixel: (x, y) ->
|
||||
@_locate x, y, (idx, mask) =>
|
||||
@pixelBuffer[idx] &= ~mask
|
||||
|
||||
_project: (x, y) ->
|
||||
(x>>1) + (@width>>1)*(y>>2)
|
||||
|
||||
_locate: (x, y, cb) ->
|
||||
return unless 0 <= x < @width and 0 <= y < @height
|
||||
idx = @_project x, y
|
||||
mask = @brailleMap[y&3][x&1]
|
||||
cb idx, mask
|
||||
|
||||
_mapBraille: ->
|
||||
@asciiToBraille = [" "]
|
||||
|
||||
masks = []
|
||||
for char, bits of @asciiMap
|
||||
continue unless bits instanceof Array
|
||||
masks.push mask: mask, char: char for mask in bits
|
||||
|
||||
for i in [1..255]
|
||||
braille = (i&7) + ((i&56)<<1) + ((i&64)>>3) + (i&128)
|
||||
|
||||
@asciiToBraille[i] = masks.reduce(((best, mask) ->
|
||||
covered = utils.population(mask.mask&braille)
|
||||
if not best or best.covered < covered
|
||||
char: mask.char, covered: covered
|
||||
else
|
||||
best
|
||||
), undefined).char
|
||||
|
||||
_termColor: (foreground, background) ->
|
||||
background = background or @globalBackground
|
||||
if foreground and background
|
||||
"\x1B[38;5;#{foreground};48;5;#{background}m"
|
||||
else if foreground
|
||||
"\x1B[49;38;5;#{foreground}m"
|
||||
else if background
|
||||
"\x1B[39;48;5;#{background}m"
|
||||
else
|
||||
@termReset
|
||||
|
||||
frame: ->
|
||||
output = []
|
||||
currentColor = null
|
||||
skip = 0
|
||||
|
||||
for y in [0...@height/4]
|
||||
skip = 0
|
||||
|
||||
for x in [0...@width/2]
|
||||
idx = y*@width/2 + x
|
||||
|
||||
if idx and not x
|
||||
output.push config.delimeter
|
||||
|
||||
if currentColor isnt colorCode = @_termColor @foregroundBuffer[idx], @backgroundBuffer[idx]
|
||||
output.push currentColor = colorCode
|
||||
|
||||
output.push if char = @charBuffer[idx]
|
||||
skip += stringWidth(char)-1
|
||||
if skip+x >= @width/2
|
||||
''
|
||||
else
|
||||
char
|
||||
else
|
||||
if not skip
|
||||
if config.useBraille
|
||||
String.fromCharCode 0x2800+@pixelBuffer[idx]
|
||||
else
|
||||
@asciiToBraille[@pixelBuffer[idx]]
|
||||
else
|
||||
skip--
|
||||
''
|
||||
|
||||
output.push @termReset+config.delimeter
|
||||
output.join ''
|
||||
|
||||
setChar: (char, x, y, color) ->
|
||||
return unless 0 <= x < @width and 0 <= y < @height
|
||||
idx = @_project x, y
|
||||
@charBuffer[idx] = char
|
||||
@foregroundBuffer[idx] = color
|
||||
|
||||
writeText: (text, x, y, color, center = true) ->
|
||||
x -= text.length/2+1 if center
|
||||
@setChar text.charAt(i), x+i*2, y, color for i in [0...text.length]
|
211
src/BrailleBuffer.js
Normal file
211
src/BrailleBuffer.js
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
termap - Terminal Map Viewer
|
||||
by Michael Strassburger <codepoet@cpan.org>
|
||||
|
||||
Simple pixel to barille character mapper
|
||||
|
||||
Implementation inspired by node-drawille (https://github.com/madbence/node-drawille)
|
||||
* added color support
|
||||
* added text label support
|
||||
* general optimizations
|
||||
|
||||
Will either be merged into node-drawille or become an own module at some point
|
||||
*/
|
||||
'use strict';
|
||||
const stringWidth = require('string-width');
|
||||
const config = require('./config');
|
||||
const utils = require('./utils');
|
||||
|
||||
const asciiMap = {
|
||||
// '▬': [2+32, 4+64],
|
||||
// '¯': [1+16],
|
||||
'▀': [1+2+16+32],
|
||||
'▄': [4+8+64+128],
|
||||
'■': [2+4+32+64],
|
||||
'▌': [1+2+4+8],
|
||||
'▐': [16+32+64+128],
|
||||
// '▓': [1+4+32+128, 2+8+16+64],
|
||||
'█': [255],
|
||||
};
|
||||
const termReset = '\x1B[39;49m';
|
||||
|
||||
class BrailleBuffer {
|
||||
constructor(width, height) {
|
||||
this.brailleMap = [[0x1, 0x8],[0x2, 0x10],[0x4, 0x20],[0x40, 0x80]]
|
||||
|
||||
this.pixelBuffer = null;
|
||||
this.charBuffer = null;
|
||||
this.foregroundBuffer = null;
|
||||
this.backgroundBuffer = null;
|
||||
|
||||
this.asciiToBraille = [];
|
||||
|
||||
this.globalBackground = null;
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
const size = width*height/8;
|
||||
this.pixelBuffer = new Buffer(size);
|
||||
this.foregroundBuffer = new Buffer(size);
|
||||
this.backgroundBuffer = new Buffer(size);
|
||||
|
||||
this._mapBraille();
|
||||
this.clear();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.pixelBuffer.fill(0);
|
||||
this.charBuffer = [];
|
||||
this.foregroundBuffer.fill(0);
|
||||
this.backgroundBuffer.fill(0);
|
||||
}
|
||||
|
||||
setGlobalBackground(background) {
|
||||
this.globalBackground = background;
|
||||
}
|
||||
|
||||
setBackground(x, y, color) {
|
||||
if (0 <= x && x < this.width && 0 <= y && y < this.height) {
|
||||
idx = this._project(x, y);
|
||||
this.backgroundBuffer[idx] = color;
|
||||
}
|
||||
}
|
||||
|
||||
setPixel(x, y, color) {
|
||||
this._locate(x, y, (idx, mask) => {
|
||||
this.pixelBuffer[idx] |= mask;
|
||||
this.foregroundBuffer[idx] = color;
|
||||
});
|
||||
}
|
||||
|
||||
unsetPixel(x, y) {
|
||||
this._locate(x, y, (idx, mask) => {
|
||||
this.pixelBuffer[idx] &= ~mask;
|
||||
});
|
||||
}
|
||||
|
||||
_project(x, y) {
|
||||
return (x>>1) + (this.width>>1)*(y>>2);
|
||||
}
|
||||
|
||||
_locate(x, y, cb) {
|
||||
if (!((0 <= x && x < this.width) && (0 <= y && y < this.height))) {
|
||||
return;
|
||||
}
|
||||
const idx = this._project(x, y);
|
||||
const mask = this.brailleMap[y & 3][x & 1];
|
||||
return cb(idx, mask);
|
||||
}
|
||||
|
||||
_mapBraille() {
|
||||
this.asciiToBraille = [' '];
|
||||
|
||||
const masks = [];
|
||||
for (const char in asciiMap) {
|
||||
const bits = asciiMap[char];
|
||||
if (!(bits instanceof Array)) continue;
|
||||
for (const mask of bits) {
|
||||
masks.push({
|
||||
mask: mask,
|
||||
char: char,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//TODO Optimize this part
|
||||
var i, k;
|
||||
const results = [];
|
||||
for (i = k = 1; k <= 255; i = ++k) {
|
||||
const braille = (i & 7) + ((i & 56) << 1) + ((i & 64) >> 3) + (i & 128);
|
||||
results.push(this.asciiToBraille[i] = masks.reduce((function(best, mask) {
|
||||
const covered = utils.population(mask.mask & braille);
|
||||
if (!best || best.covered < covered) {
|
||||
return {
|
||||
char: mask.char,
|
||||
covered: covered,
|
||||
};
|
||||
} else {
|
||||
return best;
|
||||
}
|
||||
}), void 0).char);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
_termColor(foreground, background) {
|
||||
background |= this.globalBackground;
|
||||
if (foreground && background) {
|
||||
return `\x1B[38;5;${foreground};48;5;${background}m`;
|
||||
} else if (foreground) {
|
||||
return `\x1B[49;38;5;${foreground}m`;
|
||||
} else if (background) {
|
||||
return `\x1B[39;48;5;${background}m`;
|
||||
} else {
|
||||
return termReset;
|
||||
}
|
||||
}
|
||||
|
||||
frame() {
|
||||
const output = [];
|
||||
let currentColor = null;
|
||||
let skip = 0;
|
||||
|
||||
for (let y = 0; y < this.height/4; y++) {
|
||||
skip = 0;
|
||||
|
||||
for (let x = 0; x < this.width/2; x++) {
|
||||
const idx = y*this.width/2 + x;
|
||||
|
||||
if (idx && !x) {
|
||||
output.push(config.delimeter);
|
||||
}
|
||||
|
||||
const colorCode = this._termColor(this.foregroundBuffer[idx], this.backgroundBuffer[idx]);
|
||||
if (currentColor !== colorCode) {
|
||||
output.push(currentColor = colorCode);
|
||||
}
|
||||
|
||||
const char = this.charBuffer[idx];
|
||||
if (char) {
|
||||
skip += stringWidth(char)-1;
|
||||
if (skip+x < this.width/2) {
|
||||
output.push(char);
|
||||
}
|
||||
} else {
|
||||
if (!skip) {
|
||||
if (config.useBraille) {
|
||||
output.push(String.fromCharCode(0x2800+this.pixelBuffer[idx]));
|
||||
} else {
|
||||
output.push(this.asciiToBraille[this.pixelBuffer[idx]]);
|
||||
}
|
||||
} else {
|
||||
skip--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output.push(termReset+config.delimeter);
|
||||
return output.join('');
|
||||
}
|
||||
|
||||
setChar(char, x, y, color) {
|
||||
if (0 <= x && x < this.width && 0 <= y && y < this.height) {
|
||||
const idx = this._project(x, y);
|
||||
this.charBuffer[idx] = char;
|
||||
this.foregroundBuffer[idx] = color;
|
||||
}
|
||||
}
|
||||
|
||||
writeText(text, x, y, color, center = true) {
|
||||
if (center) {
|
||||
x -= text.length/2+1;
|
||||
}
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
this.setChar(text.charAt(i), x+i*2, y, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BrailleBuffer;
|
Loading…
Reference in New Issue
Block a user