Cleanup project root

This commit is contained in:
jdescottes
2014-03-16 21:15:34 +01:00
parent 50e7d05764
commit 87574a2b30
204 changed files with 29 additions and 245 deletions

View File

@@ -0,0 +1,49 @@
(function () {
var ns = $.namespace("pskl");
ns.CanvasUtils = {
createCanvas : function (width, height, classList) {
var canvas = document.createElement("canvas");
canvas.setAttribute("width", width);
canvas.setAttribute("height", height);
if (typeof classList == "string") {
classList = [classList];
}
if (Array.isArray(classList)) {
for (var i = 0 ; i < classList.length ; i++) {
canvas.classList.add(classList[i]);
}
}
return canvas;
},
/**
* By default, all scaling operations on a Canvas 2D Context are performed using antialiasing.
* Resizing a 32x32 image to 320x320 will lead to a blurry output.
* On Chrome, FF and IE>=11, this can be disabled by setting a property on the Canvas 2D Context.
* In this case the browser will use a nearest-neighbor scaling.
* @param {Canvas} canvas
*/
disableImageSmoothing : function (canvas) {
var context = canvas.getContext('2d');
context.imageSmoothingEnabled = false;
context.mozImageSmoothingEnabled = false;
context.oImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
},
clear : function (canvas) {
if (canvas) {
canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height);
}
},
getImageDataFromCanvas : function (canvas) {
var sourceContext = canvas.getContext('2d');
return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data;
}
};
})();

29
src/js/utils/Dom.js Normal file
View File

@@ -0,0 +1,29 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.Dom = {
/**
* Check if a given HTML element is nested inside another
* @param {HTMLElement} node Element to test
* @param {HTMLElement} parent Potential Ancestor for node
* @param {Boolean} excludeParent set to true if the parent should be excluded from potential matches
* @return {Boolean} true if parent was found amongst the parentNode chain of node
*/
isParent : function (node, parent, excludeParent) {
if (node && parent) {
if (excludeParent) {
node = node.parentNode;
}
while (node) {
if (node === parent) {
return true;
}
node = node.parentNode;
}
}
return false;
}
};
})();

13
src/js/utils/FileUtils.js Normal file
View File

@@ -0,0 +1,13 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.FileUtils = {
readFile : function (file, callback) {
var reader = new FileReader();
reader.onload = function(event){
callback(event.target.result);
};
reader.readAsDataURL(file);
}
};
})();

156
src/js/utils/FrameUtils.js Normal file
View File

