Change indentation to tabs

This commit is contained in:
JannisX11 2023-02-04 21:15:01 +01:00
parent 2b0505d890
commit e354ffa310
6 changed files with 2034 additions and 2034 deletions

View File

@ -246,8 +246,8 @@ const Blockbench = {
//CSS
addCSS(css) {
let style_node = document.createElement('style');
style_node.type ='text/css';
style_node.appendChild(document.createTextNode(css));
style_node.type ='text/css';
style_node.appendChild(document.createTextNode(css));
document.getElementsByTagName('head')[0].appendChild(style_node);
function deletableStyle(node) {
this.delete = function() {

View File

@ -57,8 +57,8 @@ class Property {
if (options.options) this.options = options.options;
}
delete() {
delete this.class.properties[this.name];
}
delete this.class.properties[this.name];
}
getDefault(instance) {
if (typeof this.default == 'function') {
return this.default(instance);

View File

@ -1,110 +1,110 @@
/*
Utility to modify images with a canvas
Utility to modify images with a canvas
*/
class CanvasFrame {
constructor(a, b) {
if (a && a.nodeName == 'CANVAS') {
if (a.getContext('2d')) {
this.canvas = a;
} else {
this.createCanvas(a.width, a.height)
this.loadFromImage(a)
}
constructor(a, b) {
if (a && a.nodeName == 'CANVAS') {
if (a.getContext('2d')) {
this.canvas = a;
} else {
this.createCanvas(a.width, a.height)
this.loadFromImage(a)
}
} else if (a && a.nodeName == 'IMG') {
this.createCanvas(a.naturalWidth, a.naturalHeight)
this.loadFromImage(a)
} else if (a && a.nodeName == 'IMG') {
this.createCanvas(a.naturalWidth, a.naturalHeight)
this.loadFromImage(a)
} else if (a && b) {
this.createCanvas(a, b)
}
this.ctx = this.canvas.getContext('2d')
}
get width() {return this.canvas.width;}
get height() {return this.canvas.height;}
createCanvas(w, h) {
this.canvas = document.createElement('canvas');
this.canvas.width = w;
this.canvas.height = h;
this.ctx = this.canvas.getContext('2d')
}
async loadFromURL(url) {
let img = new Image()
img.src = url.replace(/#/g, '%23');
await new Promise((resolve, reject) => {
img.onload = () => {
this.loadFromImage(img);
resolve();
}
img.onerror = reject;
})
}
loadFromImage(img) {
if (img.naturalWidth) {
this.canvas.width = img.naturalWidth;
this.canvas.height = img.naturalHeight;
}
this.ctx.drawImage(img, 0, 0)
}
loadFromCanvas(img) {
this.canvas.width = image.naturalWidth;
this.canvas.height = image.naturalHeight;
this.ctx.drawImage(img, 0, 0)
}
autoCrop() {
// Based on code by remy, licensed under MIT
// https://gist.github.com/remy/784508
} else if (a && b) {
this.createCanvas(a, b)
}
this.ctx = this.canvas.getContext('2d')
}
get width() {return this.canvas.width;}
get height() {return this.canvas.height;}
createCanvas(w, h) {
this.canvas = document.createElement('canvas');
this.canvas.width = w;
this.canvas.height = h;
this.ctx = this.canvas.getContext('2d')
}
async loadFromURL(url) {
let img = new Image()
img.src = url.replace(/#/g, '%23');
await new Promise((resolve, reject) => {
img.onload = () => {
this.loadFromImage(img);
resolve();
}
img.onerror = reject;
})
}
loadFromImage(img) {
if (img.naturalWidth) {
this.canvas.width = img.naturalWidth;
this.canvas.height = img.naturalHeight;
}
this.ctx.drawImage(img, 0, 0)
}
loadFromCanvas(img) {
this.canvas.width = image.naturalWidth;
this.canvas.height = image.naturalHeight;
this.ctx.drawImage(img, 0, 0)
}
autoCrop() {
// Based on code by remy, licensed under MIT
// https://gist.github.com/remy/784508
let copy = document.createElement('canvas').getContext('2d');
let pixels = this.ctx.getImageData(0, 0, this.width, this.height);
let i;
let bound = {
top: null,
left: null,
right: null,
bottom: null
};
let x, y;
for (i = 0; i < pixels.data.length; i += 4) {
if (pixels.data[i+3] !== 0) {
x = (i / 4) % this.width;
y = ~~((i / 4) / this.width);
if (bound.top === null) {
bound.top = y;
}
if (bound.left === null) {
bound.left = x;
} else if (x < bound.left) {
bound.left = x;
}
if (bound.right === null) {
bound.right = x;
} else if (bound.right < x) {
bound.right = x;
}
if (bound.bottom === null) {
bound.bottom = y;
} else if (bound.bottom < y) {
bound.bottom = y;
}
}
}
var trimHeight = bound.bottom - bound.top,
trimWidth = bound.right - bound.left,
trimmed = this.ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
copy.canvas.width = trimWidth;
copy.canvas.height = trimHeight;
copy.putImageData(trimmed, 0, 0);
this.canvas = copy.canvas;
this.ctx = copy;
}
let copy = document.createElement('canvas').getContext('2d');
let pixels = this.ctx.getImageData(0, 0, this.width, this.height);
let i;
let bound = {
top: null,
left: null,
right: null,
bottom: null
};
let x, y;
for (i = 0; i < pixels.data.length; i += 4) {
if (pixels.data[i+3] !== 0) {
x = (i / 4) % this.width;
y = ~~((i / 4) / this.width);
if (bound.top === null) {
bound.top = y;
}
if (bound.left === null) {
bound.left = x;
} else if (x < bound.left) {
bound.left = x;
}
if (bound.right === null) {
bound.right = x;
} else if (bound.right < x) {
bound.right = x;
}
if (bound.bottom === null) {
bound.bottom = y;
} else if (bound.bottom < y) {
bound.bottom = y;
}
}
}
var trimHeight = bound.bottom - bound.top,
trimWidth = bound.right - bound.left,
trimmed = this.ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
copy.canvas.width = trimWidth;
copy.canvas.height = trimHeight;
copy.putImageData(trimmed, 0, 0);
this.canvas = copy.canvas;
this.ctx = copy;
}
}

View File

@ -25,228 +25,228 @@ SOFTWARE.
======================================================================== */
function APNGencoder(iCanvas) {
// Generate APNG byte array from a series of canvas images.
// See: https://en.wikipedia.org/wiki/APNG
// Generate APNG byte array from a series of canvas images.
// See: https://en.wikipedia.org/wiki/APNG
// To hide this-variables, put them in an object (e.g. variable state)
// and replace this and self by state.
var self = this; // !!! copy this to context of object
this.whoami = "apng png animation encoder canvas"; // keywords to identify
this.canvas = iCanvas; // Canvas element
this.repeat = 0; // number of repeats; 0 indefinitely
this.frame = -1; // frame number (0 is first frame)
this.seqNumber = -1; // Sequence number for fcTL and fdAT chunks
this.delay_num = 1; // Frame delay fraction numerator (int16, 2 bytes)
this.delay_den = 1; // Frame delay fraction denominator (int16, 2 bytes) 0 == 1/100 sec
this.dispose = 0; // Type of frame area disposal; values 0, 1, 2
this.blend = 1; // Type of frame area rendering: values 0, 1
// To hide this-variables, put them in an object (e.g. variable state)
// and replace this and self by state.
var self = this; // !!! copy this to context of object
this.whoami = "apng png animation encoder canvas"; // keywords to identify
this.canvas = iCanvas; // Canvas element
this.repeat = 0; // number of repeats; 0 indefinitely
this.frame = -1; // frame number (0 is first frame)
this.seqNumber = -1; // Sequence number for fcTL and fdAT chunks
this.delay_num = 1; // Frame delay fraction numerator (int16, 2 bytes)
this.delay_den = 1; // Frame delay fraction denominator (int16, 2 bytes) 0 == 1/100 sec
this.dispose = 0; // Type of frame area disposal; values 0, 1, 2
this.blend = 1; // Type of frame area rendering: values 0, 1
this.apngBytes; // APNG output stream (ByteArray)
this.frameBytes; // Byte stream of current frame image (ByteArray)
this.apngBytes; // APNG output stream (ByteArray)
this.frameBytes; // Byte stream of current frame image (ByteArray)
// Flags
// Flags
this.started = false; // ready to output frames
this.closeStream = false; // close stream when finished
this.start = function() {
// Creates APNG output stream on which images are written.
this.started = true;
this.closeStream = false;
this.apngBytes = new ByteArray(0);
this.frameBytes = new ByteArray(0);
this.frame = -1;
this.seqNumber = -1;
return 0;
} // start
// Creates APNG output stream on which images are written.
this.started = true;
this.closeStream = false;
this.apngBytes = new ByteArray(0);
this.frameBytes = new ByteArray(0);
this.frame = -1;
this.seqNumber = -1;
return 0;
} // start
this.setDelay = function(d100) {
// Sets the delay time between each frame.
// Applies to the last frame added and for subsequent frames.
// Parameter: d100 int delay time in 1/100 sec.
this.delay_num = parseInt(d100);
this.delay_den = 100;
return 0;
} // setDelay
// Sets the delay time between each frame.
// Applies to the last frame added and for subsequent frames.
// Parameter: d100 int delay time in 1/100 sec.
this.delay_num = parseInt(d100);
this.delay_den = 100;
return 0;
} // setDelay
this.setRepeat = function(iter) {
// Sets the number of times the set of APNG frames should be played.
// Default is 1; 0 means play indefinitely.
// Must be invoked before the first image is added.
// Parameter: int number of iterations.
// Sets the number of times the set of APNG frames should be played.
// Default is 1; 0 means play indefinitely.
// Must be invoked before the first image is added.
// Parameter: int number of iterations.
if (iter >= 0) this.repeat = parseInt(iter);
return 0;
} // setRepeat
return 0;
} // setRepeat
this.setDispose = function(d) {
// 0: APNG_DISPOSE_OP_NONE: no disposal is done on this frame before rendering the next;
// the contents of the output buffer are left as is.
// 1: APNG_DISPOSE_OP_BACKGROUND: the frame's region of the output buffer is to be cleared
// to fully transparent black before rendering the next frame.
// 2: APNG_DISPOSE_OP_PREVIOUS: the frame's region of the output buffer is to be reverted
// to the previous contents before rendering the next frame.
if (d < 0 || d > 2) return 0; // not valid
this.dispose = parseInt(d);
return 0;
} // setDispose
// 0: APNG_DISPOSE_OP_NONE: no disposal is done on this frame before rendering the next;
// the contents of the output buffer are left as is.
// 1: APNG_DISPOSE_OP_BACKGROUND: the frame's region of the output buffer is to be cleared
// to fully transparent black before rendering the next frame.
// 2: APNG_DISPOSE_OP_PREVIOUS: the frame's region of the output buffer is to be reverted
// to the previous contents before rendering the next frame.
if (d < 0 || d > 2) return 0; // not valid
this.dispose = parseInt(d);
return 0;
} // setDispose
this.setBlend = function(b) {
// 0: APNG_BLEND_OP_SOURCE all color components of the frame, including alpha, overwrite
// the current contents of the frame's output buffer region.
// 1: APNG_BLEND_OP_OVER the frame should be composited onto the output buffer based
// on its alpha, using a simple OVER operation.
if (b < 0 || b > 1) return 0; // not valid
this.blend = parseInt(b);
return 0;
} // setBlend
// 0: APNG_BLEND_OP_SOURCE all color components of the frame, including alpha, overwrite
// the current contents of the frame's output buffer region.
// 1: APNG_BLEND_OP_OVER the frame should be composited onto the output buffer based
// on its alpha, using a simple OVER operation.
if (b < 0 || b > 1) return 0; // not valid
this.blend = parseInt(b);
return 0;
} // setBlend
this.addFrame = function(canvas) {
// The addFrame method takes a canvas element to create each frame.
// The addFrame method takes a canvas element to create each frame.
if ((this.canvas === null) || !this.started || this.apngBytes === null) {
throw new Error("Please call start method before calling addFrame");
}
if (canvas instanceof HTMLCanvasElement) this.canvas = canvas;
if (canvas instanceof HTMLCanvasElement) this.canvas = canvas;
this.frame += 1; // frame number: used to derive seq number fcTL/fdAT chunks
this.frame += 1; // frame number: used to derive seq number fcTL/fdAT chunks
var dataURL = this.canvas.toDataURL('image/png');
var base64_png = dataURL.replace(/^data:image\/png;base64,/, "");
var dataURL = this.canvas.toDataURL('image/png');
var base64_png = dataURL.replace(/^data:image\/png;base64,/, "");
this.frameBytes.bin = base64ToBytes(base64_png); // current byteArray of canvas
this.frameBytes.bin = base64ToBytes(base64_png); // current byteArray of canvas
if (this.frame == 0) {
// Add signature (first eight bytes of a PNG datastream)
var signature = [0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A];
this.apngBytes.bin = this.apngBytes.bin.concat(signature);
if (this.frame == 0) {
// Add signature (first eight bytes of a PNG datastream)
var signature = [0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A];
this.apngBytes.bin = this.apngBytes.bin.concat(signature);
// Copy Image Header Chunk (IHDR)
var chunk = this.frameBytes.findChunk("IHDR");
var chunkSlice = this.frameBytes.bin.slice(chunk.idx, chunk.idx + 12 + chunk.len);
this.apngBytes.bin = this.apngBytes.bin.concat(chunkSlice);
// Copy Image Header Chunk (IHDR)
var chunk = this.frameBytes.findChunk("IHDR");
var chunkSlice = this.frameBytes.bin.slice(chunk.idx, chunk.idx + 12 + chunk.len);
this.apngBytes.bin = this.apngBytes.bin.concat(chunkSlice);
// acTL chunk (animation control)
var acTL = new Array(0);
acTL = acTL.concat([0,0,0,8]); // fixed length (8 data bytes)
acTL = acTL.concat( str4ToBytes4("acTL") ); // chunk type;
acTL = acTL.concat([0,0,0,1]); // number of frames: must be updated at end
acTL = acTL.concat( int32ToBytes4(this.repeat) ); // push nr of times to loop
var crcVal = crc32b(acTL.slice(4, 4+4+8));
acTL = acTL.concat( int32ToBytes4(crcVal) ); // push CRC 4 bytes
this.apngBytes.bin = this.apngBytes.bin.concat(acTL); // push to main stream
// acTL chunk (animation control)
var acTL = new Array(0);
acTL = acTL.concat([0,0,0,8]); // fixed length (8 data bytes)
acTL = acTL.concat( str4ToBytes4("acTL") ); // chunk type;
acTL = acTL.concat([0,0,0,1]); // number of frames: must be updated at end
acTL = acTL.concat( int32ToBytes4(this.repeat) ); // push nr of times to loop
var crcVal = crc32b(acTL.slice(4, 4+4+8));
acTL = acTL.concat( int32ToBytes4(crcVal) ); // push CRC 4 bytes
this.apngBytes.bin = this.apngBytes.bin.concat(acTL); // push to main stream
// Add (copy) Data Chunks (fcTL and IDAT) (first frame)
var chunkArray = this.frameBytes.findChunkAll("IDAT");
for (var i = 0; i < chunkArray.length; i++) {
if (i == 0) {
// fcTL chunk (frame control)
this.seqNumber +=1; // Sequence number for fcTL and fdAT chunks
var fcTL = new Array(0);
fcTL = fcTL.concat( int32ToBytes4(26) ); // fixed length data 8 bytes
fcTL = fcTL.concat( str4ToBytes4("fcTL") ); // chunk type;
fcTL = fcTL.concat( int32ToBytes4(this.seqNumber) ); // sequence number 0
fcTL = fcTL.concat( int32ToBytes4(this.canvas.width) ); // width
fcTL = fcTL.concat( int32ToBytes4(this.canvas.height) ); // height
fcTL = fcTL.concat( int32ToBytes4(0) ); // x-offset
fcTL = fcTL.concat( int32ToBytes4(0) ); // y-offset
fcTL = fcTL.concat( int16ToBytes2(this.delay_num) ); // Delay num
fcTL = fcTL.concat( int16ToBytes2(this.delay_den) ); // Delay den
fcTL = fcTL.concat( [this.dispose] ); // dispose mode; values [0,1,2] (1 byte)
fcTL = fcTL.concat( [this.blend] ); // blend mode values [0,1] (1 byte)
// Add (copy) Data Chunks (fcTL and IDAT) (first frame)
var chunkArray = this.frameBytes.findChunkAll("IDAT");
for (var i = 0; i < chunkArray.length; i++) {
if (i == 0) {
// fcTL chunk (frame control)
this.seqNumber +=1; // Sequence number for fcTL and fdAT chunks
var fcTL = new Array(0);
fcTL = fcTL.concat( int32ToBytes4(26) ); // fixed length data 8 bytes
fcTL = fcTL.concat( str4ToBytes4("fcTL") ); // chunk type;
fcTL = fcTL.concat( int32ToBytes4(this.seqNumber) ); // sequence number 0
fcTL = fcTL.concat( int32ToBytes4(this.canvas.width) ); // width
fcTL = fcTL.concat( int32ToBytes4(this.canvas.height) ); // height
fcTL = fcTL.concat( int32ToBytes4(0) ); // x-offset
fcTL = fcTL.concat( int32ToBytes4(0) ); // y-offset
fcTL = fcTL.concat( int16ToBytes2(this.delay_num) ); // Delay num
fcTL = fcTL.concat( int16ToBytes2(this.delay_den) ); // Delay den
fcTL = fcTL.concat( [this.dispose] ); // dispose mode; values [0,1,2] (1 byte)
fcTL = fcTL.concat( [this.blend] ); // blend mode values [0,1] (1 byte)
var crcVal = crc32b(fcTL.slice(4, 4+4+26));
fcTL = fcTL.concat( int32ToBytes4(crcVal) ); // push CRC 4 bytes
this.apngBytes.bin = this.apngBytes.bin.concat(fcTL); // push to main stream
}
var crcVal = crc32b(fcTL.slice(4, 4+4+26));
fcTL = fcTL.concat( int32ToBytes4(crcVal) ); // push CRC 4 bytes
this.apngBytes.bin = this.apngBytes.bin.concat(fcTL); // push to main stream
}
chunk = chunkArray[i]; // copy complete IDAT chunk
var chunkSlice = this.frameBytes.bin.slice(chunk.idx, chunk.idx + 12 + chunk.len);
this.apngBytes.bin = this.apngBytes.bin.concat(chunkSlice); // push to main stream
} // for
chunk = chunkArray[i]; // copy complete IDAT chunk
var chunkSlice = this.frameBytes.bin.slice(chunk.idx, chunk.idx + 12 + chunk.len);
this.apngBytes.bin = this.apngBytes.bin.concat(chunkSlice); // push to main stream
} // for
} // first frame
} // first frame
if (this.frame > 0) {
// Not first frame
// Add Data Chunks fcTL/fdAT
var chunkArray = this.frameBytes.findChunkAll("IDAT");
for (var i = 0; i < chunkArray.length; i++) {
if (i == 0) {
// fcTL chunk (frame control)
this.seqNumber +=1; // Sequence number for fcTL and fdAT chunks
var fcTL = new Array(0);
fcTL = fcTL.concat( int32ToBytes4(26) ); // fixed length data 8 bytes
fcTL = fcTL.concat( str4ToBytes4("fcTL") ); // chunk type;
fcTL = fcTL.concat( int32ToBytes4(this.seqNumber) ); // sequence number
fcTL = fcTL.concat( int32ToBytes4(this.canvas.width) ); // width
fcTL = fcTL.concat( int32ToBytes4(this.canvas.height) ); // height
fcTL = fcTL.concat( int32ToBytes4(0) ); // x-offset
fcTL = fcTL.concat( int32ToBytes4(0) ); // y-offset
fcTL = fcTL.concat( int16ToBytes2(this.delay_num) ); // Delay num
fcTL = fcTL.concat( int16ToBytes2(this.delay_den) ); // Delay den
fcTL = fcTL.concat( [this.dispose] ); // dispose mode; values [0,1,2] (1 byte)
fcTL = fcTL.concat( [this.blend] ); // blend mode values [0,1] (1 byte)
if (this.frame > 0) {
// Not first frame
// Add Data Chunks fcTL/fdAT
var chunkArray = this.frameBytes.findChunkAll("IDAT");
for (var i = 0; i < chunkArray.length; i++) {
if (i == 0) {
// fcTL chunk (frame control)
this.seqNumber +=1; // Sequence number for fcTL and fdAT chunks
var fcTL = new Array(0);
fcTL = fcTL.concat( int32ToBytes4(26) ); // fixed length data 8 bytes
fcTL = fcTL.concat( str4ToBytes4("fcTL") ); // chunk type;
fcTL = fcTL.concat( int32ToBytes4(this.seqNumber) ); // sequence number
fcTL = fcTL.concat( int32ToBytes4(this.canvas.width) ); // width
fcTL = fcTL.concat( int32ToBytes4(this.canvas.height) ); // height
fcTL = fcTL.concat( int32ToBytes4(0) ); // x-offset
fcTL = fcTL.concat( int32ToBytes4(0) ); // y-offset
fcTL = fcTL.concat( int16ToBytes2(this.delay_num) ); // Delay num
fcTL = fcTL.concat( int16ToBytes2(this.delay_den) ); // Delay den
fcTL = fcTL.concat( [this.dispose] ); // dispose mode; values [0,1,2] (1 byte)
fcTL = fcTL.concat( [this.blend] ); // blend mode values [0,1] (1 byte)
var crcVal = crc32b(fcTL.slice(4, 4+4+26));
fcTL = fcTL.concat( int32ToBytes4(crcVal) ); // push CRC 4 bytes
this.apngBytes.bin = this.apngBytes.bin.concat(fcTL); // push to main stream
}
var crcVal = crc32b(fcTL.slice(4, 4+4+26));
fcTL = fcTL.concat( int32ToBytes4(crcVal) ); // push CRC 4 bytes
this.apngBytes.bin = this.apngBytes.bin.concat(fcTL); // push to main stream
}
// ============================================================================
// fdAT chunk (frame data)
chunk = chunkArray[i]; // get IDAT chunk object
var chunk_IDAT_data = this.frameBytes.bin.slice(chunk.idx + 8, chunk.idx + 8 + chunk.len);
var len_fdAT = chunk.len + 4; // increase data with seq number
// ============================================================================
// fdAT chunk (frame data)
chunk = chunkArray[i]; // get IDAT chunk object
var chunk_IDAT_data = this.frameBytes.bin.slice(chunk.idx + 8, chunk.idx + 8 + chunk.len);
var len_fdAT = chunk.len + 4; // increase data with seq number
this.seqNumber +=1; // Sequence number for fcTL and fdAT chunks
var fdAT = new Array(0);
fdAT = fdAT.concat( int32ToBytes4(len_fdAT) ); // append length bytes
fdAT = fdAT.concat( str4ToBytes4("fdAT") ); // chunk type bytes
fdAT = fdAT.concat( int32ToBytes4(this.seqNumber) ); // add sequence number bytes
fdAT = fdAT.concat( chunk_IDAT_data ); // append original IDAT data
var crcVal = crc32b(fdAT.slice(4, 4+4+len_fdAT));
fdAT = fdAT.concat( int32ToBytes4(crcVal) ); // push CRC 4 bytes
this.seqNumber +=1; // Sequence number for fcTL and fdAT chunks
var fdAT = new Array(0);
fdAT = fdAT.concat( int32ToBytes4(len_fdAT) ); // append length bytes
fdAT = fdAT.concat( str4ToBytes4("fdAT") ); // chunk type bytes
fdAT = fdAT.concat( int32ToBytes4(this.seqNumber) ); // add sequence number bytes
fdAT = fdAT.concat( chunk_IDAT_data ); // append original IDAT data
var crcVal = crc32b(fdAT.slice(4, 4+4+len_fdAT));
fdAT = fdAT.concat( int32ToBytes4(crcVal) ); // push CRC 4 bytes
this.apngBytes.bin = this.apngBytes.bin.concat(fdAT); // push to main stream
} // for
this.apngBytes.bin = this.apngBytes.bin.concat(fdAT); // push to main stream
} // for
} // not first frame
} // not first frame
return 0;
} // addFrame
} // addFrame
this.finish = function() {
// Adds final chunk to the APNG stream.
// If you don't call the finish method the APNG stream will not be valid.
// Adds final chunk to the APNG stream.
// If you don't call the finish method the APNG stream will not be valid.
if (!this.started) return false;
// Add Image End Chunk (IEND)
var chunkArray = [0x00,0x00,0x00,0x00, 0x49,0x45,0x4E,0x44, 0xAE,0x42,0x60,0x82]; // fixed
this.apngBytes.bin = this.apngBytes.bin.concat(chunkArray);
// Add Image End Chunk (IEND)
var chunkArray = [0x00,0x00,0x00,0x00, 0x49,0x45,0x4E,0x44, 0xAE,0x42,0x60,0x82]; // fixed
this.apngBytes.bin = this.apngBytes.bin.concat(chunkArray);
// Update acTL chunk with number of frames
var chunk = this.apngBytes.findChunk("acTL");
var nFrames = int32ToBytes4(this.frame + 1);
this.apngBytes.bin[chunk.idx+8] = nFrames[0];
this.apngBytes.bin[chunk.idx+8+1] = nFrames[1];
this.apngBytes.bin[chunk.idx+8+2] = nFrames[2];
this.apngBytes.bin[chunk.idx+8+3] = nFrames[3];
// Update acTL chunk with number of frames
var chunk = this.apngBytes.findChunk("acTL");
var nFrames = int32ToBytes4(this.frame + 1);
this.apngBytes.bin[chunk.idx+8] = nFrames[0];
this.apngBytes.bin[chunk.idx+8+1] = nFrames[1];
this.apngBytes.bin[chunk.idx+8+2] = nFrames[2];
this.apngBytes.bin[chunk.idx+8+3] = nFrames[3];
// Update CRC of acTL
var acTLslice = this.apngBytes.bin.slice(chunk.idx+4, chunk.idx+4+4+8);
var crcVal = crc32b( acTLslice );
var crcBytes = int32ToBytes4(crcVal);
this.apngBytes.bin[chunk.idx+4+4+8] = crcBytes[0];
this.apngBytes.bin[chunk.idx+4+4+8+1] = crcBytes[1];
this.apngBytes.bin[chunk.idx+4+4+8+2] = crcBytes[2];
this.apngBytes.bin[chunk.idx+4+4+8+3] = crcBytes[3];
// Update CRC of acTL
var acTLslice = this.apngBytes.bin.slice(chunk.idx+4, chunk.idx+4+4+8);
var crcVal = crc32b( acTLslice );
var crcBytes = int32ToBytes4(crcVal);
this.apngBytes.bin[chunk.idx+4+4+8] = crcBytes[0];
this.apngBytes.bin[chunk.idx+4+4+8+1] = crcBytes[1];
this.apngBytes.bin[chunk.idx+4+4+8+2] = crcBytes[2];
this.apngBytes.bin[chunk.idx+4+4+8+3] = crcBytes[3];
this.started = false;
this.closeStream = true;
this.started = false;
this.closeStream = true;
return true;
} // finish
} // finish
this.stream = function() {
// Retrieves the APNG stream.
// Retrieves the APNG stream.
return self.apngBytes;
};
@ -256,208 +256,208 @@ function APNGencoder(iCanvas) {
// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
function ByteArray(len) {
// Object special designed to store a PNG image.
// Used to generate an animated PNG image and process chunks.
// Object special designed to store a PNG image.
// Used to generate an animated PNG image and process chunks.
this.bin = new Array(len); // To store the byte array
this.bin = new Array(len); // To store the byte array
// A chunk in a PNG file consists of four parts:
// - Length of data (4 bytes)
// - Chunk type (4 bytes)
// - Chunk data (length bytes)
// - CRC (Cyclic Redundancy Code / Checksum, 4 bytes)
// There are about 20 different chunk types, but for a minimal PNG, only 3 are required:
// - the IHDR (image header) chunk
// - one or more IDAT (image data) chunks
// - the IEND (image end) chunk
function Chunk(idx, len, type) {
// Object Chunk
this.idx = idx; // Starting index of chunk in context of byte array
this.len = len; // Length of data: total length of chunk is (4 + 4 + len + 4)
this.type = type; // IHDR, IEND, IDAT, acTL, fcTL, fdAT, etc.
} // Chunk
// A chunk in a PNG file consists of four parts:
// - Length of data (4 bytes)
// - Chunk type (4 bytes)
// - Chunk data (length bytes)
// - CRC (Cyclic Redundancy Code / Checksum, 4 bytes)
// There are about 20 different chunk types, but for a minimal PNG, only 3 are required:
// - the IHDR (image header) chunk
// - one or more IDAT (image data) chunks
// - the IEND (image end) chunk
function Chunk(idx, len, type) {
// Object Chunk
this.idx = idx; // Starting index of chunk in context of byte array
this.len = len; // Length of data: total length of chunk is (4 + 4 + len + 4)
this.type = type; // IHDR, IEND, IDAT, acTL, fcTL, fdAT, etc.
} // Chunk
this.findChunk =
function(iType) {
// Find first chunk matching iType; null if not found
var offset = 8; // start search
var chunk = null; // default output
while (offset < this.bin.length) {
var chunk1 = this.bin.slice(offset, offset + 4); // length chunk data
var chunk2 = this.bin.slice(offset + 4, offset + 8); // type of chunk
this.findChunk =
function(iType) {
// Find first chunk matching iType; null if not found
var offset = 8; // start search
var chunk = null; // default output
while (offset < this.bin.length) {
var chunk1 = this.bin.slice(offset, offset + 4); // length chunk data
var chunk2 = this.bin.slice(offset + 4, offset + 8); // type of chunk
var chunkLength = bytes4ToInt32(chunk1);
var chunkType = bytes4ToStr4(chunk2);
if (chunkType === iType) {
chunk = new Chunk(offset, chunkLength, chunkType);
// chunk_arr = this.bin.slice(offset, offset + 4 + 4 + chunkLength + 4);
return chunk; // STOP
}
var chunkLength = bytes4ToInt32(chunk1);
var chunkType = bytes4ToStr4(chunk2);
if (chunkType === iType) {
chunk = new Chunk(offset, chunkLength, chunkType);
// chunk_arr = this.bin.slice(offset, offset + 4 + 4 + chunkLength + 4);
return chunk; // STOP
}
offset += 4 + 4 + chunkLength + 4;
}
offset += 4 + 4 + chunkLength + 4;
}
return chunk;
} // findChunk
return chunk;
} // findChunk
this.findChunkAll =
function(iType) {
// Find all chunks matching iType. Output array of chunk objects.
var offset = 8; // start search
var chunkArray = []; // default output
while (offset < this.bin.length) {
var chunk1 = this.bin.slice(offset, offset + 4); // length chunk data
var chunk2 = this.bin.slice(offset + 4, offset + 8); // type of chunk
this.findChunkAll =
function(iType) {
// Find all chunks matching iType. Output array of chunk objects.
var offset = 8; // start search
var chunkArray = []; // default output
while (offset < this.bin.length) {
var chunk1 = this.bin.slice(offset, offset + 4); // length chunk data
var chunk2 = this.bin.slice(offset + 4, offset + 8); // type of chunk
var chunkLength = bytes4ToInt32(chunk1);
var chunkType = bytes4ToStr4(chunk2);
if (chunkType === iType) {
chunk = new Chunk(offset, chunkLength, chunkType);
chunkArray.push(chunk); // array of chunk objects
// chunk_arr = this.bin.slice(offset, offset + 4 + 4 + chunkLength + 4);
}
var chunkLength = bytes4ToInt32(chunk1);
var chunkType = bytes4ToStr4(chunk2);
if (chunkType === iType) {
chunk = new Chunk(offset, chunkLength, chunkType);
chunkArray.push(chunk); // array of chunk objects
// chunk_arr = this.bin.slice(offset, offset + 4 + 4 + chunkLength + 4);
}
offset += 4 + 4 + chunkLength + 4;
}
offset += 4 + 4 + chunkLength + 4;
}
return chunkArray;
} // findChunkAll
return chunkArray;
} // findChunkAll
this.toStrHex =
function() {
return bytesToStrHex(this.bin);
} // toStrHex
this.toStrHex =
function() {
return bytesToStrHex(this.bin);
} // toStrHex
this.toStrBase64 =
function() {
return bytesToBase64(this.bin);
} // toStrBase64
this.toStrBase64 =
function() {
return bytesToBase64(this.bin);
} // toStrBase64
this.toStrAscii =
function() {
return bytesToStrAscii(this.bin);
} // toStrAscii
this.toStrAscii =
function() {
return bytesToStrAscii(this.bin);
} // toStrAscii
this.toStrDec =
function() {
return bytesToStrDec(this.bin);
} // toStrDec
this.toStrDec =
function() {
return bytesToStrDec(this.bin);
} // toStrDec
return this;
return this;
} // ByteArray
// ===============================================================================
function bytesToStrHex(bytes) {
// Convert byte array to string of hexa-decimals.
var str = "";
for (var i=0; i < bytes.length; i++) {
str += decimalToHex(bytes[i], 2) + " ";
}
return str;
// Convert byte array to string of hexa-decimals.
var str = "";
for (var i=0; i < bytes.length; i++) {
str += decimalToHex(bytes[i], 2) + " ";
}
return str;
} // bytesToStrHex
function bytesToStrDec(bytes) {
// Convert byte array to string of decimals.
var str = "";
for (var i = 0; i < bytes.length; i++) {
str += ('000' + bytes[i]).slice(-3); // padding 3 char
str += " ";
}
return str;
// Convert byte array to string of decimals.
var str = "";
for (var i = 0; i < bytes.length; i++) {
str += ('000' + bytes[i]).slice(-3); // padding 3 char
str += " ";
}
return str;
} // bytesToStrDec
function bytesToStrAscii(bytes) {
// Conversion byte array of Unicode (UTF-8) values into characters.
var str = "";
for (var i = 0; i < bytes.length; i++) {
if (bytes[i] > 32 && bytes[i] < 127) { // printable
str += String.fromCharCode(bytes[i]);
}
else
str += ".";
}
return str;
// Conversion byte array of Unicode (UTF-8) values into characters.
var str = "";
for (var i = 0; i < bytes.length; i++) {
if (bytes[i] > 32 && bytes[i] < 127) { // printable
str += String.fromCharCode(bytes[i]);
}
else
str += ".";
}
return str;
} // bytesToStrAscii
function multiLine(str, lineWidth) {
// Split long string into lines with fixed width
var patt = new RegExp("(.{" + lineWidth + "})", "g"); // e.g. regex /(.{75})/
return str.split(patt).join("\n").replace(/\n+/g, "\n").trim();
// Split long string into lines with fixed width
var patt = new RegExp("(.{" + lineWidth + "})", "g"); // e.g. regex /(.{75})/
return str.split(patt).join("\n").replace(/\n+/g, "\n").trim();
} // multiLine
// ===============================================================================
function decimalToHex(decimal, chars) {
// This converts a number to a string hex AND pads leading zeros
return (decimal + Math.pow(16, chars)).toString(16).slice(-chars).toUpperCase();
// This converts a number to a string hex AND pads leading zeros
return (decimal + Math.pow(16, chars)).toString(16).slice(-chars).toUpperCase();
} // decimalToHex
function bytesToBase64(bytes) {
// Convert byte array to base64 string.
var str = "";
for (var i = 0; i < bytes.length; i++)
str += String.fromCharCode(bytes[i]);
return btoa(str);
// Convert byte array to base64 string.
var str = "";
for (var i = 0; i < bytes.length; i++)
str += String.fromCharCode(bytes[i]);
return btoa(str);
} // bytesToBase64
function base64ToBytes(str) {
// Convert base64 string to byte array.
var decoded = atob(str);
// Convert base64 string to byte array.
var decoded = atob(str);
var len = decoded.length;
var arr = new Array(len);
var len = decoded.length;
var arr = new Array(len);
for (var i = 0; i < len; ++i) {
arr[i] = decoded.charCodeAt(i);
}
for (var i = 0; i < len; ++i) {
arr[i] = decoded.charCodeAt(i);
}
return arr;
return arr;
} // base64ToBytes
// ===============================================================================
function str4ToBytes4(iString) {
var cc = new Array(4);
cc[0] = iString.charCodeAt(0);
cc[1] = iString.charCodeAt(1);
cc[2] = iString.charCodeAt(2);
cc[3] = iString.charCodeAt(3);
return cc;
var cc = new Array(4);
cc[0] = iString.charCodeAt(0);
cc[1] = iString.charCodeAt(1);
cc[2] = iString.charCodeAt(2);
cc[3] = iString.charCodeAt(3);
return cc;
} // strToBytes4
function bytes4ToStr4(iBytes) {
var cc =
String.fromCharCode(iBytes[0]) +
String.fromCharCode(iBytes[1]) +
String.fromCharCode(iBytes[2]) +
String.fromCharCode(iBytes[3]);
return cc;
var cc =
String.fromCharCode(iBytes[0]) +
String.fromCharCode(iBytes[1]) +
String.fromCharCode(iBytes[2]) +
String.fromCharCode(iBytes[3]);
return cc;
} // bytes4ToStr4
function int32ToBytes4(iNum) {
var int32 = iNum;
var arr = [0, 0, 0, 0];
for ( var idx = 0; idx < arr.length; idx ++ ) {
var byte = int32 & 0xff;
arr[idx] = byte;
int32 = (int32 - byte) / 256 ;
}
return arr.reverse();
var int32 = iNum;
var arr = [0, 0, 0, 0];
for ( var idx = 0; idx < arr.length; idx ++ ) {
var byte = int32 & 0xff;
arr[idx] = byte;
int32 = (int32 - byte) / 256 ;
}
return arr.reverse();
} // int32ToBytes4
function bytes4ToInt32(iBytes) {
var num = (iBytes[0] << 24) + (iBytes[1] << 12) + (iBytes[2] << 8) + iBytes[3];
return num;
var num = (iBytes[0] << 24) + (iBytes[1] << 12) + (iBytes[2] << 8) + iBytes[3];
return num;
} // bytes4ToInt32
function int16ToBytes2(iNum) {
var int16 = iNum;
var arr = [0, 0];
for ( var idx = 0; idx < arr.length; idx ++ ) {
var byte = int16 & 0xff;
arr[idx] = byte;
int16 = (int16 - byte) / 256 ;
}
return arr.reverse();
var int16 = iNum;
var arr = [0, 0];
for ( var idx = 0; idx < arr.length; idx ++ ) {
var byte = int16 & 0xff;
arr[idx] = byte;
int16 = (int16 - byte) / 256 ;
}
return arr.reverse();
} // int16ToBytes2
@ -475,7 +475,7 @@ Format function for output CRC32 calculation: formatCRC32(iVal, iType)
Testcases:
IN: [0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00];
OUT: "907753DE" or [144,119,83,222] (IHDR chunk)
OUT: "907753DE" or [144,119,83,222] (IHDR chunk)
IN: [0x49,0x45,0x4E,0x44] or [73,69,78,68]
OUT: "AE426082" or [174,66,96,130] (IEND chunk)
IN: "SheetJS"
@ -489,58 +489,58 @@ var a_table = "00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E
var b_table = a_table.split(' ').map(function(s){ return parseInt(s,16) });
function crc32b(iVar) {
// Calculate CRC32b value of iVar (string or array of integers (bytes))
if (typeof iVar == "string" || iVar instanceof String) {
// Convert string to integer array
var arr = new Array(iVar.length);
for (var i=0; i < iVar.length; i++) { arr[i] = iVar.charCodeAt(i); }
}
else if (Array.isArray(iVar)) {
var arr = iVar;
}
else {
alert("Bad input for CRC32 calculation: " + iVar);
return 0;
}
// Calculate CRC32b value of iVar (string or array of integers (bytes))
if (typeof iVar == "string" || iVar instanceof String) {
// Convert string to integer array
var arr = new Array(iVar.length);
for (var i=0; i < iVar.length; i++) { arr[i] = iVar.charCodeAt(i); }
}
else if (Array.isArray(iVar)) {
var arr = iVar;
}
else {
alert("Bad input for CRC32 calculation: " + iVar);
return 0;
}
var crc = -1;
for (var i=0, iTop = arr.length; i < iTop; i++) {
crc = ( crc >>> 8 ) ^ b_table[( crc ^ arr[i] ) & 0xFF];
}
return (crc ^ (-1)) >>> 0;
var crc = -1;
for (var i=0, iTop = arr.length; i < iTop; i++) {
crc = ( crc >>> 8 ) ^ b_table[( crc ^ arr[i] ) & 0xFF];
}
return (crc ^ (-1)) >>> 0;
} // crc32b
function formatCRC32(iVal, iType) {
// iVal: result of CRC32.str or CRC32.buf (from crc32.js)
// Format types: uint, hexs, hexb
// iVal: result of CRC32.str or CRC32.buf (from crc32.js)
// Format types: uint, hexs, hexb
function lpad(s, len, chr){
var L = len - s.length, C = chr || " ";
if(L <= 0) return s;
return new Array(L+1).join(C) + s;
} // lpad
function lpad(s, len, chr){
var L = len - s.length, C = chr || " ";
if(L <= 0) return s;
return new Array(L+1).join(C) + s;
} // lpad
var res;
switch(iType) {
case "uint": // unsigned integer
res = iVal;
break;
case "hexs": // hexadec string
res = lpad(iVal.toString(16),8,'0').toUpperCase();
break;
case "hexb": // byte array (first index is high)
res = new Array(4);
var hexs = lpad(iVal.toString(16),8,'0');
res[0] = parseInt(hexs.substring(0, 2),16);
res[1] = parseInt(hexs.substring(2, 4),16);
res[2] = parseInt(hexs.substring(4, 6),16);
res[3] = parseInt(hexs.substring(6, 8),16);
break;
default:
res = iVal;
}
return res;
var res;
switch(iType) {
case "uint": // unsigned integer
res = iVal;
break;
case "hexs": // hexadec string
res = lpad(iVal.toString(16),8,'0').toUpperCase();
break;
case "hexb": // byte array (first index is high)
res = new Array(4);
var hexs = lpad(iVal.toString(16),8,'0');
res[0] = parseInt(hexs.substring(0, 2),16);
res[1] = parseInt(hexs.substring(2, 4),16);
res[2] = parseInt(hexs.substring(4, 6),16);
res[3] = parseInt(hexs.substring(6, 8),16);
break;
default:
res = iVal;
}
return res;
} // formatCRC32
// ===============================================================================

File diff suppressed because it is too large Load Diff

View File

@ -152,23 +152,23 @@ THREE.GridBox = GridBox
THREE.Object3D.prototype.toScreenPosition = function(camera, canvas)
{
var vector = new THREE.Vector3();
var vector = new THREE.Vector3();
var widthHalf = 0.5*canvas.width;
var heightHalf = 0.5*canvas.height;
var widthHalf = 0.5*canvas.width;
var heightHalf = 0.5*canvas.height;
this.updateMatrixWorld();
vector.setFromMatrixPosition(this.matrixWorld);
vector.project(camera);
this.updateMatrixWorld();
vector.setFromMatrixPosition(this.matrixWorld);
vector.project(camera);
vector.x = ( vector.x * widthHalf ) + widthHalf;
vector.y = - ( vector.y * heightHalf ) + heightHalf;
vector.divideScalar(window.devicePixelRatio);
vector.x = ( vector.x * widthHalf ) + widthHalf;
vector.y = - ( vector.y * heightHalf ) + heightHalf;
vector.divideScalar(window.devicePixelRatio);
return {
x: vector.x,
y: vector.y
};
return {
x: vector.x,
y: vector.y
};
};