From 4f54715f705090805846eaa2ca64d90ee946ff7e Mon Sep 17 00:00:00 2001 From: jdescottes Date: Fri, 8 Nov 2013 00:44:24 +0100 Subject: [PATCH 1/7] fix : reduce piskel model size - Initial implementation : working but ... - MODEL_VERSION has been bumped to 2 - The loading process is now theoretically asynchronous (loading images to read the content of the layers), but for now, the asynchronous behaviour is hidden behind a nasty hack, which is somehow similar to lazy loading. When loading the piskel, a Piskel is created synchronously, with fake empty frames, and as the images will get loaded, the fake frames will be replaced by the actual frames. I really don't like this, and the asynchronous nature of the loading should be clearly expressed - There is no backward compatible deserializer for the previous version of the model (1) - The Serializer utils is just badly designed. Serialization and deserialization should be splitted into two different classes - Saving & loading are still done in app.js and should be moved to services BUT : the size of the piskels is now pretty small. A piskel which was using 890kB previously is now using only 10kB. Although it should be noted, that after gzip there is no significant difference between this version and the existing one. The only gains we can really expect with this are : less disk space used on appengine, ability to reuse the layers' pngs directly on piskel-website (but to be honest I can't see any valid use case for this) --- js/Constants.js | 2 +- js/app.js | 4 +- js/controller/settings/GifExportController.js | 5 +- js/rendering/CanvasRenderer.js | 18 ++--- js/rendering/FramesheetRenderer.js | 43 +++++++++++ js/rendering/PiskelRenderer.js | 14 ++++ js/rendering/SpritesheetRenderer.js | 44 ------------ js/service/LocalStorageService.js | 7 +- js/utils/FrameUtils.js | 22 +++--- js/utils/LayerUtils.js | 31 ++++++++ js/utils/Serializer.js | 72 ++++++++++++++----- piskel-script-list.js | 4 +- 12 files changed, 175 insertions(+), 91 deletions(-) create mode 100644 js/rendering/FramesheetRenderer.js create mode 100644 js/rendering/PiskelRenderer.js delete mode 100644 js/rendering/SpritesheetRenderer.js create mode 100644 js/utils/LayerUtils.js diff --git a/js/Constants.js b/js/Constants.js index fd0bcdc2..f4a37de4 100644 --- a/js/Constants.js +++ b/js/Constants.js @@ -6,7 +6,7 @@ var Constants = { FPS : 12 }, - MODEL_VERSION : 1, + MODEL_VERSION : 2, MAX_HEIGHT : 128, MAX_WIDTH : 128, diff --git a/js/app.js b/js/app.js index 3262db09..3b76f30f 100644 --- a/js/app.js +++ b/js/app.js @@ -239,8 +239,8 @@ }, getFramesheetAsPng : function () { - var renderer = new pskl.rendering.SpritesheetRenderer(this.piskelController); - var framesheetCanvas = renderer.render(); + var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); + var framesheetCanvas = renderer.renderAsCanvas(); return framesheetCanvas.toDataURL("image/png"); }, diff --git a/js/controller/settings/GifExportController.js b/js/controller/settings/GifExportController.js index 42e57d3d..ae0b6832 100644 --- a/js/controller/settings/GifExportController.js +++ b/js/controller/settings/GifExportController.js @@ -114,8 +114,9 @@ for (var i = 0; i < this.piskelController.getFrameCount(); i++) { var frame = this.piskelController.getFrameAt(i); - var renderer = new pskl.rendering.CanvasRenderer(frame, dpi); - gif.addFrame(renderer.render(), { + var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, dpi); + var canvas = canvasRenderer.render(); + gif.addFrame(canvas.getContext('2d'), { delay: 1000 / fps }); } diff --git a/js/rendering/CanvasRenderer.js b/js/rendering/CanvasRenderer.js index 2153f207..2e5e99af 100644 --- a/js/rendering/CanvasRenderer.js +++ b/js/rendering/CanvasRenderer.js @@ -19,24 +19,20 @@ ns.CanvasRenderer.prototype.render = function () { var canvas = this.createCanvas_(); var context = canvas.getContext('2d'); - for(var col = 0, width = this.frame.getWidth(); col < width; col++) { - for(var row = 0, height = this.frame.getHeight(); row < height; row++) { - var color = this.frame.getPixel(col, row); - this.renderPixel_(color, col, row, context); - } - } - return context; + this.frame.forEachPixel(function (color, x, y) { + this.renderPixel_(color, x, y, context); + }.bind(this)); + + return canvas; }; - ns.CanvasRenderer.prototype.renderPixel_ = function (color, col, row, context) { - + ns.CanvasRenderer.prototype.renderPixel_ = function (color, x, y, context) { if(color == Constants.TRANSPARENT_COLOR) { color = this.transparentColor_; } context.fillStyle = color; - - context.fillRect(col * this.dpi, row * this.dpi, this.dpi, this.dpi); + context.fillRect(x * this.dpi, y * this.dpi, this.dpi, this.dpi); }; ns.CanvasRenderer.prototype.createCanvas_ = function () { diff --git a/js/rendering/FramesheetRenderer.js b/js/rendering/FramesheetRenderer.js new file mode 100644 index 00000000..06eb4d99 --- /dev/null +++ b/js/rendering/FramesheetRenderer.js @@ -0,0 +1,43 @@ +(function () { + var ns = $.namespace('pskl.rendering'); + + /** + * Render an array of frames + * @param {Array.} frames + */ + ns.FramesheetRenderer = function (frames) { + if (frames.length > 0) { + this.frames = frames; + } else { + throw 'FramesheetRenderer : Invalid argument : frames is empty'; + } + }; + + ns.FramesheetRenderer.prototype.renderAsCanvas = function () { + var canvas = this.createCanvas_(); + for (var i = 0 ; i < this.frames.length ; i++) { + var frame = this.frames[i]; + this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0); + } + return canvas; + }; + + ns.FramesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) { + var context = canvas.getContext('2d'); + frame.forEachPixel(function (color, x, y) { + if(color != Constants.TRANSPARENT_COLOR) { + context.fillStyle = color; + context.fillRect(x + offsetWidth, y + offsetHeight, 1, 1); + } + }); + }; + + ns.FramesheetRenderer.prototype.createCanvas_ = function () { + var sampleFrame = this.frames[0]; + var count = this.frames.length; + var width = count * sampleFrame.getWidth(); + var height = sampleFrame.getHeight(); + return pskl.CanvasUtils.createCanvas(width, height); + }; + +})(); \ No newline at end of file diff --git a/js/rendering/PiskelRenderer.js b/js/rendering/PiskelRenderer.js new file mode 100644 index 00000000..33a0f2f4 --- /dev/null +++ b/js/rendering/PiskelRenderer.js @@ -0,0 +1,14 @@ +(function () { + + var ns = $.namespace("pskl.rendering"); + + ns.PiskelRenderer = function (piskelController) { + var frames = []; + for (var i = 0 ; i < piskelController.getFrameCount() ; i++) { + frames.push(this.piskelController.getFrameAt(i)); + } + ns.FramesheetRenderer.call(this, frames); + }; + + pskl.utils.inherit(ns.PiskelRenderer, ns.FramesheetRenderer); +})(); \ No newline at end of file diff --git a/js/rendering/SpritesheetRenderer.js b/js/rendering/SpritesheetRenderer.js deleted file mode 100644 index d634da0f..00000000 --- a/js/rendering/SpritesheetRenderer.js +++ /dev/null @@ -1,44 +0,0 @@ -(function () { - - var ns = $.namespace("pskl.rendering"); - - ns.SpritesheetRenderer = function (piskelController) { - this.piskelController = piskelController; - }; - - ns.SpritesheetRenderer.prototype.render = function () { - var canvas = this.createCanvas_(); - for (var i = 0 ; i < this.piskelController.getFrameCount() ; i++) { - var frame = this.piskelController.getFrameAt(i); - this.drawFrameInCanvas_(frame, canvas, i * this.piskelController.getWidth(), 0); - } - return canvas; - }; - - /** - * TODO(juliandescottes): Mutualize with code already present in FrameRenderer - */ - ns.SpritesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) { - var context = canvas.getContext('2d'); - for(var col = 0, width = frame.getWidth(); col < width; col++) { - for(var row = 0, height = frame.getHeight(); row < height; row++) { - var color = frame.getPixel(col, row); - if(color != Constants.TRANSPARENT_COLOR) { - context.fillStyle = color; - context.fillRect(col + offsetWidth, row + offsetHeight, 1, 1); - } - } - } - }; - - ns.SpritesheetRenderer.prototype.createCanvas_ = function () { - var frameCount = this.piskelController.getFrameCount(); - if (frameCount > 0){ - var width = frameCount * this.piskelController.getWidth(); - var height = this.piskelController.getHeight(); - return pskl.CanvasUtils.createCanvas(width, height); - } else { - throw "Cannot render empty Spritesheet"; - } - }; -})(); \ No newline at end of file diff --git a/js/service/LocalStorageService.js b/js/service/LocalStorageService.js index 6267773f..7f15243a 100644 --- a/js/service/LocalStorageService.js +++ b/js/service/LocalStorageService.js @@ -36,7 +36,6 @@ * @private */ ns.LocalStorageService.prototype.persistToLocalStorage_ = function() { - console.log('[LocalStorage service]: Snapshot stored'); window.localStorage.snapShot = this.piskelController.serialize(); }; @@ -45,9 +44,9 @@ * @private */ ns.LocalStorageService.prototype.restoreFromLocalStorage_ = function() { - - this.piskelController.deserialize(window.localStorage.snapShot); - this.piskelController.setCurrentFrameIndex(0); + var framesheet = JSON.parse(window.localStorage.snapShot); + var piskel = pskl.utils.Serializer.createPiskel(framesheet); + pskl.app.piskelController.setPiskel(piskel); }; /** diff --git a/js/utils/FrameUtils.js b/js/utils/FrameUtils.js index ef14f935..7b55cd76 100644 --- a/js/utils/FrameUtils.js +++ b/js/utils/FrameUtils.js @@ -36,21 +36,25 @@ 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); + }, + + createFromImageData : function (imageData, width, height) { // Draw the zoomed-up pixels to a different canvas context var frame = []; - for (var x=0;x Date: Wed, 13 Nov 2013 22:57:07 +0100 Subject: [PATCH 2/7] fix : reduce piskel model size - added backward compatible implementation for v1 models --- js/utils/Serializer.js | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/js/utils/Serializer.js b/js/utils/Serializer.js index fa706038..6f04af3f 100644 --- a/js/utils/Serializer.js +++ b/js/utils/Serializer.js @@ -30,13 +30,7 @@ }); }, - deserializePiskel : function (piskelString) { - var data = JSON.parse(piskelString); - return this.createPiskel(data); - }, - /** - * Similar to deserializePiskel, but dealing directly with a parsed piskel * @param {Object} data JSON.parse of a serialized piskel * @return {pskl.model.Piskel} a piskel */ @@ -45,13 +39,13 @@ if (data.modelVersion == Constants.MODEL_VERSION) { var piskelData = data.piskel; piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); - layersToLoad = piskelData.layers; + piskelData.layers.forEach(function (serializedLayer) { var layer = pskl.utils.Serializer.deserializeLayer(serializedLayer); piskel.addLayer(layer); }); } else if (data.modelVersion == 1) { - throw 'No backward compatible adapter for modelVersion 1'; + piskel = pskl.utils.Serializer.backwardDeserializer_v1(data); } else { piskel = pskl.utils.Serializer.backwardDeserializer_(data); } @@ -91,6 +85,23 @@ return layer; }, + deserializeFrame : function (frameString) { + var framePixelGrid = JSON.parse(frameString); + return pskl.model.Frame.fromPixelGrid(framePixelGrid); + }, + + backwardDeserializer_v1 : function (data) { + var piskelData = data.piskel; + var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); + + piskelData.layers.forEach(function (serializedLayer) { + var layer = pskl.utils.Serializer.deserializeLayer_v1(serializedLayer); + piskel.addLayer(layer); + }); + + return piskel; + }, + deserializeLayer_v1 : function (layerString) { var layerData = JSON.parse(layerString); var layer = new pskl.model.Layer(layerData.name); @@ -102,11 +113,6 @@ return layer; }, - deserializeFrame : function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }, - /** * Deserialize old piskel framesheets. Initially piskels were stored as arrays of frames : "[[pixelGrid],[pixelGrid],[pixelGrid]]". */ From df4978f6afc0767d58688a5c4103b46e80b90461 Mon Sep 17 00:00:00 2001 From: jdescottes Date: Wed, 13 Nov 2013 23:39:43 +0100 Subject: [PATCH 3/7] fix : reduce piskel model size + piskel deserialization is now clearly asynchronous + added utils.Deserializer (not a singleton though, more a builder/loader) + utils.Deserializer constructor expects a callback + when all layers are loaded and piskel is ready, the callback provided by the client is called with piskel as the first argument - Deserializer doesn't fit in the utils package, which should be reserved to singletons : can move it to service as a PiskelLoaderService, and Deserializer could remain with only the purely static methods - ImportController is realying on the Deserializer to build a Piskel but it shouldn't. Find a way to mutualize the code necessary to create a Piskel from an array of pskl.model.Frame - still cleanup to do in app.js - comments to add as well --- js/app.js | 18 +++--- js/controller/settings/ImportController.js | 14 +++-- js/service/LocalStorageService.js | 6 +- js/utils/Deserializer.js | 64 ++++++++++++++++++++++ js/utils/Serializer.js | 35 ++---------- piskel-script-list.js | 1 + 6 files changed, 95 insertions(+), 43 deletions(-) create mode 100644 js/utils/Deserializer.js diff --git a/js/app.js b/js/app.js index 3b76f30f..236063b0 100644 --- a/js/app.js +++ b/js/app.js @@ -93,9 +93,11 @@ finishInitAppEngine_ : function () { if (pskl.framesheetData_ && pskl.framesheetData_.content) { - var piskel = pskl.utils.Serializer.createPiskel(pskl.framesheetData_.content); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(pskl.framesheetData_.fps); + var deserializer = new pskl.utils.Deserializer(pskl.framesheetData_.content, function (piskel) { + pskl.app.piskelController.setPiskel(piskel); + pskl.app.animationController.setFPS(pskl.framesheetData_.fps); + }); + deserializer.deserialize(); } }, @@ -156,10 +158,12 @@ xhr.responseType = 'text'; xhr.onload = function (e) { var res = JSON.parse(this.responseText); - var piskel = pskl.utils.Serializer.createPiskel(res.framesheet); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(res.fps); - $.publish(Events.HIDE_NOTIFICATION); + var deserializer = new pskl.utils.Deserializer(res.framesheet, function (piskel) { + pskl.app.piskelController.setPiskel(piskel); + pskl.app.animationController.setFPS(res.fps); + $.publish(Events.HIDE_NOTIFICATION); + }); + deserializer.deserialize(); }; xhr.onerror = function () { diff --git a/js/controller/settings/ImportController.js b/js/controller/settings/ImportController.js index 4a7e73cd..3fca0487 100644 --- a/js/controller/settings/ImportController.js +++ b/js/controller/settings/ImportController.js @@ -153,11 +153,15 @@ var image = pskl.utils.ImageResizer.resize(this.importedImage_, w, h, smoothing); var frame = pskl.utils.FrameUtils.createFromImage(image); - var piskel = pskl.utils.Serializer.createPiskel([frame]); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); - - this.reset_(); + // TODO : juliandescottes : here we only want to create a layer from an array of frames, and create a new piskel using this layer + // we shouldn't use the deserializer for this ... it's only working because it's falling back to the old implementation + // bad, very bad + var deserializer = new pskl.utils.Deserializer([frame], function (piskel) { + pskl.app.piskelController.setPiskel(piskel); + pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); + this.reset_(); + }.bind(this)); + deserializer.deserialize(); } } }; diff --git a/js/service/LocalStorageService.js b/js/service/LocalStorageService.js index 7f15243a..7f4d9ed8 100644 --- a/js/service/LocalStorageService.js +++ b/js/service/LocalStorageService.js @@ -45,8 +45,10 @@ */ ns.LocalStorageService.prototype.restoreFromLocalStorage_ = function() { var framesheet = JSON.parse(window.localStorage.snapShot); - var piskel = pskl.utils.Serializer.createPiskel(framesheet); - pskl.app.piskelController.setPiskel(piskel); + var deserializer = new pskl.utils.Deserializer(framesheet, function (piskel) { + pskl.app.piskelController.setPiskel(piskel); + }); + deserializer.deserialize(); }; /** diff --git a/js/utils/Deserializer.js b/js/utils/Deserializer.js new file mode 100644 index 00000000..5a248bab --- /dev/null +++ b/js/utils/Deserializer.js @@ -0,0 +1,64 @@ +(function () { + var ns = $.namespace('pskl.utils'); + + ns.Deserializer = function (data, callback) { + this.layersToLoad_ = 0; + this.data_ = data; + this.callback_ = callback; + this.piskel_ = null; + }; + + ns.Deserializer.prototype.deserialize = function () { + var data = this.data_; + if (data.modelVersion == Constants.MODEL_VERSION) { + var piskelData = data.piskel; + this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height); + + this.layersToLoad_ = piskelData.layers.length; + + piskelData.layers.forEach(function (serializedLayer) { + var layer = this.deserializeLayer(serializedLayer); + this.piskel_.addLayer(layer); + }.bind(this)); + } else if (data.modelVersion == 1) { + this.callback_(pskl.utils.Serializer.backwardDeserializer_v1(data)); + } else { + this.callback_(pskl.utils.Serializer.backwardDeserializer_(data)); + } + }; + + 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(function (frame) { + layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); + }); + + 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_); + } + }; +})(); \ No newline at end of file diff --git a/js/utils/Serializer.js b/js/utils/Serializer.js index 6f04af3f..d103ad77 100644 --- a/js/utils/Serializer.js +++ b/js/utils/Serializer.js @@ -30,29 +30,6 @@ }); }, - /** - * @param {Object} data JSON.parse of a serialized piskel - * @return {pskl.model.Piskel} a piskel - */ - createPiskel : function (data) { - var piskel = null; - if (data.modelVersion == Constants.MODEL_VERSION) { - var piskelData = data.piskel; - piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = pskl.utils.Serializer.deserializeLayer(serializedLayer); - piskel.addLayer(layer); - }); - } else if (data.modelVersion == 1) { - piskel = pskl.utils.Serializer.backwardDeserializer_v1(data); - } else { - piskel = pskl.utils.Serializer.backwardDeserializer_(data); - } - - return piskel; - }, - deserializeLayer : function (layerString) { var layerData = JSON.parse(layerString); var layer = new pskl.model.Layer(layerData.name); @@ -85,11 +62,6 @@ return layer; }, - deserializeFrame : function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }, - backwardDeserializer_v1 : function (data) { var piskelData = data.piskel; var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); @@ -106,13 +78,18 @@ var layerData = JSON.parse(layerString); var layer = new pskl.model.Layer(layerData.name); layerData.frames.forEach(function (serializedFrame) { - var frame = pskl.utils.Serializer.deserializeFrame(serializedFrame); + var frame = pskl.utils.Serializer.deserializeFrame_v1(serializedFrame); layer.addFrame(frame); }); return layer; }, + deserializeFrame_v1 : function (frameString) { + var framePixelGrid = JSON.parse(frameString); + return pskl.model.Frame.fromPixelGrid(framePixelGrid); + }, + /** * Deserialize old piskel framesheets. Initially piskels were stored as arrays of frames : "[[pixelGrid],[pixelGrid],[pixelGrid]]". */ diff --git a/piskel-script-list.js b/piskel-script-list.js index 80df9fa9..f4a02c4d 100644 --- a/piskel-script-list.js +++ b/piskel-script-list.js @@ -19,6 +19,7 @@ exports.scripts = [ "js/utils/LayerUtils.js", "js/utils/ImageResizer.js", "js/utils/PixelUtils.js", + "js/utils/Deserializer.js", "js/utils/Serializer.js", "js/utils/Template.js", "js/utils/UserSettings.js", From e9a2ccfd1d9c3c7e22006da2d4566a05e883ff45 Mon Sep 17 00:00:00 2001 From: jdescottes Date: Wed, 13 Nov 2013 23:51:27 +0100 Subject: [PATCH 4/7] fix : reduce piskel model size : fix import feature --- js/utils/FrameUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/utils/FrameUtils.js b/js/utils/FrameUtils.js index 7b55cd76..b20d84fa 100644 --- a/js/utils/FrameUtils.js +++ b/js/utils/FrameUtils.js @@ -36,7 +36,7 @@ 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); + return pskl.utils.FrameUtils.createFromImageData(imgData, w, h); }, createFromImageData : function (imageData, width, height) { From 4a1a7b6c2b2daeded6aabc2042fadff97a472e87 Mon Sep 17 00:00:00 2001 From: jdescottes Date: Thu, 14 Nov 2013 23:03:29 +0100 Subject: [PATCH 5/7] fix : reduce piskel model size : ImportController + ImportController is no longer relying on the deserializer to build a piskel instance + Static builders have been added to Piskel and Layer to help easily create new instances from existing elements --- diff | 179 +++++++++++++++++++++ js/controller/settings/ImportController.js | 15 +- js/model/Layer.js | 13 ++ js/model/Piskel.js | 18 +++ js/utils/Deserializer.js | 4 +- js/utils/FrameUtils.js | 10 +- js/utils/Serializer.js | 48 +----- 7 files changed, 228 insertions(+), 59 deletions(-) create mode 100644 diff diff --git a/diff b/diff new file mode 100644 index 00000000..4da927ae --- /dev/null +++ b/diff @@ -0,0 +1,179 @@ +diff --git a/js/controller/settings/ImportController.js b/js/controller/settings/ImportController.js +index 3fca048..3c94eaa 100644 +--- a/js/controller/settings/ImportController.js ++++ b/js/controller/settings/ImportController.js +@@ -153,15 +153,12 @@ + var image = pskl.utils.ImageResizer.resize(this.importedImage_, w, h, smoothing); + var frame = pskl.utils.FrameUtils.createFromImage(image); + +- // TODO : juliandescottes : here we only want to create a layer from an array of frames, and create a new piskel using this layer +- // we shouldn't use the deserializer for this ... it's only working because it's falling back to the old implementation +- // bad, very bad +- var deserializer = new pskl.utils.Deserializer([frame], function (piskel) { +- pskl.app.piskelController.setPiskel(piskel); +- pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); +- this.reset_(); +- }.bind(this)); +- deserializer.deserialize(); ++ var layer = pskl.model.Layer.fromFrames('Layer 1', [frame]); ++ var piskel = pskl.model.Piskel.fromLayers([layer]); ++ ++ pskl.app.piskelController.setPiskel(piskel); ++ pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); ++ this.reset_(); + } + } + }; +diff --git a/js/model/Layer.js b/js/model/Layer.js +index 0132e6a..464b1f9 100644 +--- a/js/model/Layer.js ++++ b/js/model/Layer.js +@@ -10,6 +10,12 @@ + } + }; + ++ ns.Layer.fromFrames = function (name, frames) { ++ var layer = new ns.Layer(name); ++ frames.forEach(layer.addFrame.bind(layer)); ++ return layer; ++ }; ++ + ns.Layer.prototype.getName = function () { + return this.name; + }; +diff --git a/js/model/Piskel.js b/js/model/Piskel.js +index 7748408..223d618 100644 +--- a/js/model/Piskel.js ++++ b/js/model/Piskel.js +@@ -21,6 +21,18 @@ + } + }; + ++ ns.Piskel.fromLayers = function (layers) { ++ var piskel = null; ++ if (layers.length > 0 && layers[0].length() > 0) { ++ var sampleFrame = layers[0].getFrameAt(0); ++ piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight()); ++ layers.forEach(piskel.addLayer.bind(piskel)); ++ } else { ++ throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument' ++ } ++ return piskel; ++ }; ++ + ns.Piskel.prototype.getLayers = function () { + return this.layers; + }; +diff --git a/js/utils/Deserializer.js b/js/utils/Deserializer.js +index 5a248ba..56f64e4 100644 +--- a/js/utils/Deserializer.js ++++ b/js/utils/Deserializer.js +@@ -41,9 +41,7 @@ + var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); + + // 6 - add each image to the layer +- frames.forEach(function (frame) { +- layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); +- }); ++ frames.forEach(layer.addFrame.bind(layer)); + + this.onLayerLoaded_(); + }.bind(this); +diff --git a/js/utils/FrameUtils.js b/js/utils/FrameUtils.js +index b20d84f..055c8ed 100644 +--- a/js/utils/FrameUtils.js ++++ b/js/utils/FrameUtils.js +@@ -41,9 +41,9 @@ + + createFromImageData : function (imageData, width, height) { + // Draw the zoomed-up pixels to a different canvas context +- var frame = []; ++ var grid = []; + for (var x = 0 ; x < width ; x++){ +- frame[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; +@@ -52,13 +52,13 @@ + var b = imageData[i+2]; + var a = imageData[i+3]; + if (a < 125) { +- frame[x][y] = Constants.TRANSPARENT_COLOR; ++ grid[x][y] = Constants.TRANSPARENT_COLOR; + } else { +- frame[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); ++ grid[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); + } + } + } +- return frame; ++ return pskl.model.Frame.fromPixelGrid(grid); + }, + + /** +diff --git a/js/utils/Serializer.js b/js/utils/Serializer.js +index d103ad7..5841e6b 100644 +--- a/js/utils/Serializer.js ++++ b/js/utils/Serializer.js +@@ -30,38 +30,6 @@ + }); + }, + +- deserializeLayer : function (layerString) { +- var layerData = JSON.parse(layerString); +- var layer = new pskl.model.Layer(layerData.name); +- // TODO : nasty trick to keep the whole loading process lazily synchronous +- // 1 - adding a fake frame so that the rendering can start +- layer.addFrame(new pskl.model.Frame(32,32)); +- +- // 2 - create an image to load the base64PNG representing the layer +- var base64PNG = layerData.base64PNG; +- var image = new Image(); +- +- // 3 - attach the onload callback that will be triggered asynchronously +- image.onload = function () { +- // 6 - remove the fake frame +- layer.removeFrameAt(0); +- +- // 7 - extract the frames from the loaded image +- var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); +- +- // 8 - add each image to the layer +- frames.forEach(function (frame) { +- layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); +- }); +- }; +- +- // 4 - set the source of the image +- image.src = base64PNG; +- +- // 5 - return a pointer to the new layer instance, which at this point contains a fake frame +- return layer; +- }, +- + backwardDeserializer_v1 : function (data) { + var piskelData = data.piskel; + var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); +@@ -93,16 +61,12 @@ + /** + * Deserialize old piskel framesheets. Initially piskels were stored as arrays of frames : "[[pixelGrid],[pixelGrid],[pixelGrid]]". + */ +- backwardDeserializer_ : function (frames) { +- var layer = new pskl.model.Layer('Layer 1'); +- frames.forEach(function (frame) { +- layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); ++ backwardDeserializer_ : function (pixelGrids) { ++ var frames = pixelGrids.map(function (grid) { ++ return pskl.model.Frame.fromPixelGrid(grid); + }); +- var width = layer.getFrameAt(0).getWidth(), height = layer.getFrameAt(0).getHeight(); +- var piskel = new pskl.model.Piskel(width, height); +- piskel.addLayer(layer); +- +- return piskel; ++ var layer = pskl.model.Layer.fromFrames('Layer 1', frames); ++ return pskl.model.Piskel.fromLayers([layer]); + } + }; + })(); diff --git a/js/controller/settings/ImportController.js b/js/controller/settings/ImportController.js index 3fca0487..3c94eaa5 100644 --- a/js/controller/settings/ImportController.js +++ b/js/controller/settings/ImportController.js @@ -153,15 +153,12 @@ var image = pskl.utils.ImageResizer.resize(this.importedImage_, w, h, smoothing); var frame = pskl.utils.FrameUtils.createFromImage(image); - // TODO : juliandescottes : here we only want to create a layer from an array of frames, and create a new piskel using this layer - // we shouldn't use the deserializer for this ... it's only working because it's falling back to the old implementation - // bad, very bad - var deserializer = new pskl.utils.Deserializer([frame], function (piskel) { - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); - this.reset_(); - }.bind(this)); - deserializer.deserialize(); + var layer = pskl.model.Layer.fromFrames('Layer 1', [frame]); + var piskel = pskl.model.Piskel.fromLayers([layer]); + + pskl.app.piskelController.setPiskel(piskel); + pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); + this.reset_(); } } }; diff --git a/js/model/Layer.js b/js/model/Layer.js index 0132e6a6..3725622b 100644 --- a/js/model/Layer.js +++ b/js/model/Layer.js @@ -10,6 +10,19 @@ } }; + /** + * Create a Layer instance from an already existing set a Frames + * @static + * @param {String} name layer's name + * @param {Array} frames should all have the same dimensions + * @return {pskl.model.Layer} + */ + ns.Layer.fromFrames = function (name, frames) { + var layer = new ns.Layer(name); + frames.forEach(layer.addFrame.bind(layer)); + return layer; + }; + ns.Layer.prototype.getName = function () { return this.name; }; diff --git a/js/model/Piskel.js b/js/model/Piskel.js index 7748408f..77e7f261 100644 --- a/js/model/Piskel.js +++ b/js/model/Piskel.js @@ -21,6 +21,24 @@ } }; + /** + * Create a piskel instance from an existing set of (non empty) layers + * Layers should all be synchronized : same number of frames, same dimensions + * @param {Array} layers + * @return {pskl.model.Piskel} + */ + ns.Piskel.fromLayers = function (layers) { + var piskel = null; + if (layers.length > 0 && layers[0].length() > 0) { + var sampleFrame = layers[0].getFrameAt(0); + piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight()); + layers.forEach(piskel.addLayer.bind(piskel)); + } else { + throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument'; + } + return piskel; + }; + ns.Piskel.prototype.getLayers = function () { return this.layers; }; diff --git a/js/utils/Deserializer.js b/js/utils/Deserializer.js index 5a248bab..56f64e4f 100644 --- a/js/utils/Deserializer.js +++ b/js/utils/Deserializer.js @@ -41,9 +41,7 @@ var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); // 6 - add each image to the layer - frames.forEach(function (frame) { - layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); - }); + frames.forEach(layer.addFrame.bind(layer)); this.onLayerLoaded_(); }.bind(this); diff --git a/js/utils/FrameUtils.js b/js/utils/FrameUtils.js index b20d84fa..055c8edd 100644 --- a/js/utils/FrameUtils.js +++ b/js/utils/FrameUtils.js @@ -41,9 +41,9 @@ createFromImageData : function (imageData, width, height) { // Draw the zoomed-up pixels to a different canvas context - var frame = []; + var grid = []; for (var x = 0 ; x < width ; x++){ - frame[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; @@ -52,13 +52,13 @@ var b = imageData[i+2]; var a = imageData[i+3]; if (a < 125) { - frame[x][y] = Constants.TRANSPARENT_COLOR; + grid[x][y] = Constants.TRANSPARENT_COLOR; } else { - frame[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); + grid[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); } } } - return frame; + return pskl.model.Frame.fromPixelGrid(grid); }, /** diff --git a/js/utils/Serializer.js b/js/utils/Serializer.js index d103ad77..cab86bc4 100644 --- a/js/utils/Serializer.js +++ b/js/utils/Serializer.js @@ -30,38 +30,6 @@ }); }, - deserializeLayer : function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - // TODO : nasty trick to keep the whole loading process lazily synchronous - // 1 - adding a fake frame so that the rendering can start - layer.addFrame(new pskl.model.Frame(32,32)); - - // 2 - create an image to load the base64PNG representing the layer - var base64PNG = layerData.base64PNG; - var image = new Image(); - - // 3 - attach the onload callback that will be triggered asynchronously - image.onload = function () { - // 6 - remove the fake frame - layer.removeFrameAt(0); - - // 7 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); - - // 8 - add each image to the layer - frames.forEach(function (frame) { - layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); - }); - }; - - // 4 - set the source of the image - image.src = base64PNG; - - // 5 - return a pointer to the new layer instance, which at this point contains a fake frame - return layer; - }, - backwardDeserializer_v1 : function (data) { var piskelData = data.piskel; var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); @@ -91,18 +59,14 @@ }, /** - * Deserialize old piskel framesheets. Initially piskels were stored as arrays of frames : "[[pixelGrid],[pixelGrid],[pixelGrid]]". + * Deserialize old piskel framesheets. Initially piskels were stored as arrays of pixelGrids : "[[pixelGrid],[pixelGrid],[pixelGrid]]". */ - backwardDeserializer_ : function (frames) { - var layer = new pskl.model.Layer('Layer 1'); - frames.forEach(function (frame) { - layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); + backwardDeserializer_ : function (pixelGrids) { + var frames = pixelGrids.map(function (grid) { + return pskl.model.Frame.fromPixelGrid(grid); }); - var width = layer.getFrameAt(0).getWidth(), height = layer.getFrameAt(0).getHeight(); - var piskel = new pskl.model.Piskel(width, height); - piskel.addLayer(layer); - - return piskel; + var layer = pskl.model.Layer.fromFrames('Layer 1', frames); + return pskl.model.Piskel.fromLayers([layer]); } }; })(); From 86cd1cdeaadc52b034bb95ba474c813f2ca174dd Mon Sep 17 00:00:00 2001 From: jdescottes Date: Fri, 15 Nov 2013 00:03:05 +0100 Subject: [PATCH 6/7] fix : reduce piskel model size + moved Serializer and Deserializer to utils.serialization package + put all backward code in utils.serialization.backward + added static method on Deserializer to make its usage similar to other utils in the package - still not happy with the names used in Deserializer classes (deserializer.deserialize ...) --- diff | 179 ------------------ js/app.js | 6 +- js/service/LocalStorageService.js | 3 +- js/utils/Serializer.js | 72 ------- js/utils/{ => serialization}/Deserializer.js | 34 ++-- js/utils/serialization/Serializer.js | 31 +++ .../serialization/backward/Deserializer_v0.js | 18 ++ .../serialization/backward/Deserializer_v1.js | 36 ++++ piskel-script-list.js | 6 +- 9 files changed, 112 insertions(+), 273 deletions(-) delete mode 100644 diff delete mode 100644 js/utils/Serializer.js rename js/utils/{ => serialization}/Deserializer.js (66%) create mode 100644 js/utils/serialization/Serializer.js create mode 100644 js/utils/serialization/backward/Deserializer_v0.js create mode 100644 js/utils/serialization/backward/Deserializer_v1.js diff --git a/diff b/diff deleted file mode 100644 index 4da927ae..00000000 --- a/diff +++ /dev/null @@ -1,179 +0,0 @@ -diff --git a/js/controller/settings/ImportController.js b/js/controller/settings/ImportController.js -index 3fca048..3c94eaa 100644 ---- a/js/controller/settings/ImportController.js -+++ b/js/controller/settings/ImportController.js -@@ -153,15 +153,12 @@ - var image = pskl.utils.ImageResizer.resize(this.importedImage_, w, h, smoothing); - var frame = pskl.utils.FrameUtils.createFromImage(image); - -- // TODO : juliandescottes : here we only want to create a layer from an array of frames, and create a new piskel using this layer -- // we shouldn't use the deserializer for this ... it's only working because it's falling back to the old implementation -- // bad, very bad -- var deserializer = new pskl.utils.Deserializer([frame], function (piskel) { -- pskl.app.piskelController.setPiskel(piskel); -- pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); -- this.reset_(); -- }.bind(this)); -- deserializer.deserialize(); -+ var layer = pskl.model.Layer.fromFrames('Layer 1', [frame]); -+ var piskel = pskl.model.Piskel.fromLayers([layer]); -+ -+ pskl.app.piskelController.setPiskel(piskel); -+ pskl.app.animationController.setFPS(Constants.DEFAULT.FPS); -+ this.reset_(); - } - } - }; -diff --git a/js/model/Layer.js b/js/model/Layer.js -index 0132e6a..464b1f9 100644 ---- a/js/model/Layer.js -+++ b/js/model/Layer.js -@@ -10,6 +10,12 @@ - } - }; - -+ ns.Layer.fromFrames = function (name, frames) { -+ var layer = new ns.Layer(name); -+ frames.forEach(layer.addFrame.bind(layer)); -+ return layer; -+ }; -+ - ns.Layer.prototype.getName = function () { - return this.name; - }; -diff --git a/js/model/Piskel.js b/js/model/Piskel.js -index 7748408..223d618 100644 ---- a/js/model/Piskel.js -+++ b/js/model/Piskel.js -@@ -21,6 +21,18 @@ - } - }; - -+ ns.Piskel.fromLayers = function (layers) { -+ var piskel = null; -+ if (layers.length > 0 && layers[0].length() > 0) { -+ var sampleFrame = layers[0].getFrameAt(0); -+ piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight()); -+ layers.forEach(piskel.addLayer.bind(piskel)); -+ } else { -+ throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument' -+ } -+ return piskel; -+ }; -+ - ns.Piskel.prototype.getLayers = function () { - return this.layers; - }; -diff --git a/js/utils/Deserializer.js b/js/utils/Deserializer.js -index 5a248ba..56f64e4 100644 ---- a/js/utils/Deserializer.js -+++ b/js/utils/Deserializer.js -@@ -41,9 +41,7 @@ - var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); - - // 6 - add each image to the layer -- frames.forEach(function (frame) { -- layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); -- }); -+ frames.forEach(layer.addFrame.bind(layer)); - - this.onLayerLoaded_(); - }.bind(this); -diff --git a/js/utils/FrameUtils.js b/js/utils/FrameUtils.js -index b20d84f..055c8ed 100644 ---- a/js/utils/FrameUtils.js -+++ b/js/utils/FrameUtils.js -@@ -41,9 +41,9 @@ - - createFromImageData : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context -- var frame = []; -+ var grid = []; - for (var x = 0 ; x < width ; x++){ -- frame[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; -@@ -52,13 +52,13 @@ - var b = imageData[i+2]; - var a = imageData[i+3]; - if (a < 125) { -- frame[x][y] = Constants.TRANSPARENT_COLOR; -+ grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { -- frame[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); -+ grid[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); - } - } - } -- return frame; -+ return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** -diff --git a/js/utils/Serializer.js b/js/utils/Serializer.js -index d103ad7..5841e6b 100644 ---- a/js/utils/Serializer.js -+++ b/js/utils/Serializer.js -@@ -30,38 +30,6 @@ - }); - }, - -- deserializeLayer : function (layerString) { -- var layerData = JSON.parse(layerString); -- var layer = new pskl.model.Layer(layerData.name); -- // TODO : nasty trick to keep the whole loading process lazily synchronous -- // 1 - adding a fake frame so that the rendering can start -- layer.addFrame(new pskl.model.Frame(32,32)); -- -- // 2 - create an image to load the base64PNG representing the layer -- var base64PNG = layerData.base64PNG; -- var image = new Image(); -- -- // 3 - attach the onload callback that will be triggered asynchronously -- image.onload = function () { -- // 6 - remove the fake frame -- layer.removeFrameAt(0); -- -- // 7 - extract the frames from the loaded image -- var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); -- -- // 8 - add each image to the layer -- frames.forEach(function (frame) { -- layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); -- }); -- }; -- -- // 4 - set the source of the image -- image.src = base64PNG; -- -- // 5 - return a pointer to the new layer instance, which at this point contains a fake frame -- return layer; -- }, -- - backwardDeserializer_v1 : function (data) { - var piskelData = data.piskel; - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); -@@ -93,16 +61,12 @@ - /** - * Deserialize old piskel framesheets. Initially piskels were stored as arrays of frames : "[[pixelGrid],[pixelGrid],[pixelGrid]]". - */ -- backwardDeserializer_ : function (frames) { -- var layer = new pskl.model.Layer('Layer 1'); -- frames.forEach(function (frame) { -- layer.addFrame(pskl.model.Frame.fromPixelGrid(frame)); -+ backwardDeserializer_ : function (pixelGrids) { -+ var frames = pixelGrids.map(function (grid) { -+ return pskl.model.Frame.fromPixelGrid(grid); - }); -- var width = layer.getFrameAt(0).getWidth(), height = layer.getFrameAt(0).getHeight(); -- var piskel = new pskl.model.Piskel(width, height); -- piskel.addLayer(layer); -- -- return piskel; -+ var layer = pskl.model.Layer.fromFrames('Layer 1', frames); -+ return pskl.model.Piskel.fromLayers([layer]); - } - }; - })(); diff --git a/js/app.js b/js/app.js index 236063b0..b8a739e2 100644 --- a/js/app.js +++ b/js/app.js @@ -93,11 +93,10 @@ finishInitAppEngine_ : function () { if (pskl.framesheetData_ && pskl.framesheetData_.content) { - var deserializer = new pskl.utils.Deserializer(pskl.framesheetData_.content, function (piskel) { + pskl.utils.serialization.Deserializer.deserialize(pskl.framesheetData_.content, function (piskel) { pskl.app.piskelController.setPiskel(piskel); pskl.app.animationController.setFPS(pskl.framesheetData_.fps); }); - deserializer.deserialize(); } }, @@ -158,12 +157,11 @@ xhr.responseType = 'text'; xhr.onload = function (e) { var res = JSON.parse(this.responseText); - var deserializer = new pskl.utils.Deserializer(res.framesheet, function (piskel) { + pskl.utils.serialization.Deserializer.deserialize(res.framesheet, function (piskel) { pskl.app.piskelController.setPiskel(piskel); pskl.app.animationController.setFPS(res.fps); $.publish(Events.HIDE_NOTIFICATION); }); - deserializer.deserialize(); }; xhr.onerror = function () { diff --git a/js/service/LocalStorageService.js b/js/service/LocalStorageService.js index 7f4d9ed8..783211c3 100644 --- a/js/service/LocalStorageService.js +++ b/js/service/LocalStorageService.js @@ -45,10 +45,9 @@ */ ns.LocalStorageService.prototype.restoreFromLocalStorage_ = function() { var framesheet = JSON.parse(window.localStorage.snapShot); - var deserializer = new pskl.utils.Deserializer(framesheet, function (piskel) { + pskl.utils.serialization.Deserializer.deserialize(framesheet, function (piskel) { pskl.app.piskelController.setPiskel(piskel); }); - deserializer.deserialize(); }; /** diff --git a/js/utils/Serializer.js b/js/utils/Serializer.js deleted file mode 100644 index cab86bc4..00000000 --- a/js/utils/Serializer.js +++ /dev/null @@ -1,72 +0,0 @@ -(function () { - var ns = $.namespace('pskl.utils'); - - var layersToLoad = 0; - - 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 - }); - }, - - backwardDeserializer_v1 : function (data) { - var piskelData = data.piskel; - var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); - - piskelData.layers.forEach(function (serializedLayer) { - var layer = pskl.utils.Serializer.deserializeLayer_v1(serializedLayer); - piskel.addLayer(layer); - }); - - return piskel; - }, - - deserializeLayer_v1 : function (layerString) { - var layerData = JSON.parse(layerString); - var layer = new pskl.model.Layer(layerData.name); - layerData.frames.forEach(function (serializedFrame) { - var frame = pskl.utils.Serializer.deserializeFrame_v1(serializedFrame); - layer.addFrame(frame); - }); - - return layer; - }, - - deserializeFrame_v1 : function (frameString) { - var framePixelGrid = JSON.parse(frameString); - return pskl.model.Frame.fromPixelGrid(framePixelGrid); - }, - - /** - * Deserialize old piskel framesheets. Initially piskels were stored as arrays of pixelGrids : "[[pixelGrid],[pixelGrid],[pixelGrid]]". - */ - backwardDeserializer_ : function (pixelGrids) { - var frames = pixelGrids.map(function (grid) { - return pskl.model.Frame.fromPixelGrid(grid); - }); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - return pskl.model.Piskel.fromLayers([layer]); - } - }; -})(); diff --git a/js/utils/Deserializer.js b/js/utils/serialization/Deserializer.js similarity index 66% rename from js/utils/Deserializer.js rename to js/utils/serialization/Deserializer.js index 56f64e4f..118538c6 100644 --- a/js/utils/Deserializer.js +++ b/js/utils/serialization/Deserializer.js @@ -1,5 +1,5 @@ (function () { - var ns = $.namespace('pskl.utils'); + var ns = $.namespace('pskl.utils.serialization'); ns.Deserializer = function (data, callback) { this.layersToLoad_ = 0; @@ -8,23 +8,29 @@ 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 () { var data = this.data_; - if (data.modelVersion == Constants.MODEL_VERSION) { - var piskelData = data.piskel; - this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height); + var piskelData = data.piskel; + this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height); - this.layersToLoad_ = piskelData.layers.length; + this.layersToLoad_ = piskelData.layers.length; - piskelData.layers.forEach(function (serializedLayer) { - var layer = this.deserializeLayer(serializedLayer); - this.piskel_.addLayer(layer); - }.bind(this)); - } else if (data.modelVersion == 1) { - this.callback_(pskl.utils.Serializer.backwardDeserializer_v1(data)); - } else { - this.callback_(pskl.utils.Serializer.backwardDeserializer_(data)); - } + piskelData.layers.forEach(function (serializedLayer) { + var layer = this.deserializeLayer(serializedLayer); + this.piskel_.addLayer(layer); + }.bind(this)); }; ns.Deserializer.prototype.deserializeLayer = function (layerString) { diff --git a/js/utils/serialization/Serializer.js b/js/utils/serialization/Serializer.js new file mode 100644 index 00000000..934de4b4 --- /dev/null +++ b/js/utils/serialization/Serializer.js @@ -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 + }); + } + }; +})(); diff --git a/js/utils/serialization/backward/Deserializer_v0.js b/js/utils/serialization/backward/Deserializer_v0.js new file mode 100644 index 00000000..c976acb8 --- /dev/null +++ b/js/utils/serialization/backward/Deserializer_v0.js @@ -0,0 +1,18 @@ +(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 layer = pskl.model.Layer.fromFrames('Layer 1', frames); + + this.callback_(pskl.model.Piskel.fromLayers([layer])); + }; +})(); \ No newline at end of file diff --git a/js/utils/serialization/backward/Deserializer_v1.js b/js/utils/serialization/backward/Deserializer_v1.js new file mode 100644 index 00000000..92b05741 --- /dev/null +++ b/js/utils/serialization/backward/Deserializer_v1.js @@ -0,0 +1,36 @@ +(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 piskel = new pskl.model.Piskel(piskelData.width, piskelData.height); + + 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); + }; +})(); \ No newline at end of file diff --git a/piskel-script-list.js b/piskel-script-list.js index f4a02c4d..562de48f 100644 --- a/piskel-script-list.js +++ b/piskel-script-list.js @@ -19,10 +19,12 @@ exports.scripts = [ "js/utils/LayerUtils.js", "js/utils/ImageResizer.js", "js/utils/PixelUtils.js", - "js/utils/Deserializer.js", - "js/utils/Serializer.js", "js/utils/Template.js", "js/utils/UserSettings.js", + "js/utils/serialization/Serializer.js", + "js/utils/serialization/Deserializer.js", + "js/utils/serialization/backward/Deserializer_v0.js", + "js/utils/serialization/backward/Deserializer_v1.js", "js/lib/jsColor_1_4_0/jscolor.js", // Application libraries--> From 3de3c3542e9c9478f176c0fadc1271260bf13fd1 Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 23 Nov 2013 19:33:00 +0100 Subject: [PATCH 7/7] Post merge fixes --- js/service/LocalStorageService.js | 5 ----- piskel-script-list.js | 1 - 2 files changed, 6 deletions(-) diff --git a/js/service/LocalStorageService.js b/js/service/LocalStorageService.js index 4fb92114..783211c3 100644 --- a/js/service/LocalStorageService.js +++ b/js/service/LocalStorageService.js @@ -45,14 +45,9 @@ */ ns.LocalStorageService.prototype.restoreFromLocalStorage_ = function() { var framesheet = JSON.parse(window.localStorage.snapShot); -<<<<<<< HEAD pskl.utils.serialization.Deserializer.deserialize(framesheet, function (piskel) { pskl.app.piskelController.setPiskel(piskel); }); -======= - var piskel = pskl.utils.Serializer.createPiskel(framesheet); - pskl.app.piskelController.setPiskel(piskel); ->>>>>>> master }; /** diff --git a/piskel-script-list.js b/piskel-script-list.js index 63c45f9e..9234465c 100644 --- a/piskel-script-list.js +++ b/piskel-script-list.js @@ -50,7 +50,6 @@ exports.scripts = [ "js/rendering/frame/FrameRenderer.js", "js/rendering/frame/CachedFrameRenderer.js", "js/rendering/CanvasRenderer.js", - "js/rendering/FrameRenderer.js", "js/rendering/FramesheetRenderer.js", "js/rendering/PiskelRenderer.js",