@@ -0,0 +1,156 @@
(function () {
var ns = $.namespace('pskl.utils');
var colorCache = {};
ns.FrameUtils = {
merge : function (frames) {
var merged = null;
if (frames.length) {
merged = frames[0].clone();
var w = merged.getWidth(), h = merged.getHeight();
for (var i = 1 ; i < frames.length ; i++) {
pskl.utils.FrameUtils.mergeFrames_(merged, frames[i]);
}
}
return merged;
},
mergeFrames_ : function (frameA, frameB) {
frameB.forEachPixel(function (p, col, row) {
if (p != Constants.TRANSPARENT_COLOR) {
frameA.setPixel(col, row, p);
}
});
},
/**
* Alpha compositing using porter duff algorithm :
* http://en.wikipedia.org/wiki/Alpha_compositing
* http://keithp.com/~keithp/porterduff/p253-porter.pdf
* @param {String} strColor1 color over
* @param {String} strColor2 color under
* @return {String} the composite color
*/
mergePixels : function (strColor1, strColor2, globalOpacity1) {
var col1 = pskl.utils.FrameUtils.toRgba(strColor1);
var col2 = pskl.utils.FrameUtils.toRgba(strColor2);
if (typeof globalOpacity1 == 'number') {
col1 = JSON.parse(JSON.stringify(col1));
col1.a = globalOpacity1 * col1.a;
}
var a = col1.a + col2.a * (1 - col1.a);
var r = ((col1.r * col1.a + col2.r * col2.a * (1 - col1.a)) / a)|0;
var g = ((col1.g * col1.a + col2.g * col2.a * (1 - col1.a)) / a)|0;
var b = ((col1.b * col1.a + col2.b * col2.a * (1 - col1.a)) / a)|0;
return 'rgba('+r+','+g+','+b+','+a+')';
},
/**
* Convert a color defined as a string (hex, rgba, rgb, 'TRANSPARENT') to an Object with r,g,b,a properties.
* r, g and b are integers between 0 and 255, a is a float between 0 and 1
* @param {String} c color as a string
* @return {Object} {r:Number,g:Number,b:Number,a:Number}
*/
toRgba : function (c) {
if (colorCache[c]) {
return colorCache[c];
}
var color, matches;
if (c === 'TRANSPARENT') {
color = {
r : 0,
g : 0,
b : 0,
a : 0
};
} else if (c.indexOf('rgba(') != -1) {
matches = /rgba\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(1|0\.\d+)\s*\)/.exec(c);
color = {
r : parseInt(matches[1],10),
g : parseInt(matches[2],10),
b : parseInt(matches[3],10),
a : parseFloat(matches[4])
};
} else if (c.indexOf('rgb(') != -1) {
matches = /rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(c);
color = {
r : parseInt(matches[1],10),
g : parseInt(matches[2],10),
b : parseInt(matches[3],10),
a : 1
};
} else {
matches = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(c);
color = {
r : parseInt(matches[1], 16),
g : parseInt(matches[2], 16),
b : parseInt(matches[3], 16),
a : 1
};
}
colorCache[c] = color;
return color;
},
/*
* Create a pskl.model.Frame from an Image object.
* Transparent pixels will either be converted to completely opaque or completely transparent pixels.
* @param {Image} image source image
* @return {pskl.model.Frame} corresponding frame
*/
createFromImage : function (image) {
var w = image.width,
h = image.height;
var canvas = pskl.CanvasUtils.createCanvas(w, h);
var context = canvas.getContext('2d');
context.drawImage(image, 0,0,w,h,0,0,w,h);
var imgData = context.getImageData(0,0,w,h).data;
return pskl.utils.FrameUtils.createFromImageData(imgData, w, h);
},
createFromImageData : function (imageData, width, height) {
// Draw the zoomed-up pixels to a different canvas context
var grid = [];
for (var x = 0 ; x < width ; x++){
grid[x] = [];
for (var y = 0 ; y < height ; y++){
// Find the starting index in the one-dimensional image data
var i = (y * width + x)*4;
var r = imageData[i ];
var g = imageData[i+1];
var b = imageData[i+2];
var a = imageData[i+3];
if (a < 125) {
grid[x][y] = Constants.TRANSPARENT_COLOR;
} else {
grid[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b);
}
}
}
return pskl.model.Frame.fromPixelGrid(grid);
},
/**
* Convert a rgb(Number, Number, Number) color to hexadecimal representation
* @param {Number} r red value, between 0 and 255
* @param {Number} g green value, between 0 and 255
* @param {Number} b blue value, between 0 and 255
* @return {String} hex representation of the color '#ABCDEF'
*/
rgbToHex : function (r, g, b) {
return "#" + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b);
},
/**
* Convert a color component (as a Number between 0 and 255) to its string hexa representation
* @param {Number} c component value, between 0 and 255
* @return {String} eg. '0A'
*/
componentToHex : function (c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
};
})();

View File

@@ -0,0 +1,76 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.ImageResizer = {
resize : function (image, targetWidth, targetHeight, smoothingEnabled) {
var canvas = pskl.CanvasUtils.createCanvas(targetWidth, targetHeight);
var context = canvas.getContext('2d');
context.save();
if (!smoothingEnabled) {
pskl.CanvasUtils.disableImageSmoothing(canvas);
}
context.translate(canvas.width / 2, canvas.height / 2);
context.scale(targetWidth / image.width, targetHeight / image.height);
context.drawImage(image, -image.width / 2, -image.height / 2);
context.restore();
return canvas;
},
/**
* Manual implementation of resize using a nearest neighbour algorithm
* It is slower than relying on the native 'disabledImageSmoothing' available on CanvasRenderingContext2d.
* But it can be useful if :
* - IE < 11 (doesn't support msDisableImageSmoothing)
* - need to display a gap between pixel
*
* @param {Canvas2d} source original image to be resized, as a 2d canvas
* @param {Number} zoom ratio between desired dim / source dim
* @param {Number} margin gap to be displayed between pixels
* @return {Canvas2d} the resized canvas
*/
resizeNearestNeighbour : function (source, zoom, margin) {
margin = margin || 0;
var canvas = pskl.CanvasUtils.createCanvas(zoom*source.width, zoom*source.height);
var context = canvas.getContext('2d');
var imgData = pskl.CanvasUtils.getImageDataFromCanvas(source);
var yRanges = {},
xOffset = 0,
yOffset = 0,
xRange,
yRange;
// Draw the zoomed-up pixels to a different canvas context
for (var x = 0; x < source.width; x++) {
// Calculate X Range
xRange = Math.floor((x + 1) * zoom) - xOffset;
for (var y = 0; y < source.height; y++) {
// Calculate Y Range
if (!yRanges[y + ""]) {
// Cache Y Range
yRanges[y + ""] = Math.floor((y + 1) * zoom) - yOffset;
}
yRange = yRanges[y + ""];
var i = (y * source.width + x) * 4;
var r = imgData[i];
var g = imgData[i + 1];
var b = imgData[i + 2];
var a = imgData[i + 3];
context.fillStyle = "rgba(" + r + "," + g + "," + b + "," + (a / 255) + ")";
context.fillRect(xOffset, yOffset, xRange-margin, yRange-margin);
yOffset += yRange;
}
yOffset = 0;
xOffset += xRange;
}
return canvas;
}
};
})();

