public/js/file.js
var Load = (function() {
"use strict";
function File(bytes) {
var pos, SAUCE_ID, COMNT_ID, commentCount;
SAUCE_ID = new Uint8Array([0x53, 0x41, 0x55, 0x43, 0x45]);
COMNT_ID = new Uint8Array([0x43, 0x4F, 0x4D, 0x4E, 0x54]);
this.get = function() {
if (pos >= bytes.length) {
throw "Unexpected end of file reached.";
}
pos += 1;
return bytes[pos - 1];
};
this.get16 = function() {
var v;
v = this.get();
return v + (this.get() << 8);
};
this.get32 = function() {
var v;
v = this.get();
v += this.get() << 8;
v += this.get() << 16;
return v + (this.get() << 24);
};
this.getC = function() {
return String.fromCharCode(this.get());
};
this.getS = function(num) {
var string;
string = "";
while (num > 0) {
string += this.getC();
num -= 1;
}
return string.replace(/\s+$/, "");
};
this.lookahead = function(match) {
var i;
for (i = 0; i < match.length; i += 1) {
if ((pos + i === bytes.length) || (bytes[pos + i] !== match[i])) {
break;
}
}
return i === match.length;
};
this.read = function(num) {
var t;
t = pos;
num = num || this.size - pos;
while ((pos += 1) < this.size) {
num -= 1;
if (num === 0) {
break;
}
}
return bytes.subarray(t, pos);
};
this.seek = function(newPos) {
pos = newPos;
};
this.peek = function(num) {
num = num || 0;
return bytes[pos + num];
};
this.getPos = function() {
return pos;
};
this.eof = function() {
return pos === this.size;
};
pos = bytes.length - 128;
if (this.lookahead(SAUCE_ID)) {
this.sauce = {};
this.getS(5);
this.sauce.version = this.getS(2); // String, maximum of 2 characters
this.sauce.title = this.getS(35); // String, maximum of 35 characters
this.sauce.author = this.getS(20); // String, maximum of 20 characters
this.sauce.group = this.getS(20); // String, maximum of 20 characters
this.sauce.date = this.getS(8); // String, maximum of 8 characters
this.sauce.fileSize = this.get32(); // unsigned 32-bit
this.sauce.dataType = this.get(); // unsigned 8-bit
this.sauce.fileType = this.get(); // unsigned 8-bit
this.sauce.tInfo1 = this.get16(); // unsigned 16-bit
this.sauce.tInfo2 = this.get16(); // unsigned 16-bit
this.sauce.tInfo3 = this.get16(); // unsigned 16-bit
this.sauce.tInfo4 = this.get16(); // unsigned 16-bit
this.sauce.comments = [];
commentCount = this.get(); // unsigned 8-bit
this.sauce.flags = this.get(); // unsigned 8-bit
if (commentCount > 0) {
pos = bytes.length - 128 - (commentCount * 64) - 5;
if (this.lookahead(COMNT_ID)) {
this.getS(5);
while (commentCount > 0) {
this.sauce.comments.push(this.getS(64));
commentCount -= 1;
}
}
}
}
pos = 0;
if (this.sauce) {
if (this.sauce.fileSize > 0 && this.sauce.fileSize < bytes.length) {
this.size = this.sauce.fileSize;
} else {
this.size = bytes.length - 128;
}
} else {
this.size = bytes.length;
}
}
function ScreenData(width) {
var imageData, maxY, pos;
function binColor(ansiColor) {
switch (ansiColor) {
case 4:
return 1;
case 6:
return 3;
case 1:
return 4;
case 3:
return 6;
case 12:
return 9;
case 14:
return 11;
case 9:
return 12;
case 11:
return 14;
default:
return ansiColor;
}
}
this.reset = function() {
imageData = new Uint8Array(width * 100 * 3);
maxY = 0;
pos = 0;
};
this.reset();
this.raw = function(bytes) {
var i, j;
maxY = Math.ceil(bytes.length / 2 / width);
imageData = new Uint8Array(width * maxY * 3);
for (i = 0, j = 0; j < bytes.length; i += 3, j += 2) {
imageData[i] = bytes[j];
imageData[i + 1] = bytes[j + 1] & 15;
imageData[i + 2] = bytes[j + 1] >> 4;
}
};
function extendImageData(y) {
var newImageData;
newImageData = new Uint8Array(width * (y + 100) * 3 + imageData.length);
newImageData.set(imageData, 0);
imageData = newImageData;
}
this.set = function(x, y, charCode, fg, bg) {
pos = (y * width + x) * 3;
if (pos >= imageData.length) {
extendImageData(y);
}
imageData[pos] = charCode;
imageData[pos + 1] = binColor(fg);
imageData[pos + 2] = binColor(bg);
if (y > maxY) {
maxY = y;
}
};
this.getData = function() {
return imageData.subarray(0, width * (maxY + 1) * 3);
};
this.getHeight = function() {
return maxY + 1;
};
this.rowLength = width * 3;
this.stripBlinking = function() {
var i;
for (i = 2; i < imageData.length; i += 3) {
if (imageData[i] >= 8) {
imageData[i] -= 8;
}
}
};
}
function loadAnsi(bytes) {
var file, escaped, escapeCode, j, code, values, columns, imageData, topOfScreen, x, y, savedX, savedY, foreground, background, bold, blink, inverse;
file = new File(bytes);
function resetAttributes() {
foreground = 7;
background = 0;
bold = false;
blink = false;
inverse = false;
}
resetAttributes();
function newLine() {
x = 1;
if (y === 26 - 1) {
topOfScreen += 1;
} else {
y += 1;
}
}
function setPos(newX, newY) {
x = Math.min(columns, Math.max(1, newX));
y = Math.min(26, Math.max(1, newY));
}
x = 1;
y = 1;
topOfScreen = 0;
escapeCode = "";
escaped = false;
columns = (file.sauce !== undefined) ? file.sauce.tInfo1 : 80;
imageData = new ScreenData(columns);
function getValues() {
return escapeCode.substr(1, escapeCode.length - 2).split(";").map(function(value) {
var parsedValue;
parsedValue = parseInt(value, 10);
return isNaN(parsedValue) ? 1 : parsedValue;
});
}
while (!file.eof()) {
code = file.get();
if (escaped) {
escapeCode += String.fromCharCode(code);
if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122)) {
escaped = false;
values = getValues();
if (escapeCode.charAt(0) === "[") {
switch (escapeCode.charAt(escapeCode.length - 1)) {
case "A": // Up cursor.
y = Math.max(1, y - values[0]);
break;
case "B": // Down cursor.
y = Math.min(26 - 1, y + values[0]);
break;
case "C": // Forward cursor.
if (x === columns) {
newLine();
}
x = Math.min(columns, x + values[0]);
break;
case "D": // Backward cursor.
x = Math.max(1, x - values[0]);
break;
case "H": // Set the cursor position by calling setPos(), first <y>, then <x>.
if (values.length === 1) {
setPos(1, values[0]);
} else {
setPos(values[1], values[0]);
}
break;
case "J": // Clear screen.
if (values[0] === 2) {
x = 1;
y = 1;
imageData.reset();
}
break;
case "K": // Clear until the end of line.
for (j = x - 1; j < columns; j += 1) {
imageData.set(j, y - 1 + topOfScreen, 0, 0);
}
break;
case "m": // Attributes, work through each code in turn.
for (j = 0; j < values.length; j += 1) {
if (values[j] >= 30 && values[j] <= 37) {
foreground = values[j] - 30;
} else if (values[j] >= 40 && values[j] <= 47) {
background = values[j] - 40;
} else {
switch (values[j]) {
case 0: // Reset attributes
resetAttributes();
break;
case 1: // Bold
bold = true;
break;
case 5: // Blink
blink = true;
break;
case 7: // Inverse
inverse = true;
break;
case 22: // Bold off
bold = false;
break;
case 25: // Blink off
blink = false;
break;
case 27: // Inverse off
inverse = false;
break;
}
}
}
break;
case "s": // Save the current <x> and <y> positions.
savedX = x;
savedY = y;
break;
case "u": // Restore the current <x> and <y> positions.
x = savedX;
y = savedY;
break;
}
}
escapeCode = "";
}
} else {
switch (code) {
case 10: // Lone linefeed (LF).
newLine();
break;
case 13: // Carriage Return, and Linefeed (CRLF)
if (file.peek() === 0x0A) {
file.read(1);
newLine();
}
break;
case 26: // Ignore eof characters until the actual end-of-file, or sauce record has been reached.
break;
default:
if (code === 27 && file.peek() === 0x5B) {
escaped = true;
} else {
if (!inverse) {
imageData.set(x - 1, y - 1 + topOfScreen, code, bold ? (foreground + 8) : foreground, blink ? (background + 8) : background);
} else {
imageData.set(x - 1, y - 1 + topOfScreen, code, bold ? (background + 8) : background, blink ? (foreground + 8) : foreground);
}
x += 1;
if (x === columns + 1) {
newLine();
}
}
}
}
}
return {
"width": columns,
"height": imageData.getHeight(),
"data": imageData.getData(),
"noblink": file.sauce ? ((file.sauce.flags & 1) === 1) : false,
"title": file.sauce ? file.sauce.title : "",
"author": file.sauce ? file.sauce.author : "",
"group": file.sauce ? file.sauce.group : ""
};
}
function convertData(data) {
var output = new Uint16Array(data.length / 3);
for (var i = 0, j = 0; i < data.length; i += 1, j += 3) {
output[i] = (data[j] << 8) + (data[j + 2] << 4) + data[j + 1];
}
return output;
}
function bytesToString(bytes, offset, size) {
var text = "", i;
for (i = 0; i < size; i++) {
text += String.fromCharCode(bytes[offset + i]);
}
return text;
}
function getSauce(bytes, defaultColumnValue) {
var sauce, fileSize, dataType, columns, rows, flags;
function removeTrailingWhitespace(text) {
return text.replace(/\s+$/, "");
}
if (bytes.length >= 128) {
sauce = bytes.slice(-128);
if (bytesToString(sauce, 0, 5) === "SAUCE" && bytesToString(sauce, 5, 2) === "00") {
fileSize = (sauce[93] << 24) + (sauce[92] << 16) + (sauce[91] << 8) + sauce[90];
dataType = sauce[94];
if (dataType === 5) {
columns = sauce[95] * 2;
rows = fileSize / columns / 2;
} else {
columns = (sauce[97] << 8) + sauce[96];
rows = (sauce[99] << 8) + sauce[98];
}
flags = sauce[105];
return {
"title": removeTrailingWhitespace(bytesToString(sauce, 7, 35)),
"author": removeTrailingWhitespace(bytesToString(sauce, 42, 20)),
"group": removeTrailingWhitespace(bytesToString(sauce, 62, 20)),
"fileSize": (sauce[93] << 24) + (sauce[92] << 16) + (sauce[91] << 8) + sauce[90],
"columns": columns,
"rows": rows,
"iceColours": (flags & 0x01) === 1,
"letterSpacing": (flags >> 1 & 0x02) === 2
};
}
}
return {
"title": "",
"author": "",
"group": "",
"fileSize": bytes.length,
"columns": defaultColumnValue,
"rows": undefined,
"iceColours": false,
"letterSpacing": false
};
}
function convertUInt8ToUint16(uint8Array, start, size) {
var i, j;
var uint16Array = new Uint16Array(size / 2);
for (i = 0, j = 0; i < size; i += 2, j += 1) {
uint16Array[j] = (uint8Array[start + i] << 8) + uint8Array[start + i + 1];
}
return uint16Array;
}
function loadBin(bytes) {
var sauce = getSauce(bytes, 160);
var data;
if (sauce.rows === undefined) {
sauce.rows = sauce.fileSize / 160 / 2;
}
data = convertUInt8ToUint16(bytes, 0, sauce.columns * sauce.rows * 2);
return {
"columns": sauce.columns,
"rows": sauce.rows,
"data": data,
"iceColours": sauce.iceColours,
"letterSpacing": sauce.letterSpacing,
"title": sauce.title,
"author": sauce.author,
"group": sauce.group
};
}
function uncompress(bytes, dataIndex, fileSize, column, rows) {
var data = new Uint16Array(column * rows);
var i, value, count, j, k, char, attribute;
for (i = dataIndex, j = 0; i < fileSize;) {
value = bytes[i++];
count = value & 0x3F;
switch (value >> 6) {
case 1:
char = bytes[i++];
for (k = 0; k <= count; k++) {
data[j++] = (char << 8) + bytes[i++];
}
break;
case 2:
attribute = bytes[i++];
for (k = 0; k <= count; k++) {
data[j++] = (bytes[i++] << 8) + attribute;
}
break;
case 3:
char = bytes[i++];
attribute = bytes[i++];
for (k = 0; k <= count; k++) {
data[j++] = (char << 8) + attribute;
}
break;
default:
for (k = 0; k <= count; k++) {
data[j++] = (bytes[i++] << 8) + bytes[i++];
}
break;
}
}
return data;
}
function loadXBin(bytes) {
var sauce = getSauce(bytes);
var columns, rows, fontHeight, flags, paletteFlag, fontFlag, compressFlag, iceColoursFlag, font512Flag, dataIndex, data;
if (bytesToString(bytes, 0, 4) === "XBIN" && bytes[4] === 0x1A) {
columns = (bytes[6] << 8) + bytes[5];
rows = (bytes[8] << 8) + bytes[7];
fontHeight = bytes[9];
flags = bytes[10];
paletteFlag = (flags & 0x01) === 1;
fontFlag = (flags >> 1 & 0x01) === 1;
compressFlag = (flags >> 2 & 0x01) === 1;
iceColoursFlag = (flags >> 3 & 0x01) === 1;
font512Flag = (flags >> 4 & 0x01) === 1;
dataIndex = 11;
if (paletteFlag === true) {
dataIndex += 48;
}
if (fontFlag === true) {
if (font512Flag === true) {
dataIndex += 512 * fontHeight;
} else {
dataIndex += 256 * fontHeight;
}
}
if (compressFlag === true) {
data = uncompress(bytes, dataIndex, sauce.fileSize, columns, rows);
} else {
data = convertUInt8ToUint16(bytes, dataIndex, columns * rows * 2);
}
}
return {
"columns": columns,
"rows": rows,
"data": data,
"iceColours": iceColoursFlag,
"letterSpacing": false,
"title": sauce.title,
"author": sauce.author,
"group": sauce.group
};
}
function file(file, callback) {
var reader = new FileReader();
reader.addEventListener("load", function(evt) {
var data = new Uint8Array(reader.result);
var imageData;
switch (file.name.split(".").pop().toLowerCase()) {
case "xb":
imageData = loadXBin(data);
callback(imageData.columns, imageData.rows, imageData.data, imageData.iceColours, imageData.letterSpacing);
break;
case "bin":
imageData = loadBin(data);
callback(imageData.columns, imageData.rows, imageData.data, imageData.iceColours, imageData.letterSpacing);
break;
default:
imageData = loadAnsi(data);
$("sauce-title").value = imageData.title;
$("sauce-group").value = imageData.group;
$("sauce-author").value = imageData.author;
callback(imageData.width, imageData.height, convertData(imageData.data), imageData.noblink, false);
break;
}
});
reader.readAsArrayBuffer(file);
}
return {
"file": file
};
}());
var Save = (function() {
"use strict";
function saveFile(bytes, sauce, filename) {
var outputBytes;
if (sauce !== undefined) {
outputBytes = new Uint8Array(bytes.length + sauce.length);
outputBytes.set(sauce, bytes.length);
} else {
outputBytes = new Uint8Array(bytes.length);
}
outputBytes.set(bytes, 0);
var downloadLink = document.createElement("A");
if ((navigator.userAgent.indexOf("Chrome") === -1) && (navigator.userAgent.indexOf("Safari") !== -1)) {
var base64String = "";
for (var i = 0; i < outputBytes.length; i += 1) {
base64String += String.fromCharCode(outputBytes[i]);
}
downloadLink.href = "data:application/octet-stream;base64," + btoa(base64String);
} else {
var blob = new Blob([outputBytes], { "type": "application/octet-stream" });
downloadLink.href = URL.createObjectURL(blob);
}
downloadLink.download = filename;
var clickEvent = document.createEvent("MouseEvent");
clickEvent.initEvent("click", true, true);
downloadLink.dispatchEvent(clickEvent);
window.URL.revokeObjectURL(downloadLink.href);
}
function createSauce(datatype, filetype, filesize, doFlagsAndTInfoS) {
function addText(text, maxlength, index) {
var i;
for (i = 0; i < maxlength; i += 1) {
sauce[i + index] = (i < text.length) ? text.charCodeAt(i) : 0x20;
}
}
var sauce = new Uint8Array(129);
sauce[0] = 0x1A;
sauce.set(new Uint8Array([0x53, 0x41, 0x55, 0x43, 0x45, 0x30, 0x30]), 1);
addText($("sauce-title").value, 35, 8);
addText($("sauce-author").value, 20, 43);
addText($("sauce-group").value, 20, 63);
var date = new Date();
addText(date.getFullYear().toString(10), 4, 83);
var month = date.getMonth() + 1;
addText((month < 10) ? ("0" + month.toString(10)) : month.toString(10), 2, 87);
var day = date.getDate();
addText((day < 10) ? ("0" + day.toString(10)) : day.toString(10), 2, 89);
sauce[91] = filesize & 0xFF;
sauce[92] = (filesize >> 8) & 0xFF;
sauce[93] = (filesize >> 16) & 0xFF;
sauce[94] = filesize >> 24;
sauce[95] = datatype;
sauce[96] = filetype;
var columns = textArtCanvas.getColumns();
sauce[97] = columns & 0xFF;
sauce[98] = columns >> 8;
var rows = textArtCanvas.getRows();
sauce[99] = rows & 0xFF;
sauce[100] = rows >> 8;
sauce[105] = 0;
if (doFlagsAndTInfoS) {
var flags = 0;
if (textArtCanvas.getIceColours() === true) {
flags += 1;
}
if (font.getLetterSpacing() === false) {
flags += (1 << 1);
} else {
flags += (1 << 2);
}
sauce[106] = flags;
var fontName = "IBM VGA";
addText(fontName, fontName.length, 107);
}
return sauce;
}
function getUnicode(charCode) {
switch (charCode) {
case 1: return 0x263A;
case 2: return 0x263B;
case 3: return 0x2665;
case 4: return 0x2666;
case 5: return 0x2663;
case 6: return 0x2660;
case 7: return 0x2022;
case 8: return 0x25D8;
case 9: return 0x25CB;
case 10: return 0x25D9;
case 11: return 0x2642;
case 12: return 0x2640;
case 13: return 0x266A;
case 14: return 0x266B;
case 15: return 0x263C;
case 16: return 0x25BA;
case 17: return 0x25C4;
case 18: return 0x2195;
case 19: return 0x203C;
case 20: return 0x00B6;
case 21: return 0x00A7;
case 22: return 0x25AC;
case 23: return 0x21A8;
case 24: return 0x2191;
case 25: return 0x2193;
case 26: return 0x2192;
case 27: return 0x2190;
case 28: return 0x221F;
case 29: return 0x2194;
case 30: return 0x25B2;
case 31: return 0x25BC;
case 127: return 0x2302;
case 128: return 0x00C7;
case 129: return 0x00FC;
case 130: return 0x00E9;
case 131: return 0x00E2;
case 132: return 0x00E4;
case 133: return 0x00E0;
case 134: return 0x00E5;
case 135: return 0x00E7;
case 136: return 0x00EA;
case 137: return 0x00EB;
case 138: return 0x00E8;
case 139: return 0x00EF;
case 140: return 0x00EE;
case 141: return 0x00EC;
case 142: return 0x00C4;
case 143: return 0x00C5;
case 144: return 0x00C9;
case 145: return 0x00E6;
case 146: return 0x00C6;
case 147: return 0x00F4;
case 148: return 0x00F6;
case 149: return 0x00F2;
case 150: return 0x00FB;
case 151: return 0x00F9;
case 152: return 0x00FF;
case 153: return 0x00D6;
case 154: return 0x00DC;
case 155: return 0x00A2;
case 156: return 0x00A3;
case 157: return 0x00A5;
case 158: return 0x20A7;
case 159: return 0x0192;
case 160: return 0x00E1;
case 161: return 0x00ED;
case 162: return 0x00F3;
case 163: return 0x00FA;
case 164: return 0x00F1;
case 165: return 0x00D1;
case 166: return 0x00AA;
case 167: return 0x00BA;
case 168: return 0x00BF;
case 169: return 0x2310;
case 170: return 0x00AC;
case 171: return 0x00BD;
case 172: return 0x00BC;
case 173: return 0x00A1;
case 174: return 0x00AB;
case 175: return 0x00BB;
case 176: return 0x2591;
case 177: return 0x2592;
case 178: return 0x2593;
case 179: return 0x2502;
case 180: return 0x2524;
case 181: return 0x2561;
case 182: return 0x2562;
case 183: return 0x2556;
case 184: return 0x2555;
case 185: return 0x2563;
case 186: return 0x2551;
case 187: return 0x2557;
case 188: return 0x255D;
case 189: return 0x255C;
case 190: return 0x255B;
case 191: return 0x2510;
case 192: return 0x2514;
case 193: return 0x2534;
case 194: return 0x252C;
case 195: return 0x251C;
case 196: return 0x2500;
case 197: return 0x253C;
case 198: return 0x255E;
case 199: return 0x255F;
case 200: return 0x255A;
case 201: return 0x2554;
case 202: return 0x2569;
case 203: return 0x2566;
case 204: return 0x2560;
case 205: return 0x2550;
case 206: return 0x256C;
case 207: return 0x2567;
case 208: return 0x2568;
case 209: return 0x2564;
case 210: return 0x2565;
case 211: return 0x2559;
case 212: return 0x2558;
case 213: return 0x2552;
case 214: return 0x2553;
case 215: return 0x256B;
case 216: return 0x256A;
case 217: return 0x2518;
case 218: return 0x250C;
case 219: return 0x2588;
case 220: return 0x2584;
case 221: return 0x258C;
case 222: return 0x2590;
case 223: return 0x2580;
case 224: return 0x03B1;
case 225: return 0x00DF;
case 226: return 0x0393;
case 227: return 0x03C0;
case 228: return 0x03A3;
case 229: return 0x03C3;
case 230: return 0x00B5;
case 231: return 0x03C4;
case 232: return 0x03A6;
case 233: return 0x0398;
case 234: return 0x03A9;
case 235: return 0x03B4;
case 236: return 0x221E;
case 237: return 0x03C6;
case 238: return 0x03B5;
case 239: return 0x2229;
case 240: return 0x2261;
case 241: return 0x00B1;
case 242: return 0x2265;
case 243: return 0x2264;
case 244: return 0x2320;
case 245: return 0x2321;
case 246: return 0x00F7;
case 247: return 0x2248;
case 248: return 0x00B0;
case 249: return 0x2219;
case 250: return 0x00B7;
case 251: return 0x221A;
case 252: return 0x207F;
case 253: return 0x00B2;
case 254: return 0x25A0;
case 0:
case 255:
return 0x00A0;
default:
return charCode;
}
}
function unicodeToArray(unicode) {
if (unicode < 0x80) {
return [unicode];
} else if (unicode < 0x800) {
return [(unicode >> 6) | 192, (unicode & 63) | 128];
}
return [(unicode >> 12) | 224, ((unicode >> 6) & 63) | 128, (unicode & 63) | 128];
}
function getUTF8(charCode) {
return unicodeToArray(getUnicode(charCode));
}
function encodeANSi(useUTF8) {
function ansiColor(binColor) {
switch (binColor) {
case 1:
return 4;
case 3:
return 6;
case 4:
return 1;
case 6:
return 3;
default:
return binColor;
}
}
var imageData = textArtCanvas.getImageData();
var columns = textArtCanvas.getColumns();
var rows = textArtCanvas.getRows();
var output = [27, 91, 48, 109];
var bold = false;
var blink = false;
var currentForeground = 7;
var currentBackground = 0;
var currentBold = false;
var currentBlink = false;
for (var inputIndex = 0; inputIndex < rows * columns; inputIndex++) {
var attribs = [];
var charCode = imageData[inputIndex] >> 8;
var foreground = imageData[inputIndex] & 15;
var background = imageData[inputIndex] >> 4 & 15;
switch (charCode) {
case 10:
charCode = 9;
break;
case 13:
charCode = 14;
break;
case 26:
charCode = 16;
break;
case 27:
charCode = 17;
break;
default:
break;
}
if (foreground > 7) {
bold = true;
foreground = foreground - 8;
} else {
bold = false;
}
if (background > 7) {
blink = true;
background = background - 8;
} else {
blink = false;
}
if ((currentBold && !bold) || (currentBlink && !blink)) {
attribs.push([48]);
currentForeground = 7;
currentBackground = 0;
currentBold = false;
currentBlink = false;
}
if (bold && !currentBold) {
attribs.push([49]);
currentBold = true;
}
if (blink && !currentBlink) {
attribs.push([53]);
currentBlink = true;
}
if (foreground !== currentForeground) {
attribs.push([51, 48 + ansiColor(foreground)]);
currentForeground = foreground;
}
if (background !== currentBackground) {
attribs.push([52, 48 + ansiColor(background)]);
currentBackground = background;
}
if (attribs.length) {
output.push(27, 91);
for (var attribIndex = 0; attribIndex < attribs.length; attribIndex += 1) {
output = output.concat(attribs[attribIndex]);
if (attribIndex !== attribs.length - 1) {
output.push(59);
} else {
output.push(109);
}
}
}
if (useUTF8 === true) {
getUTF8(charCode).forEach((utf8Code) => {
output.push(utf8Code);
});
if ((inputIndex + 1) % columns === 0) {
output.push(10);
}
} else {
output.push(charCode);
}
}
var sauce = createSauce(1, 1, output.length, true);
saveFile(new Uint8Array(output), sauce, (useUTF8 === true) ? title.getName() + ".utf8.ans" : title.getName() + ".ans");
}
function ans() {
encodeANSi(false);
}
function utf8() {
encodeANSi(true);
}
function convert16BitArrayTo8BitArray(Uint16s) {
var Uint8s = new Uint8Array(Uint16s.length * 2);
for (var i = 0, j = 0; i < Uint16s.length; i++, j += 2) {
Uint8s[j] = Uint16s[i] >> 8;
Uint8s[j + 1] = Uint16s[i] & 255;
}
return Uint8s;
}
function bin() {
var columns = textArtCanvas.getColumns();
if (columns % 2 === 0) {
var imageData = convert16BitArrayTo8BitArray(textArtCanvas.getImageData());
var sauce = createSauce(5, columns / 2, imageData.length, true);
saveFile(imageData, sauce, title.getName() + ".bin");
}
}
function xb() {
var imageData = convert16BitArrayTo8BitArray(textArtCanvas.getImageData());
var columns = textArtCanvas.getColumns();
var rows = textArtCanvas.getRows();
var iceColours = textArtCanvas.getIceColours();
var flags = 0;
if (iceColours === true) {
flags += 1 << 3;
}
var output = new Uint8Array(11 + imageData.length);
output.set(new Uint8Array([
88, 66, 73, 78, 26,
columns & 255,
columns >> 8,
rows & 255,
rows >> 8,
font.getHeight(),
flags
]), 0);
output.set(imageData, 11);
var sauce = createSauce(6, 0, imageData.length, false);
saveFile(output, sauce, title.getName() + ".xb");
}
function dataUrlToBytes(dataURL) {
var base64Index = dataURL.indexOf(";base64,") + 8;
var byteChars = atob(dataURL.substr(base64Index, dataURL.length - base64Index));
var bytes = new Uint8Array(byteChars.length);
for (var i = 0; i < bytes.length; i++) {
bytes[i] = byteChars.charCodeAt(i);
}
return bytes;
}
function png() {
saveFile(dataUrlToBytes(textArtCanvas.getImage().toDataURL()), undefined, title.getName() + ".png");
}
return {
"ans": ans,
"utf8": utf8,
"bin": bin,
"xb": xb,
"png": png
};
}());