mirror of
https://github.com/JannisX11/blockbench.git
synced 2025-02-17 16:20:13 +08:00
Change indentation to tabs
This commit is contained in:
parent
2b0505d890
commit
e354ffa310
@ -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() {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
// ===============================================================================
|
||||
|
3106
lib/lzutf8.js
3106
lib/lzutf8.js
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user