View File

@@ -0,0 +1,31 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.LayerUtils = {
/**
* Create a pskl.model.Layer from an Image object.
* Transparent pixels will either be converted to completely opaque or completely transparent pixels.
* @param {Image} image source image
* @return {pskl.model.Frame} corresponding frame
*/
createFromImage : function (image, frameCount) {
var w = image.width,
h = image.height,
frameWidth = w / frameCount;
var canvas = pskl.CanvasUtils.createCanvas(w, h);
var context = canvas.getContext('2d');
context.drawImage(image, 0,0,w,h,0,0,w,h);
// Draw the zoomed-up pixels to a different canvas context
var frames = [];
for (var i = 0 ; i < frameCount ; i++) {
var imgData = context.getImageData(frameWidth*i,0,frameWidth,h).data;
var frame = pskl.utils.FrameUtils.createFromImageData(imgData, frameWidth, h);
frames.push(frame);
}
return frames;
}
};
})();

9
src/js/utils/Math.js Normal file
View File

@@ -0,0 +1,9 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.Math = {
minmax : function (val, min, max) {
return Math.max(Math.min(val, max), min);
}
};
})();

177
src/js/utils/PixelUtils.js Normal file
View File

@@ -0,0 +1,177 @@
(function () {
var ns = $.namespace("pskl");
ns.PixelUtils = {
getRectanglePixels : function (x0, y0, x1, y1) {
var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1);
var pixels = [];
for(var x = rectangle.x0; x <= rectangle.x1; x++) {
for(var y = rectangle.y0; y <= rectangle.y1; y++) {
pixels.push({"col": x, "row": y});
}
}
return pixels;
},
getBoundRectanglePixels : function (x0, y0, x1, y1) {
var rectangle = this.getOrderedRectangleCoordinates(x0, y0, x1, y1);
var pixels = [];
// Creating horizontal sides of the rectangle:
for(var x = rectangle.x0; x <= rectangle.x1; x++) {
pixels.push({"col": x, "row": rectangle.y0});
pixels.push({"col": x, "row": rectangle.y1});
}
// Creating vertical sides of the rectangle:
for(var y = rectangle.y0; y <= rectangle.y1; y++) {
pixels.push({"col": rectangle.x0, "row": y});
pixels.push({"col": rectangle.x1, "row": y});
}
return pixels;
},
/**
* Return an object of ordered rectangle coordinate.
* In returned object {x0, y0} => top left corner - {x1, y1} => bottom right corner
* @private
*/
getOrderedRectangleCoordinates : function (x0, y0, x1, y1) {
return {
x0 : Math.min(x0, x1),
y0 : Math.min(y0, y1),
x1 : Math.max(x0, x1),
y1 : Math.max(y0, y1)
};
},
/**
* Return the list of pixels that would have been filled by a paintbucket tool applied
* on pixel at coordinate (x,y).
* This function is not altering the Frame object argument.
*
* @param frame pskl.model.Frame The frame target in which we want to paintbucket
* @param col number Column coordinate in the frame
* @param row number Row coordinate in the frame
*
* @return an array of the pixel coordinates paint with the replacement color
*/
getSimilarConnectedPixelsFromFrame: function(frame, col, row) {
// To get the list of connected (eg the same color) pixels, we will use the paintbucket algorithm
// in a fake cloned frame. The returned pixels by the paintbucket algo are the painted pixels
// and are as well connected.
var fakeFrame = frame.clone(); // We just want to
var fakeFillColor = "sdfsdfsdf"; // A fake color that will never match a real color.
var paintedPixels = this.paintSimilarConnectedPixelsFromFrame(fakeFrame, col, row, fakeFillColor);
return paintedPixels;
},
/**
* Apply the paintbucket tool in a frame at the (col, row) initial position
* with the replacement color.
*
* @param frame pskl.model.Frame The frame target in which we want to paintbucket
* @param col number Column coordinate in the frame
* @param row number Row coordinate in the frame
* @param replacementColor string Hexadecimal color used to fill the area
*
* @return an array of the pixel coordinates paint with the replacement color
*/
paintSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor) {
/**
* Queue linear Flood-fill (node, target-color, replacement-color):
* 1. Set Q to the empty queue.
* 2. If the color of node is not equal to target-color, return.
* 3. Add node to Q.
* 4. For each element n of Q:
* 5. If the color of n is equal to target-color:
* 6. Set w and e equal to n.
* 7. Move w to the west until the color of the node to the west of w no longer matches target-color.
* 8. Move e to the east until the color of the node to the east of e no longer matches target-color.
* 9. Set the color of nodes between w and e to replacement-color.
* 10. For each node n between w and e:
* 11. If the color of the node to the north of n is target-color, add that node to Q.
* 12. If the color of the node to the south of n is target-color, add that node to Q.
* 13. Continue looping until Q is exhausted.
* 14. Return.
*/
var paintedPixels = [];
var queue = [];
var dy = [-1, 0, 1, 0];
var dx = [0, 1, 0, -1];
var targetColor;
try {
targetColor = frame.getPixel(col, row);
} catch(e) {
// Frame out of bound exception.
}
if(targetColor == replacementColor) {
return;
}
queue.push({"col": col, "row": row});
var loopCount = 0;
var cellCount = frame.getWidth() * frame.getHeight();
while(queue.length > 0) {
loopCount ++;
var currentItem = queue.pop();
frame.setPixel(currentItem.col, currentItem.row, replacementColor);
paintedPixels.push({"col": currentItem.col, "row": currentItem.row });
for (var i = 0; i < 4; i++) {
var nextCol = currentItem.col + dx[i];
var nextRow = currentItem.row + dy[i];
try {
if (frame.containsPixel(nextCol, nextRow) && frame.getPixel(nextCol, nextRow) == targetColor) {
queue.push({"col": nextCol, "row": nextRow });
}
} catch(e) {
// Frame out of bound exception.
}
}
// Security loop breaker:
if(loopCount > 10 * cellCount) {
console.log("loop breaker called");
break;
}
}
return paintedPixels;
},
/**
* Calculate and return the maximal zoom level to display a picture in a given container.
*
* @param container jQueryObject Container where the picture should be displayed
* @param number pictureHeight height in pixels of the picture to display
* @param number pictureWidth width in pixels of the picture to display
* @return number maximal zoom
*/
calculateZoomForContainer : function (container, pictureHeight, pictureWidth) {
return this.calculateZoom(container.height(), container.width(), pictureHeight, pictureWidth);
},
/**
* Calculate and return the maximal zoom to display a picture for a given height and width.
*
* @param height number Height available to display the picture
* @param width number Width available to display the picture
* @param number pictureHeight height in pixels of the picture to display
* @param number pictureWidth width in pixels of the picture to display
* @return number maximal zoom
*/
calculateZoom : function (height, width, pictureHeight, pictureWidth) {
var heightRatio = Math.floor(height / pictureHeight),
widthRatio = Math.floor(width / pictureWidth);
return Math.min(heightRatio, widthRatio);
}
};
})();

