html显示字符画,ASCII码艺术(字符图像)在线生成器

JavaScript

语言:

JaveScriptBabelCoffeeScript

确定

var ColorPalette;

(function(ColorPalette) {

ColorPalette["Monochrome"] = "none";

ColorPalette["Grey2Bit"] = "grey2bit";

ColorPalette["Grey4Bit"] = "grey4bit";

ColorPalette["Grey8Bit"] = "grey8bit";

ColorPalette["Color3Bit"] = "color3bit";

ColorPalette["Color4Bit"] = "color4bit";

ColorPalette["ColorFull"] = "color";

})(ColorPalette || (ColorPalette = {}));

var AsciiArtGenerator = /** @class */ (function() {

function AsciiArtGenerator() {

var _this = this;

this.settings = {

charSet: ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~',

url: '/assets/coolgirl.jpg',

charSamples: 1,

size: 50,

contrast: 0,

brightness: 0,

alpha: 0,

ColorPalette: ColorPalette.Grey2Bit,

debug: false,

isDemoRunning: true,

saveAsHtml: function() {

_this.asciiElement.style.setProperty('--width', _this.width.toString());

_this.asciiElement.style.setProperty('--height', _this.height.toString());

var blob = new Blob([_this.asciiElement.outerHTML]);

_this.exportElement.href = URL.createObjectURL(blob);

_this.exportElement.click();

}

};

this.demoDirection = -1;

this.demoSettings = [{

url: '/assets/coolgirl.jpg',

size: 50,

charSamples: 1

}, {

url: '/assets/coolboy.jpg',

size: 60,

charSamples: 1

}];

this.demoIndex = 0;

this.isImageLoaded = false;

this.charRegions = {};

this.colorMap = [];

this.valueMap = [];

this.normalizedMap = [];

this.width = 0;

this.height = 0;

this.cachedUrls = {};

this.colorPalettes = {};

var elements = this.elements;

this.asciiElement = elements.asciiElement;

this.exportElement = elements.exportElement;

this.debugImageElement = elements.debugImageElement;

this.debugCharsElement = elements.debugCharsElement;

this.initGui();

this.generatePalettes();

this.analyzeCharRegions();

this.loadFromUrl();

this.initDemo();

}

AsciiArtGenerator.prototype.initDemo = function() {

var _this = this;

this.demo();

var stopDemo = function() {

_this.settings.isDemoRunning = false;

window.removeEventListener('mousedown', stopDemo);

};

window.addEventListener('mousedown', stopDemo);

};

AsciiArtGenerator.prototype.initGui = function() {

var _this = this;

var gui = new dat.GUI();

gui.add(this.settings, 'charSet').onChange(function() {

_this.analyzeCharRegions();

_this.generate();

});

gui.add(this.settings, 'url').listen().onChange(function() {

return _this.loadFromUrl();

});

gui.add(this.settings, 'charSamples', 1, 3, 1).listen().onChange(function() {

_this.analyzeCharRegions();

_this.loadFromUrl();

});

gui.add(this.settings, 'size', 10, 150, 1).listen().onChange(function() {

return _this.loadFromUrl();

});

gui.add(this.settings, 'contrast', -1, 1, 0.01).onChange(function() {

_this.normalizeValueMap();

_this.generate();

});

gui.add(this.settings, 'brightness', -1, 1, 0.01).listen().onChange(function() {

_this.normalizeValueMap();

_this.generate();

});

gui.add(this.settings, 'alpha', -1, 1, 0.01).onChange(function() {

return _this.generate();

});

gui.add(this.settings, 'ColorPalette', ColorPalette).onChange(function() {

_this.generate();

});

gui.add(this.settings, 'debug').onChange(function() {

_this.analyzeCharRegions();

_this.loadFromUrl();

});

gui.add(this.settings, 'isDemoRunning').listen().onChange(function() {

if (_this.settings.isDemoRunning) {

_this.demo();

}

});

gui.add(this.settings, 'saveAsHtml');

};

Object.defineProperty(AsciiArtGenerator.prototype, "elements", {

get: function() {

var asciiElement = document.getElementById('ascii');

if (!asciiElement)

throw '#ascii Element is missing';

var exportElement = document.getElementById('export');

if (!exportElement)

throw '#export Element is missing';

var debugImageElement = document.getElementById('debug-image');

if (!debugImageElement)

throw '#debug-image Element is missing';

var debugCharsElement = document.getElementById('debug-chars');

if (!debugCharsElement)

throw '#debug-chars Element is missing';

return {

asciiElement: asciiElement,

exportElement: exportElement,

debugImageElement: debugImageElement,

debugCharsElement: debugCharsElement

};

},

enumerable: true,

configurable: true

});

AsciiArtGenerator.prototype.generatePalettes = function() {

this.colorPalettes[ColorPalette.Grey2Bit] = [

[0, 0, 0],

[104, 104, 104],

[184, 184, 184],

[255, 255, 255],

];

this.colorPalettes[ColorPalette.Grey4Bit] = [];

for (var i = 0; i < 16; i += 1) {

this.colorPalettes[ColorPalette.Grey4Bit].push([i * 17, i * 17, i * 17]);

}

this.colorPalettes[ColorPalette.Grey8Bit] = [];

for (var i = 0; i < 256; i += 1) {

this.colorPalettes[ColorPalette.Grey8Bit].push([i, i, i]);

}

this.colorPalettes[ColorPalette.Color3Bit] = [

[0, 0, 0],

[0, 249, 45],

[0, 252, 254],

[255, 48, 21],

[255, 62, 253],

[254, 253, 52],

[16, 37, 251],

[255, 255, 255],

];

this.colorPalettes[ColorPalette.Color4Bit] = this.colorPalettes[ColorPalette.Color3Bit].slice();

for (var i = 1; i < 8; i += 1) {

this.colorPalettes[ColorPalette.Color4Bit].push([i * 32, i * 32, i * 32]);

}

};

AsciiArtGenerator.prototype.analyzeChar = function(char) {

var canvas = document.createElement('canvas');

canvas.width = 12;

canvas.height = 12;

var ctx = canvas.getContext('2d');

if (!ctx)

throw 'context creation failed';

ctx.font = '12px monospace';

ctx.fillText(char, 2, 10);

var data = ctx.getImageData(0, 0, 12, 12).data;

var values = [];

var size = 12 / this.settings.charSamples;

for (var cellY = 0; cellY < this.settings.charSamples; cellY += 1) {

for (var cellX = 0; cellX < this.settings.charSamples; cellX += 1) {

var value = 0;

for (var posY = 0; posY < size; posY += 1) {

for (var posX = 0; posX < size; posX += 1) {

value += data[(cellX * size + posX + (cellY * size + posY) * 12) * 4 + 3];

}

}

values.push(value / (size * size) / 255);

}

}

if (this.settings.debug) {

this.debugCharsElement.appendChild(canvas);

for (var cellX = 0; cellX < this.settings.charSamples; cellX += 1) {

for (var cellY = 0; cellY < this.settings.charSamples; cellY += 1) {

ctx.fillStyle = "rgba(255, 0, 255, " + values[cellX + cellY * this.settings.charSamples] + ")";

ctx.fillRect(cellX * size, cellY * size, size, size);

}

}

console.log({

char: char,

values: values

});

}

this.charRegions[char] = values;

};

AsciiArtGenerator.prototype.normalizeCharRegions = function() {

var min = 1;

var max = 0;

for (var char in this.charRegions) {

// let value = 0;

for (var _i = 0, _a = this.charRegions[char]; _i < _a.length; _i++) {

var region = _a[_i];

if (min > region)

min = region;

if (max < region)

max = region;

}

// value /= this.settings.charSamples * this.settings.charSamples;

// if (min > value) min = value;

// if (max < value) max = value;

}

if (max > 0 && min != max) {

var diff = max - min;

for (var char in this.charRegions) {

var regions = this.charRegions[char];

for (var index = 0; index < regions.length; index += 1) {

regions[index] = (regions[index] - min) * (1 / diff);

}

}

}

if (this.settings.debug) {

console.log({

min: min,

max: max,

charRegions: this.charRegions

});

}

};

AsciiArtGenerator.prototype.analyzeCharRegions = function() {

this.clearElement(this.debugCharsElement);

this.charRegions = {};

for (var _i = 0, _a = this.settings.charSet; _i < _a.length; _i++) {

var char = _a[_i];

this.analyzeChar(char);

}

this.normalizeCharRegions();

};

AsciiArtGenerator.prototype.loadFromUrl = function() {

var _this = this;

this.isImageLoaded = false;

if (this.cachedUrls[this.settings.url]) {

this.onImageLoaded(this.cachedUrls[this.settings.url]);

} else {

var img_1 = document.createElement('img');

img_1.crossOrigin = 'Anonymous';

img_1.src = this.settings.url;

img_1.addEventListener('load', function() {

_this.cachedUrls[_this.settings.url] = img_1;

_this.onImageLoaded(img_1);

});

img_1.addEventListener('error', function() {

var urls = Object.keys(_this.cachedUrls);

if (urls.length > 0) {

_this.onImageLoaded(_this.cachedUrls[urls[urls.length - 1]]);

}

});

}

};

AsciiArtGenerator.prototype.onImageLoaded = function(img) {

this.width = this.settings.size;

this.height = ~~((img.height / img.width) * this.width / 1.9);

var canvas = document.createElement('canvas');

canvas.width = this.width * this.settings.charSamples;

canvas.height = this.height * this.settings.charSamples;

var ctx = canvas.getContext('2d');

if (!ctx)

throw 'context creation failed';

ctx.drawImage(img, 0, 0, this.width * this.settings.charSamples, this.height * this.settings.charSamples);

this.clearElement(this.debugImageElement);

if (this.settings.debug) {

this.debugImageElement.appendChild(canvas);

console.log({

img: img,

width: this.width,

height: this.height

});

}

document.body.style.setProperty('--width', this.width.toString());

document.body.style.setProperty('--height', this.height.toString());

this.generateValueMap(ctx);

this.isImageLoaded = true;

};

AsciiArtGenerator.prototype.generateValueMap = function(ctx) {

this.valueMap = [];

this.colorMap = [];

var data = Array.from(ctx.getImageData(0, 0, this.width * this.settings.charSamples, this.height * this.settings.charSamples).data);

var rowLength = this.width * this.settings.charSamples * 4;

for (var cellY = 0; cellY < this.height; cellY += 1) {

for (var cellX = 0; cellX < this.width; cellX += 1) {

var cell = [];

var pos = (cellX * this.settings.charSamples) * 4 + (cellY * this.settings.charSamples) * rowLength;

this.colorMap.push(data.slice(pos, pos + 4));

for (var posY = 0; posY < this.settings.charSamples; posY += 1) {

for (var posX = 0; posX < this.settings.charSamples; posX += 1) {

var pos_1 = (cellX * this.settings.charSamples + posX) * 4 + (cellY * this.settings.charSamples + posY) * rowLength;

var alpha = data[pos_1 + 3] / 255;

var values = data.slice(pos_1, pos_1 + 3);

var value = 1 - ((values[0] + values[1] + values[2]) / 765 * (alpha) + 1 - alpha);

if (this.settings.debug) {

ctx.fillStyle = "rgba(255, 0, 255, " + value + ")";

ctx.fillRect(cellX * this.settings.charSamples + posX, cellY * this.settings.charSamples + posY, 1, 1);

}

cell.push(value);

}

}

this.valueMap.push(cell);

}

}

if (this.settings.debug) {

console.log({

valueMap: this.valueMap,

colorMap: this.colorMap

});

}

this.normalizeValueMap();

this.generate();

};

AsciiArtGenerator.prototype.normalizeValueMap = function() {

var min = 1;

var max = 0;

for (var _i = 0, _a = this.valueMap; _i < _a.length; _i++) {

var regions = _a[_i];

// const value = 0;

for (var _b = 0, regions_1 = regions; _b < regions_1.length; _b++) {

var region = regions_1[_b];

if (min > region)

min = region;

if (max < region)

max = region;

}

}

if (max > 0 && min != max) {

var diff = max - min;

this.normalizedMap = [];

for (var _c = 0, _d = this.valueMap; _c < _d.length; _c++) {

var regions = _d[_c];

var normals = Array.from(regions);

for (var index = 0; index < normals.length; index += 1) {

normals[index] = (normals[index] - min) * (1 / diff);

normals[index] = (this.settings.contrast + 1) * (normals[index] - 0.5) + 0.5 + this.settings.brightness;

}

this.normalizedMap.push(normals);

}

} else {

this.normalizedMap = this.valueMap;

}

if (this.settings.debug) {

console.log({

min: min,

max: max,

valueMap: this.valueMap

});

}

};

AsciiArtGenerator.prototype.getClosestChar = function(values) {

var minDiff = Number.MAX_VALUE;

var minChar = '';

for (var char in this.charRegions) {

var regions = this.charRegions[char];

var diff = 0;

for (var index = 0; index < regions.length; index++) {

diff += Math.abs(regions[index] - values[index]);

}

if (diff < minDiff) {

minDiff = diff;

minChar = char;

}

}

return minChar;

};

AsciiArtGenerator.prototype.clearElement = function(element) {

while (element.firstChild) {

element.removeChild(element.firstChild);

}

};

AsciiArtGenerator.prototype.arrayToRgba = function(color) {

var r = color[3] > 0 ? ~~color[0] : 255;

var g = color[3] > 0 ? ~~color[1] : 255;

var b = color[3] > 0 ? ~~color[2] : 255;

var a = Math.max(0, Math.min(1, color[3] / 255 + this.settings.alpha));

return "rgba(" + r + "," + g + "," + b + "," + a + ")";

};

AsciiArtGenerator.prototype.getCharColor = function(color) {

if (this.settings.ColorPalette === ColorPalette.ColorFull) {

return this.arrayToRgba(color);

} else {

var closestColor = [0, 0, 0];

var minDiff = Number.MAX_VALUE;

for (var _i = 0, _a = this.colorPalettes[this.settings.ColorPalette]; _i < _a.length; _i++) {

var paletteColor = _a[_i];

var diff = Math.abs(color[0] - paletteColor[0]) + Math.abs(color[1] - paletteColor[1]) + Math.abs(color[2] - paletteColor[2]);

if (diff < minDiff) {

minDiff = diff;

closestColor = paletteColor;

}

}

return this.arrayToRgba(closestColor.concat([color[3]]));

}

};

AsciiArtGenerator.prototype.generate = function() {

this.clearElement(this.asciiElement);

for (var cellY = 0; cellY < this.height; cellY += 1) {

for (var cellX = 0; cellX < this.width; cellX += 1) {

var cell = document.createElement('div');

if (this.settings.ColorPalette !== ColorPalette.Monochrome) {

cell.style.color = this.getCharColor(this.colorMap[cellX + cellY * this.width]);

}

cell.innerHTML = this.getClosestChar(this.normalizedMap[cellX + cellY * this.width]).replace(' ', ' ');

this.asciiElement.appendChild(cell);

}

}

};

AsciiArtGenerator.prototype.demo = function() {

var _this = this;

if (this.settings.isDemoRunning) {

if (this.isImageLoaded) {

this.settings.brightness += 0.05 * this.demoDirection;

this.normalizeValueMap();

this.generate();

if (this.settings.brightness >= 0.5 || this.settings.brightness <= -1) {

this.demoDirection *= -1;

}

if (this.settings.brightness <= -1) {

this.demoIndex = (this.demoIndex + 1) % this.demoSettings.length;

this.settings.url = this.demoSettings[this.demoIndex].url;

this.settings.size = this.demoSettings[this.demoIndex].size;

this.settings.charSamples = this.demoSettings[this.demoIndex].charSamples;

this.analyzeCharRegions();

this.loadFromUrl();

}

}

requestAnimationFrame(function() {

return _this.demo();

});

}

};

return AsciiArtGenerator;

}());

var generator = new AsciiArtGenerator();

console.log(generator);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值