commit a15a988a51009ce6ee657bfe373d3c38a3efce1e
parent 66a56a7e0ca1ab07988b12aab58f64ce3a82d616
Author: Andy Herbert <andy.herbert@gmail.com>
Date: Sun, 9 Mar 2014 09:26:33 +0000
Refactor the rendering functions for both 6bit and 24bit methods.
Diffstat:
M | ansilove.js | | | 372 | ++++++++++++++++++++++++++++++++----------------------------------------------- |
1 file changed, 151 insertions(+), 221 deletions(-)
diff --git a/ansilove.js b/ansilove.js
@@ -669,47 +669,39 @@ var AnsiLove = (function () {
};
}
- // Receives a <raw> object returned from the image-parsing functions found in Parser, and outputs a Uint8Array with RGBA data, <rgbaData>, with dimensions <width> and <height>. <start> and <length> point to offsets in <raw.imageData>, so that only part of the image can be rendered. <altFont> is a font object, returned by font() to be used when rendering the image (assuming no font information is held in raw.font), and <options>, which are passed by the user.
+ // Receives a <raw> object returned from the image-parsing functions found in Parser, and outputs a Uint8Array with RGBA data, <rgbaData>, with dimensions <width> and <height>. <start> and <length> point to rows offsets, so that only part of the image can be rendered. <altFont> is a font object, returned by font() to be used when rendering the image (assuming no font information is held in raw.font), and <options>, which are passed by the user.
function display(raw, start, length, options) {
- var canvasWidth, canvasHeight, rgbaData, end, i, k, l, x, fontBitWidth, fontData, rowOffset, screenOffset, fontOffset, chunky;
+ var canvasWidth, canvasHeight, rgbaData, end, i, k, l, x, fontBitWidth, fontData, rowOffset, data, screenOffset, fontOffset, chunky;
// Temporary variable to pre-calculate some data.
fontBitWidth = raw.font.width * 4;
+ data = raw.getData();
+
// Define where to stop reading data.
- end = Math.min(start + length, raw.imageData.length);
+ start = start * raw.columns * 10;
+ end = Math.min(start + length * raw.columns * 10, data.length);
// Calculate the dimensions of the output image.
- canvasWidth = raw.width * raw.font.width;
- canvasHeight = (end - start) / raw.rowLength * raw.font.height;
+ canvasWidth = raw.columns * raw.font.width;
+ canvasHeight = (end - start) / (raw.columns * 10) * raw.font.height;
// Initialize the RGBA image data and calculate how many bytes are in each text-row.
rgbaData = new Uint8Array(canvasWidth * canvasHeight * 4);
rowOffset = canvasWidth * 4;
- // If the image has palette data...
- if (raw.palette) {
- for (i = start, screenOffset = 0, x = 0; i < end; i += 2, screenOffset += fontBitWidth) {
- // ... retrieve the font image data by calling getData() in Font, and inserting the Uint8Array data at the required position in the RGBA data.
- fontData = raw.font.getData(raw.imageData[i], raw.palette, raw.imageData[i + 1] & 15, raw.imageData[i + 1] >> 4);
- for (fontOffset = screenOffset, k = l = 0; k < raw.font.height; ++k, fontOffset += rowOffset, l += fontBitWidth) {
- rgbaData.set(fontData.subarray(l, l + fontBitWidth), fontOffset);
- }
- if (++x % raw.width === 0) {
- screenOffset += (raw.font.height - 1) * rowOffset;
- }
+ for (i = start, screenOffset = 0, x = 0; i < end; i += 10, screenOffset += fontBitWidth) {
+ // If we have 24 bit data
+ if (data[i + 1]) {
+ fontData = raw.font.get24BitData(data[i], data.subarray(i + 2, i + 6), data.subarray(i + 6, i + 10));
+ } else {
+ fontData = raw.font.getData(data[i], raw.palette, data[i + 2], data[i + 3]);
}
- } else {
- // If the image stores 24-bit data...
- for (i = start, screenOffset = 0, x = 0; i < end; i += 9, screenOffset += fontBitWidth) {
- // ... retrieve the font image data by calling get24BitData() in Font, and inserting the Uint8Array data at the required position in the RGBA data.
- fontData = raw.font.get24BitData(raw.imageData[i], raw.imageData.subarray(i + 1, i + 5), raw.imageData.subarray(i + 5, i + 9));
- for (fontOffset = screenOffset, k = l = 0; k < raw.font.height; ++k, fontOffset += rowOffset, l += fontBitWidth) {
- rgbaData.set(fontData.subarray(l, l + fontBitWidth), fontOffset);
- }
- if (++x % raw.width === 0) {
- screenOffset += (raw.font.height - 1) * rowOffset;
- }
+ for (fontOffset = screenOffset, k = l = 0; k < raw.font.height; ++k, fontOffset += rowOffset, l += fontBitWidth) {
+ rgbaData.set(fontData.subarray(l, l + fontBitWidth), fontOffset);
+ }
+ if (++x % raw.columns === 0) {
+ screenOffset += (raw.font.height - 1) * rowOffset;
}
}
@@ -795,15 +787,18 @@ var AnsiLove = (function () {
// Collects all the functions which parse the supported image formats, with a single entrypoint, readBytes.
Parser = (function () {
// ScreenData() returns a representation of the screen with <width> columns. This is used for images with a predefined palette. i.e. all formats except Tundra.
- function ScreenData(width) {
- // <imageData> represents a Uint8Array of the screen, two pairs of bytes represent the character code and colour attributes in the second, as also used in the .bin file format. <maxY> stores the highest row number written to, and <pos> is the current cursor position represented in the <imageData> array.
- var imageData, maxY, pos;
+ function ScreenData(columns) {
+ // <imageData> represents a Uint8Array of the screen, two pairs of bytes represent the character code and colour attributes in the second, as also used in the .bin file format. <rows> stores the highest row number written to, and <pos> is the current cursor position represented in the <imageData> array.
+ var that, imageData, pos;
+
+ that = this;
// Returns the ScreenData object to its initial start, used upon initialization or when a screen-clear code is issued.
this.reset = function () {
- imageData = new Uint8Array(width * 1000 * 2);
- maxY = 0;
+ imageData = new Uint8Array(columns * 1000 * 10);
pos = 0;
+ that.columns = columns;
+ that.rows = 0;
};
this.reset();
@@ -811,116 +806,81 @@ var AnsiLove = (function () {
// Extend the <imageData> array if necessary, by creating a new array with an additional 1000 rows after from the <y> position currently attempting to be written to, and copy the existing data to the start.
function extendImageData(y) {
var newImageData;
- newImageData = new Uint8Array(width * (y + 1000) * 2 + imageData.length);
+ newImageData = new Uint8Array(that.columns * (y + 1000) * 10 + imageData.length);
newImageData.set(imageData, 0);
imageData = newImageData;
}
// Set the character code, <charCode>, and foreground & background attribute, <attrib>, and the <x> and <y> position of the <imageData> array.
- this.set = function (x, y, charCode, attrib) {
- pos = (y * width + x) * 2;
+ this.set = function (x, y, charCode, trueColor, fg, bg) {
+ pos = (y * that.columns + x) * 10;
// If we see that we will be writing past the end of the array, extend the array by calling extendImageData() with the current <y> position we want to write to.
if (pos >= imageData.length) {
extendImageData(y);
}
// Store the data...
imageData[pos] = charCode;
- imageData[pos + 1] = attrib;
- // ... and update <maxY> if it's the largest <y> value used so far.
- if (y > maxY) {
- maxY = y;
- }
- };
-
- // Set the character code, <charCode>, and foreground & background atrtribute, <attrib>, after the last position which was written to.
- this.push = function (charCode, attrib) {
- var y;
- // Calculate the current <y> position where the character will be inserted.
- y = Math.ceil(pos / width / 2);
- // Extend the <imageData> array the limits of the array have been reached.
- if (pos === imageData.length) {
- extendImageData(y);
+ if (trueColor) {
+ // Indicate that we are referring to RGBA values...
+ imageData[pos + 1] = 1;
+ // ... and store the data.
+ imageData.set(fg, pos + 2);
+ imageData.set(bg, pos + 6);
+ } else {
+ // ... and store the palette pointers.
+ imageData[pos + 2] = fg;
+ imageData[pos + 3] = bg;
}
- // Store the data...
- imageData[pos++] = charCode;
- imageData[pos++] = attrib;
- // ... and update <maxY> if it's the largest <y> value used so far.
- if (y > maxY) {
- maxY = y;
+ // ... and update <rows> if it's the largest <y> value used so far.
+ if (y + 1 > that.rows) {
+ that.rows = y + 1;
}
};
- // Return the <imageData> array, but only up to the <maxY> row.
- this.getData = function () {
- return imageData.subarray(0, width * (maxY + 1) * 2);
- };
-
- // Return the amount of rows written to the <imageData> array.
- this.getHeight = function () {
- return maxY + 1;
+ this.raw = function (bytes) {
+ var i, j;
+ that.rows = Math.ceil(bytes.length / 2 / that.columns);
+ imageData = new Uint8Array(that.columns * that.rows * 10);
+ for (i = 0, j = 0; j < bytes.length; i += 10, j += 2) {
+ imageData[i] = bytes[j];
+ imageData[i + 2] = bytes[j + 1] & 15;
+ imageData[i + 3] = bytes[j + 1] >> 4;
+ }
};
- // Return the length of each row in the <imageData> array, in bytes.
- this.rowLength = width * 2;
- }
-
- // A 24-bit version of the ScreenData() object, which represents a character code, a single bytes, then foreground and background data as eight 8-bit bytes (RGBA data), for each glyph on-screen. Used only for the Tundra file format.
- function ScreenData24(width) {
- // <imageData> represents a Uint8Array of the screen, one byte for the character code, then two sets of RGBA data for foreground and background. <maxY> stores the highest row number written to, and <pos> is the current cursor position represented in the <imageData> array.
- var imageData, maxY, pos;
-
- imageData = new Uint8Array(width * 27 * 9);
- maxY = 0;
- pos = 0;
-
- // Extend the <imageData> array if necessary, by creating a new array with an additional 1000 rows after from the <y> position currently attempting to be written to, and copy the existing data to the start.
- function extendImageData(y) {
- var newImageData;
- newImageData = new Uint8Array(width * (y + 27) * 9 + imageData.length);
- newImageData.set(imageData, 0);
- imageData = newImageData;
- }
-
- // Set the character code, <charCode> at the <x> and <y> position of the <imageData> array, with the RGBA data defined in fg and bg.
- this.set = function (x, y, charCode, fg, bg) {
- pos = (y * width + x) * 9;
- // If we see that we will be writing past the end of the array, extend the array by calling extendImageData() with the current <y> position we want to write to.
- if (pos >= imageData.length) {
- extendImageData(y);
+ this.trimColumns = function () {
+ var i, height, j, maxX, newImageData;
+ for (maxX = 0, height = imageData.length / 10 / that.columns, i = 0; i < imageData.length; i += 10) {
+ // If a character code is seen, check to see if it's the highest column value, and record it if necessary.
+ if (imageData[i]) {
+ maxX = Math.max((i / 10) % that.columns, maxX);
+ }
}
- // Store the data...
- imageData[pos] = charCode;
- imageData.set(fg, pos + 1);
- imageData.set(bg, pos + 5);
- // ... and update <maxY> if it's the largest <y> value used so far.
- if (y > maxY) {
- maxY = y;
+ ++maxX;
+ // Create a new imageData object, with a reduced size if necessary.
+ for (newImageData = new Uint8Array((maxX + 1) * height * 10), i = 0, j = 0; i < newImageData.length; i += maxX * 10, j += that.columns * 10) {
+ newImageData.set(imageData.subarray(j, j + that.columns * 10), i);
}
+ imageData = newImageData;
+ // Set the new width.
+ that.columns = maxX;
};
- // Return the <imageData> array, but only up to the <maxY> row.
+ // Return the <imageData> array, but only up to the <rows> row.
this.getData = function () {
var subarray, i;
// Before returning the truncated array, set the Alpha byte for every character position to the maximum value, otherwise the whole image will be transparent when later copying into a RGBA.
- for (subarray = imageData.subarray(0, width * (maxY + 1) * 9), i = 0; i < subarray.length; i += 9) {
- subarray[i + 4] = 255;
- subarray[i + 8] = 255;
+ for (subarray = imageData.subarray(0, that.columns * that.rows * 10), i = 0; i < subarray.length; i += 10) {
+ subarray[i + 5] = 255;
+ subarray[i + 9] = 255;
}
return subarray;
};
-
- // Return the amount of rows written to the <imageData> array.
- this.getHeight = function () {
- return maxY + 1;
- };
-
- // Return the length of each row in the <imageData> array, in bytes.
- this.rowLength = width * 9;
}
// A function to parse a sequence of bytes representing an Artworx file format.
function adf(bytes, options) {
- var file, palette, font, imageData;
+ var file, imageData;
// Turn bytes into a File object.
file = new File(bytes);
@@ -928,28 +888,26 @@ var AnsiLove = (function () {
// Read version number.
file.getC();
+ imageData = new ScreenData(80);
+
// Read Palette. See Palette.adf().
- palette = Palette.adf(file);
+ imageData.palette = Palette.adf(file);
// Read Font. See Font.font8x16x256().
- font = Font.font8x16x256(file, options);
+ imageData.font = Font.font8x16x256(file, options);
+
// Raw Imagedata.
- imageData = file.read();
+ imageData.raw(file.read());
// Return an object readable by display() for constructing an RGBA image.
return {
- "font": font,
- "height": imageData.length / 2 / 80,
"imageData": imageData,
- "palette": palette,
- "width": 80,
- "rowLength": 80 * 2, // Length of each row for the image, in bytes.
"sauce": file.sauce // sauce record.
};
}
// A function to parse a sequence of bytes representing an ANSI file format.
function ans(bytes, options) {
- var file, escaped, escapeCode, j, code, values, columns, imageData, topOfScreen, x, y, savedX, savedY, foreground, background, bold, blink, inverse, palette, icecolors;
+ var file, escaped, escapeCode, j, code, values, columns, imageData, topOfScreen, x, y, savedX, savedY, foreground, background, bold, blink, inverse, icecolors;
// Turn bytes into a File object.
file = new File(bytes);
@@ -1012,6 +970,19 @@ var AnsiLove = (function () {
// Create the ScreenData() object at the required width.
imageData = new ScreenData(columns);
+ imageData.font = Font.preset(options.font, options);
+
+ // Choose the correct Palette constant, depending on whichever mode has been set. See Palette for more information.
+ switch (options.bits) {
+ case "ced":
+ imageData.palette = Palette.CED;
+ break;
+ case "workbench":
+ imageData.palette = Palette.WORKBENCH;
+ break;
+ default:
+ imageData.palette = Palette.ANSI;
+ }
// Returns an array of values found in <escapeCode>, seperated by ";". If there value is not a number, or missing, then the default value of 1 is used.
function getValues() {
@@ -1067,7 +1038,7 @@ var AnsiLove = (function () {
break;
case "K": // Clear until the end of line.
for (j = x - 1; j < columns; ++j) {
- imageData.set(j, y - 1 + topOfScreen, 0, 0);
+ imageData.set(j, y - 1 + topOfScreen, 0, false, 0, 0);
}
break;
case "m": // Attributes, work through each code in turn.
@@ -1139,13 +1110,13 @@ var AnsiLove = (function () {
} else {
// If "ced" mod has been invoked, don't record any additional attribute data.
if (options.mode === "ced") {
- imageData.set(x - 1, y - 1 + topOfScreen, code, 1);
+ imageData.set(x - 1, y - 1 + topOfScreen, code, false, 1, 0);
} else {
// In <inverse> mode, or not, set the character <code> and attribute data to the <imageData> object, according to the current <foreground>, <background>, <icecolors>, <bold>, and <blink> setting.
if (!inverse) {
- imageData.set(x - 1, y - 1 + topOfScreen, code, (bold ? (foreground + 8) : foreground) + (blink && icecolors ? (background + 8 << 4) : (background << 4)));
+ imageData.set(x - 1, y - 1 + topOfScreen, code, false, (bold ? (foreground + 8) : foreground), (blink && icecolors ? background + 8 : background));
} else {
- imageData.set(x - 1, y - 1 + topOfScreen, code, (bold ? (background + 8) : background) + (blink && icecolors ? (foreground + 8 << 4) : (foreground << 4)));
+ imageData.set(x - 1, y - 1 + topOfScreen, code, false, (bold ? (background + 8) : background), (blink && icecolors ? foreground + 8 : foreground));
}
}
// If the end of row has been reached, start a new line.
@@ -1157,26 +1128,9 @@ var AnsiLove = (function () {
}
}
- // Choose the correct Palette constant, depending on whichever mode has been set. See Palette for more information.
- switch (options.bits) {
- case "ced":
- palette = Palette.CED;
- break;
- case "workbench":
- palette = Palette.WORKBENCH;
- break;
- default:
- palette = Palette.ANSI;
- }
-
// Returns an object usable by display() to convert into an RGBA array.
return {
- "font": Font.preset(options.font, options),
- "imageData": imageData.getData(),
- "rowLength": imageData.rowLength, // size of each row in bytes.
- "palette": palette,
- "width": columns,
- "height": imageData.getHeight(),
+ "imageData": imageData,
"sauce": file.sauce // SAUCE record.
};
}
@@ -1188,6 +1142,8 @@ var AnsiLove = (function () {
// Create a new <file> object, based on <bytes>, and create an <imageData> representation of the screen.
file = new File(bytes);
imageData = new ScreenData(80);
+ imageData.font = Font.preset(options.font, options);
+ imageData.palette = Palette.ASC_PC;
// Initialize the cursor position by setting <x> and <y>.
x = 0;
@@ -1206,7 +1162,7 @@ var AnsiLove = (function () {
x = 0;
} else {
// For a literal, record the character code at the <x> and <y>.
- imageData.set(x, y, code, 1);
+ imageData.set(x, y, code, false, 1, 0);
// Start a new line when columns is reached.
if (++x === 80) {
++y;
@@ -1217,12 +1173,7 @@ var AnsiLove = (function () {
// Returns an object usable by display() to convert into an RGBA array.
return {
- "font": Font.preset(options.font, options),
- "imageData": imageData.getData(),
- "palette": Palette.ASC_PC,
- "width": 80,
- "rowLength": imageData.rowLength, // size of each row in bytes.
- "height": imageData.getHeight(),
+ "imageData": imageData,
"sauce": file.sauce // SAUCE record.
};
}
@@ -1233,7 +1184,13 @@ var AnsiLove = (function () {
// Create a new <file> object, based on <bytes>, and create an <imageData> representation of the screen.
file = new File(bytes);
- imageData = file.read();
+
+ imageData = new ScreenData(options.columns);
+ imageData.font = Font.preset(options.font, options);
+ imageData.palette = Palette.BIN;
+
+ // Raw Imagedata.
+ imageData.raw(file.read());
// If there is sauce record, look for an <icecolors> setting in flags, use the user-defined or default setting if not.
if (file.sauce) {
@@ -1251,19 +1208,14 @@ var AnsiLove = (function () {
// Returns an object usable by display() to convert into an RGBA array.
return {
- "font": Font.preset(options.font, options),
- "height": Math.round(imageData.length / 2 / options.columns),
"imageData": imageData,
- "palette": Palette.BIN,
- "width": options.columns,
- "rowLength": options.columns * 2, // Length of each row in bytes.
"sauce": file.sauce // SAUCE record.
};
}
// A function to parse a sequence of bytes representing an iCE Draw file format.
function idf(bytes, options) {
- var file, columns, palette, font, imageData, c, loop, ch, attr;
+ var file, columns, imageData, c, loop, ch, attr, x, y;
// Convert the bytes to a File() object.
file = new File(bytes);
@@ -1277,6 +1229,9 @@ var AnsiLove = (function () {
// Seek to the raw image data, and decode based on a run length encoding method.
file.seek(12);
+
+ x = 0;
+ y = 0;
while (file.getPos() < file.size - 4144) {
c = file.get16();
if (c === 1) {
@@ -1285,24 +1240,27 @@ var AnsiLove = (function () {
ch = file.get();
attr = file.get();
while (loop-- > 0) {
- imageData.push(ch, attr);
+ imageData.set(x++, y, ch, false, attr & 15, attr >> 4);
+ if (x === columns) {
+ x = 0;
+ ++y;
+ }
}
} else {
- imageData.push(c & 255, c >> 8);
+ imageData.set(x++, y, c & 255, false, (c >> 8) & 15, c >> 12);
+ if (x === columns) {
+ x = 0;
+ ++y;
+ }
}
}
// Decode the font and palette data.
- font = Font.font8x16x256(file, options);
- palette = Palette.triplets16(file);
+ imageData.font = Font.font8x16x256(file, options);
+ imageData.palette = Palette.triplets16(file);
return {
- "font": font,
- "height": imageData.getHeight(),
- "imageData": imageData.getData(),
- "palette": palette,
- "width": columns,
- "rowLength": imageData.rowLength, // The length of each row of text in <imageData>, in bytes.
+ "imageData": imageData,
"sauce": file.sauce // The SAUCE record.
};
}
@@ -1314,6 +1272,8 @@ var AnsiLove = (function () {
// Convert bytes into a File() object, only for the convenience of later extracting the sauce record.
file = new File(bytes);
imageData = new ScreenData(80);
+ imageData.font = Font.preset(options.font, options);
+ imageData.palette = Palette.BIN;
// Reset all colour attributes, <bg> and <fg> and cursor positions, <x> and <y>.
bg = 0;
@@ -1330,7 +1290,7 @@ var AnsiLove = (function () {
// Convenient function, to insert the current character code, <charCode>, with foreground and background attributes, <fg> and <bg>, at the current cursor position, <x> and <y>.
function printChar() {
- imageData.set(x, y, charCode, fg + (bg << 4));
+ imageData.set(x, y, charCode, false, fg, bg);
if (++x === 80) {
y++;
x = 0;
@@ -1393,12 +1353,7 @@ var AnsiLove = (function () {
}
return {
- "font": Font.preset(options.font, options),
- "height": imageData.getHeight(),
- "imageData": imageData.getData(),
- "palette": Palette.BIN,
- "width": 80,
- "rowLength": imageData.rowLength, // Length of the <imageData> per row, in bytes.
+ "imageData": imageData,
"sauce": file.sauce // The sauce record.
};
}
@@ -1434,7 +1389,9 @@ var AnsiLove = (function () {
y = 0;
// Create the <imageData> object, as a 24-bit version.
- imageData = new ScreenData24(80);
+ imageData = new ScreenData(80);
+ imageData.font = Font.preset(options.font, options);
+ imageData.palette = Palette.ANSI;
while (!file.eof()) {
// Start a newline if the current <x> position exceeds the column width.
@@ -1471,25 +1428,20 @@ var AnsiLove = (function () {
}
// In case we see a literal, print it (<charCode>), with the current foreground and background attributes, <fg> and <bg>.
if (charCode !== 1 && charCode !== 2 && charCode !== 4 && charCode !== 6) {
- imageData.set(x, y, charCode, fg, bg);
+ imageData.set(x, y, charCode, true, fg, bg);
++x;
}
}
return {
- "font": Font.preset(options.font, options),
- "height": imageData.getHeight(),
- "imageData": imageData.getData(),
- "palette": undefined, // Set to undefined, as the palette information is in the <imageData> object.
- "width": 80,
- "rowLength": imageData.rowLength, // The length of each row in <imageData>, in bytes.
+ "imageData": imageData,
"sauce": file.sauce // The sauce record.
};
}
// A function to parse a sequence of bytes representing an XBiN file format.
function xb(bytes, options) {
- var file, header, palette, font, imageData;
+ var file, header, imageData;
// This function is called to parse the XBin header.
function XBinHeader(file) {
@@ -1575,51 +1527,29 @@ var AnsiLove = (function () {
file = new File(bytes);
header = new XBinHeader(file);
+ // Fetch the image data, and uncompress if necessary.
+ imageData = new ScreenData(header.width);
+
// If palette information is included, read it immediately after the header, if not, use the default palette used for BIN files.
- palette = header.palette ? Palette.triplets16(file) : Palette.BIN;
+ imageData.palette = header.palette ? Palette.triplets16(file) : Palette.BIN;
// If font information is included, read it, if not, use the default 80x25 font.
- font = header.font ? Font.xbin(file, header.fontHeight, options) : Font.preset("80x25", options);
- // Fetch the image data, and uncompress if necessary.
- imageData = header.compressed ? uncompress(file, header.width, header.height) : file.read(header.width * header.height * 2);
+ imageData.font = header.font ? Font.xbin(file, header.fontHeight, options) : Font.preset("80x25", options);
+
+ if (header.compressed) {
+ imageData.raw(uncompress(file, header.width, header.height));
+ } else {
+ imageData.raw(file.read(header.width * header.height * 2));
+ }
return {
- "font": font,
- "height": header.height,
"imageData": imageData,
- "palette": palette,
- "width": header.width,
- "rowLength": header.width * 2, // The length of each row of text in <imageData>, in bytes.
"sauce": file.sauce // The sauce record.
};
}
- // This routine accepts an image <data> object, with character and attribute pairs, and trims the excess columns by finding the longest line and truncating the array, and set a new width. Used for .diz files.
- function trimColumns(data) {
- var i, height, j, maxX, imageData;
- for (maxX = 0, height = data.imageData.length / 2 / data.width, i = 0; i < data.imageData.length; i += 2) {
- // If a character code is seen, check to see if it's the highest column value, and record it if necessary.
- if (data.imageData[i]) {
- maxX = Math.max((i / 2) % data.width, maxX);
- }
- }
- // Create a new imageData object, with a reduced size if necessary.
- for (imageData = new Uint8Array((maxX + 1) * height * 2), i = j = 0; i < data.imageData.length; i += 2) {
- if (i / 2 % data.width <= maxX) {
- imageData[j++] = data.imageData[i];
- imageData[j++] = data.imageData[i + 1];
- }
- }
- data.imageData = imageData;
- // Set the new width.
- data.width = maxX + 1;
- // and row length.
- data.rowLength = data.width * 2;
- return data;
- }
-
// Parses an array of <bytes>, which represent a file, and calls <callback> when the image has been generated successfully, <splitRows> is set to a value greater than 0 if the image is to be split over multiple images, defined by an amount of rows. And <options> is key-pair list of options supplied by the user.
function readBytes(bytes, callback, splitRows, options) {
- var data, returnArray, start, splitLength, displayData;
+ var data, returnArray, start, displayData;
// Validate the options given by the user.
options = validateOptions(options);
@@ -1635,7 +1565,8 @@ var AnsiLove = (function () {
case "diz":
case "ion":
// For diz files, use the ascii parser, and use the default, or user-defined font. Also, trim the extra columns.
- data = trimColumns(asc(bytes, options));
+ data = asc(bytes, options);
+ data.imageData.trimColumns();
break;
case "adf":
// For Artworx files, use the adf parser. Font is already defined in the file.
@@ -1670,10 +1601,9 @@ var AnsiLove = (function () {
if (splitRows > 0) {
// .. intialize an array used to store the multiple images, and calculate the byte-length of each image.
returnArray = [];
- splitLength = data.rowLength * splitRows;
- for (start = 0; start < data.imageData.length; start += splitLength) {
+ for (start = 0; start < data.imageData.rows; start += splitRows) {
// Call display with each "chunk" of data.
- displayData = display(data, start, splitLength, options);
+ displayData = display(data.imageData, start, splitRows, options);
// Push the either raw image data or a canvas of each image into the array, according to the <options.imagedata> setting...
returnArray.push(options.imagedata ? displayData : displayDataToCanvas(displayData));
}
@@ -1681,7 +1611,7 @@ var AnsiLove = (function () {
callback(returnArray, data.sauce);
} else {
// For a single image, send the data to display()...
- displayData = display(data, 0, data.imageData.length, options);
+ displayData = display(data.imageData, 0, data.imageData.rows, options);
// ... and call callback() with either the raw data, or a canvas element, depending on the <options.imagedata> setting.
callback(options.imagedata ? displayData : displayDataToCanvas(displayData), data.sauce);
}