30
src/js/utils/Template.js Normal file
View File

@@ -0,0 +1,30 @@
(function () {
var ns = $.namespace("pskl.utils");
ns.Template = {
get : function (templateId) {
var template = document.getElementById(templateId);
if (template) {
return template.innerHTML;
} else {
console.error("Could not find template for id :", templateId);
}
},
createFromHTML : function (html) {
var dummyEl = document.createElement("div");
dummyEl.innerHTML = html;
return dummyEl.children[0];
},
replace : function (template, dict) {
for (var key in dict) {
if (dict.hasOwnProperty(key)) {
var value = dict[key];
template = template.replace(new RegExp('\\{\\{'+key+'\\}\\}', 'g'), value);
}
}
return template;
}
};
})();

20
src/js/utils/UserAgent.js Normal file
View File

@@ -0,0 +1,20 @@
(function () {
var ns = $.namespace('pskl.utils');
var ua = navigator.userAgent;
ns.UserAgent = {
isIE : /MSIE/i.test( ua ),
isChrome : /Chrome/i.test( ua ),
isFirefox : /Firefox/i.test( ua )
};
ns.UserAgent.version = (function () {
if (pskl.utils.UserAgent.isIE) {
return parseInt(/MSIE\s?(\d+)/i.exec( ua )[1], 10);
} else if (pskl.utils.UserAgent.isChrome) {
return parseInt(/Chrome\/(\d+)/i.exec( ua )[1], 10);
} else if (pskl.utils.UserAgent.isFirefox) {
return parseInt(/Firefox\/(\d+)/i.exec( ua )[1], 10);
}
})();
})();

View File

@@ -0,0 +1,76 @@
(function () {
var ns = $.namespace("pskl");
ns.UserSettings = {
SHOW_GRID : 'SHOW_GRID',
CANVAS_BACKGROUND : 'CANVAS_BACKGROUND',
KEY_TO_DEFAULT_VALUE_MAP_ : {
'SHOW_GRID' : false,
'CANVAS_BACKGROUND' : 'medium-canvas-background'
},
/**
* @private
*/
cache_ : {},
/**
* Static method to access a user defined settings value ot its default
* value if not defined yet.
*/
get : function (key) {
this.checkKeyValidity_(key);
if (!(key in this.cache_)) {
this.cache_[key] =
this.readFromLocalStorage_(key) || this.readFromDefaults_(key);
}
return this.cache_[key];
},
set : function (key, value) {
this.checkKeyValidity_(key);
this.cache_[key] = value;
this.writeToLocalStorage_(key, value);
$.publish(Events.USER_SETTINGS_CHANGED, [key, value]);
},
/**
* @private
*/
readFromLocalStorage_ : function(key) {
var value = window.localStorage[key];
if (typeof value != "undefined") {
value = JSON.parse(value);
}
return value;
},
/**
* @private
*/
writeToLocalStorage_ : function(key, value) {
// TODO(grosbouddha): Catch storage exception here.
window.localStorage[key] = JSON.stringify(value);
},
/**
* @private
*/
readFromDefaults_ : function (key) {
return this.KEY_TO_DEFAULT_VALUE_MAP_[key];
},
/**
* @private
*/
checkKeyValidity_ : function(key) {
if(!(key in this.KEY_TO_DEFAULT_VALUE_MAP_)) {
// TODO(grosbouddha): Define error catching strategy and throw exception from here.
console.log("UserSettings key <"+ key +"> not find in supported keys.");
}
}
};
})();

51
src/js/utils/core.js Normal file
View File

@@ -0,0 +1,51 @@
jQuery.namespace = function() {
var a=arguments, o=null, i, j, d;
for (i=0; i<a.length; i=i+1) {
d=a[i].split(".");
o=window;
for (j=0; j<d.length; j=j+1) {
o[d[j]]=o[d[j]] || {};
o=o[d[j]];
}
}
return o;
};
/**
* Need a polyfill for PhantomJS
*/
if (typeof Function.prototype.bind !== "function") {
Function.prototype.bind = function(scope) {
"use strict";
var _function = this;
return function() {
return _function.apply(scope, arguments);
};
};
}
/**
* @provide pskl.utils
*
* @require Constants
*/
(function() { // namespace: pskl.utils
var ns = $.namespace("pskl.utils");
ns.rgbToHex = function(r, g, b) {
if (r > 255 || g > 255 || b > 255) {
throw "Invalid color component";
}
return ((r << 16) | (g << 8) | b).toString(16);
};
ns.inherit = function(extendedObject, inheritFrom) {
extendedObject.prototype = Object.create(inheritFrom.prototype);
extendedObject.prototype.constructor = extendedObject;
extendedObject.prototype.superclass = inheritFrom.prototype;
};
})();

View File

@@ -0,0 +1,71 @@
(function () {
var ns = $.namespace('pskl.utils.serialization');
ns.Deserializer = function (data, callback) {
this.layersToLoad_ = 0;
this.data_ = data;
this.callback_ = callback;
this.piskel_ = null;
};
ns.Deserializer.deserialize = function (data, callback) {
var deserializer;
if (data.modelVersion == Constants.MODEL_VERSION) {
deserializer = new ns.Deserializer(data, callback);
} else if (data.modelVersion == 1) {
deserializer = new ns.backward.Deserializer_v1(data, callback);
} else {
deserializer = new ns.backward.Deserializer_v0(data, callback);
}
deserializer.deserialize();
};
ns.Deserializer.prototype.deserialize = function (name) {
var data = this.data_;
var piskelData = data.piskel;
name = name || 'Deserialized piskel';
var descriptor = new pskl.model.piskel.Descriptor(name, '');
this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor);
this.layersToLoad_ = piskelData.layers.length;
piskelData.layers.forEach(function (serializedLayer) {
var layer = this.deserializeLayer(serializedLayer);
this.piskel_.addLayer(layer);
}.bind(this));
};
ns.Deserializer.prototype.deserializeLayer = function (layerString) {
var layerData = JSON.parse(layerString);
var layer = new pskl.model.Layer(layerData.name);
// 1 - create an image to load the base64PNG representing the layer
var base64PNG = layerData.base64PNG;
var image = new Image();
// 2 - attach the onload callback that will be triggered asynchronously
image.onload = function () {
// 5 - extract the frames from the loaded image
var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount);
// 6 - add each image to the layer
frames.forEach(layer.addFrame.bind(layer));
this.onLayerLoaded_();
}.bind(this);
// 3 - set the source of the image
image.src = base64PNG;
// 4 - return a pointer to the new layer instance
return layer;
};
ns.Deserializer.prototype.onLayerLoaded_ = function () {
this.layersToLoad_ = this.layersToLoad_ - 1;
if (this.layersToLoad_ === 0) {
this.callback_(this.piskel_);
}
};
})();

View File

@@ -0,0 +1,31 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.Serializer = {
serializePiskel : function (piskel) {
var serializedLayers = piskel.getLayers().map(function (l) {
return pskl.utils.Serializer.serializeLayer(l);
});
return JSON.stringify({
modelVersion : Constants.MODEL_VERSION,
piskel : {
height : piskel.getHeight(),
width : piskel.getWidth(),
layers : serializedLayers
}
});
},
serializeLayer : function (layer) {
var frames = layer.getFrames();
var renderer = new pskl.rendering.FramesheetRenderer(frames);
var base64PNG = renderer.renderAsCanvas().toDataURL();
return JSON.stringify({
name : layer.getName(),
base64PNG : base64PNG,
frameCount : frames.length
});
}
};
})();

View File

@@ -0,0 +1,19 @@
(function () {
var ns = $.namespace('pskl.utils.serialization.backward');
ns.Deserializer_v0 = function (data, callback) {
this.data_ = data;
this.callback_ = callback;
};
ns.Deserializer_v0.prototype.deserialize = function () {
var pixelGrids = this.data_;
var frames = pixelGrids.map(function (grid) {
return pskl.model.Frame.fromPixelGrid(grid);
});
var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', '');
var layer = pskl.model.Layer.fromFrames('Layer 1', frames);
this.callback_(pskl.model.Piskel.fromLayers([layer], descriptor));
};
})();

View File

@@ -0,0 +1,37 @@
(function () {
var ns = $.namespace('pskl.utils.serialization.backward');
ns.Deserializer_v1 = function (data, callback) {
this.callback_ = callback;
this.data_ = data;
};
ns.Deserializer_v1.prototype.deserialize = function () {
var piskelData = this.data_.piskel;
var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', '');
var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor);
piskelData.layers.forEach(function (serializedLayer) {
var layer = this.deserializeLayer(serializedLayer);
piskel.addLayer(layer);
}.bind(this));
this.callback_(piskel);
};
ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) {
var layerData = JSON.parse(layerString);
var layer = new pskl.model.Layer(layerData.name);
layerData.frames.forEach(function (serializedFrame) {
var frame = this.deserializeFrame(serializedFrame);
layer.addFrame(frame);
}.bind(this));
return layer;
};
ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) {
var framePixelGrid = JSON.parse(frameString);
return pskl.model.Frame.fromPixelGrid(framePixelGrid);
};
})();