move arraybuffer serializer to dedicated subfolder

This commit is contained in:
Julian Descottes 2016-10-16 18:28:12 +02:00
parent 2a7957bce2
commit 73986c4e61
17 changed files with 392 additions and 422 deletions

View File

@ -7,7 +7,7 @@ var Constants = {
LAYER_OPACITY : 0.2 LAYER_OPACITY : 0.2
}, },
MODEL_VERSION : 3, MODEL_VERSION : 2,
MAX_HEIGHT : 1024, MAX_HEIGHT : 1024,
MAX_WIDTH : 1024, MAX_WIDTH : 1024,

View File

@ -279,6 +279,6 @@
}; };
ns.PiskelController.prototype.serialize = function () { ns.PiskelController.prototype.serialize = function () {
return pskl.utils.Serializer.serializePiskel(this.piskel); return pskl.utils.serialization.Serializer.serialize(this.piskel);
}; };
})(); })();

View File

@ -34,7 +34,7 @@
// Do not save an unchanged piskel // Do not save an unchanged piskel
if (hash !== this.lastHash) { if (hash !== this.lastHash) {
this.lastHash = hash; this.lastHash = hash;
var serializedPiskel = pskl.utils.StringSerializer.serializePiskel(piskel); var serializedPiskel = pskl.utils.serialization.Serializer.serialize(piskel);
this.savePiskel_('next', serializedPiskel, JSON.stringify(info)); this.savePiskel_('next', serializedPiskel, JSON.stringify(info));
} }
}; };

View File

@ -1,10 +1,11 @@
(function () { (function () {
var ns = $.namespace('pskl.service'); var ns = $.namespace('pskl.service');
ns.HistoryService = function (piskelController, shortcutService, deserializer) { ns.HistoryService = function (piskelController, shortcutService, deserializer, serializer) {
this.piskelController = piskelController || pskl.app.piskelController; this.piskelController = piskelController || pskl.app.piskelController;
this.shortcutService = shortcutService || pskl.app.shortcutService; this.shortcutService = shortcutService || pskl.app.shortcutService;
this.deserializer = deserializer || pskl.utils.serialization.Deserializer; this.deserializer = deserializer || pskl.utils.serialization.arraybuffer.ArrayBufferDeserializer;
this.serializer = serializer || pskl.utils.serialization.arraybuffer.ArrayBufferSerializer;
this.stateQueue = []; this.stateQueue = [];
this.currentIndex = -1; this.currentIndex = -1;
@ -53,7 +54,8 @@
var isSnapshot = action.type === ns.HistoryService.SNAPSHOT; var isSnapshot = action.type === ns.HistoryService.SNAPSHOT;
var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0; var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0;
if (isSnapshot || isAtAutoSnapshotInterval) { if (isSnapshot || isAtAutoSnapshotInterval) {
state.piskel = this.piskelController.serialize(); var piskel = this.piskelController.getPiskel();
state.piskel = this.serializer.serialize(piskel);
} }
this.stateQueue.push(state); this.stateQueue.push(state);

View File

@ -24,7 +24,7 @@
return Q.reject('Invalid file name'); return Q.reject('Invalid file name');
} }
var serialized = pskl.utils.StringSerializer.serializePiskel(piskel); var serialized = pskl.utils.serialization.Serializer.serialize(piskel);
savePath = this.addExtensionIfNeeded_(savePath); savePath = this.addExtensionIfNeeded_(savePath);
piskel.savePath = savePath; piskel.savePath = savePath;
piskel.setName(this.extractFilename_(savePath)); piskel.setName(this.extractFilename_(savePath));

View File

@ -5,7 +5,7 @@
ns.FileDownloadStorageService.prototype.init = function () {}; ns.FileDownloadStorageService.prototype.init = function () {};
ns.FileDownloadStorageService.prototype.save = function (piskel) { ns.FileDownloadStorageService.prototype.save = function (piskel) {
var serialized = pskl.utils.StringSerializer.serializePiskel(piskel, false); var serialized = pskl.utils.serialization.Serializer.serialize(piskel);
var deferred = Q.defer(); var deferred = Q.defer();
pskl.utils.BlobUtils.stringToBlob(serialized, function(blob) { pskl.utils.BlobUtils.stringToBlob(serialized, function(blob) {

View File

@ -11,7 +11,7 @@
var descriptor = piskel.getDescriptor(); var descriptor = piskel.getDescriptor();
var deferred = Q.defer(); var deferred = Q.defer();
var serialized = pskl.utils.StringSerializer.serializePiskel(piskel); var serialized = pskl.utils.serialization.Serializer.serialize(piskel);
var data = { var data = {
framesheet : serialized, framesheet : serialized,

View File

@ -14,7 +14,7 @@
var name = piskel.getDescriptor().name; var name = piskel.getDescriptor().name;
var description = piskel.getDescriptor().description; var description = piskel.getDescriptor().description;
var serialized = pskl.utils.StringSerializer.serializePiskel(piskel); var serialized = pskl.utils.serialization.Serializer.serialize(piskel);
if (pskl.app.localStorageService.getPiskel(name)) { if (pskl.app.localStorageService.getPiskel(name)) {
var confirmOverwrite = window.confirm('There is already a piskel saved as ' + name + '. Overwrite ?'); var confirmOverwrite = window.confirm('There is already a piskel saved as ' + name + '. Overwrite ?');
if (!confirmOverwrite) { if (!confirmOverwrite) {

View File

@ -2,43 +2,18 @@
var ns = $.namespace('pskl.utils.serialization'); var ns = $.namespace('pskl.utils.serialization');
ns.Deserializer = function (data, callback) { ns.Deserializer = function (data, callback) {
this.layersToLoad_ = 0;
this.data_ = data; this.data_ = data;
this.callback_ = callback; this.callback_ = callback;
this.piskel_ = null;
this.layers_ = [];
}; };
ns.Deserializer.deserialize = function (data, callback) { ns.Deserializer.deserialize = function (data, callback) {
var modelVersion;
var isJSON = false;
if (data instanceof ArrayBuffer || data instanceof Array) {
var uint8 = new Uint8Array(data);
// Backward compatibility for modelVersion < 3 for LocalStorage, FileImport etc... which
// now always serve the serialized sprites as strings and no longer as objects
if (String.fromCharCode(uint8[0]) == '{') {
data = '';
for (var i = 0 ; i < uint8.length ; i++) {
data += String.fromCharCode(uint8[i]);
}
data = JSON.parse(data);
modelVersion = data.modelVersion;
} else {
var arr16 = new Uint16Array(uint8.buffer);
modelVersion = arr16[0];
}
} else if (typeof data == 'object') {
// Backward Compatibility for sprites served from piskelapp.com with modelVersion < 3
modelVersion = data.modelVersion;
} else {
throw 'Invalid data for deserializing: ' + data;
}
var deserializer; var deserializer;
if (modelVersion == Constants.MODEL_VERSION) { if (data.modelVersion == Constants.MODEL_VERSION) {
deserializer = new ns.Deserializer(data, callback); deserializer = new ns.Deserializer(data, callback);
} else if (modelVersion == 2) { } else if (data.modelVersion == 1) {
deserializer = new ns.backward.Deserializer_v2(data, callback);
} else if (modelVersion == 1) {
deserializer = new ns.backward.Deserializer_v1(data, callback); deserializer = new ns.backward.Deserializer_v1(data, callback);
} else { } else {
deserializer = new ns.backward.Deserializer_v0(data, callback); deserializer = new ns.backward.Deserializer_v0(data, callback);
@ -47,110 +22,70 @@
}; };
ns.Deserializer.prototype.deserialize = function () { ns.Deserializer.prototype.deserialize = function () {
var i; var data = this.data_;
var j; var piskelData = data.piskel;
var buffer = this.data_; var name = piskelData.name || 'Deserialized piskel';
var arr8 = new Uint8Array(buffer); var description = piskelData.description || '';
var arr16 = new Uint16Array(arr8.buffer);
var sub;
/********/ var descriptor = new pskl.model.piskel.Descriptor(name, description);
/* META */ this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor);
/********/
// Piskel meta
var modelVersion = arr16[0];
var width = arr16[1];
var height = arr16[2];
var fps = arr16[3];
// Descriptor meta this.layersToLoad_ = piskelData.layers.length;
var descriptorNameLength = arr16[4]; if (piskelData.expanded) {
var descriptorDescriptionLength = arr16[5]; piskelData.layers.forEach(this.loadExpandedLayer.bind(this));
} else {
// Layers meta piskelData.layers.forEach(this.deserializeLayer.bind(this));
var layerCount = arr16[6];
/********/
/* DATA */
/********/
// Descriptor name
var descriptorName = '';
for (i = 0; i < descriptorNameLength; i++) {
descriptorName += String.fromCharCode(arr16[7 + i]);
} }
};
// Descriptor description ns.Deserializer.prototype.deserializeLayer = function (layerString, index) {
var descriptorDescription = ''; var layerData = JSON.parse(layerString);
for (i = 0; i < descriptorDescriptionLength; i++) { var layer = new pskl.model.Layer(layerData.name);
descriptorDescription = String.fromCharCode(arr16[7 + descriptorNameLength + i]); layer.setOpacity(layerData.opacity);
}
// Layers // 1 - create an image to load the base64PNG representing the layer
var layerStartIndex = 7 + descriptorNameLength + descriptorDescriptionLength; var base64PNG = layerData.base64PNG;
var layers = []; var image = new Image();
var layer;
for (i = 0; i < layerCount; i++) {
layer = {};
var frames = [];
// Meta // 2 - attach the onload callback that will be triggered asynchronously
var layerNameLength = arr16[layerStartIndex]; image.onload = function () {
var opacity = arr16[layerStartIndex + 1] / 65535; // 5 - extract the frames from the loaded image
var frameCount = arr16[layerStartIndex + 2]; var frames = pskl.utils.LayerUtils.createFramesFromSpritesheet(image, layerData.frameCount);
var dataUriLengthFirstHalf = arr16[layerStartIndex + 3]; // 6 - add each image to the layer
var dataUriLengthSecondHalf = arr16[layerStartIndex + 4]; this.addFramesToLayer(frames, layer, index);
var dataUriLength = (dataUriLengthSecondHalf >>> 0) | (dataUriLengthFirstHalf << 16 >>> 0); }.bind(this);
// Name // 3 - set the source of the image
var layerName = ''; image.src = base64PNG;
for (j = 0; j < layerNameLength; j++) { return layer;
layerName += String.fromCharCode(arr16[layerStartIndex + 5 + j]); };
}
// Data URI ns.Deserializer.prototype.loadExpandedLayer = function (layerData, index) {
var dataUri = ''; var width = this.piskel_.getWidth();
for (j = 0; j < dataUriLength; j++) { var height = this.piskel_.getHeight();
dataUri += String.fromCharCode(arr8[(layerStartIndex + 5 + layerNameLength) * 2 + j]); var layer = new pskl.model.Layer(layerData.name);
} layer.setOpacity(layerData.opacity);
dataUri = 'data:image/png;base64,' + dataUri; var frames = layerData.grids.map(function (grid) {
return pskl.model.Frame.fromPixelGrid(grid, width, height);
});
this.addFramesToLayer(frames, layer, index);
return layer;
};
layerStartIndex += Math.ceil(5 + layerNameLength + (dataUriLength / 2)); ns.Deserializer.prototype.addFramesToLayer = function (frames, layer, index) {
frames.forEach(layer.addFrame.bind(layer));
layer.name = layerName; this.layers_[index] = layer;
layer.opacity = opacity; this.onLayerLoaded_();
layer.frameCount = frameCount; };
layer.dataUri = dataUri;
layers.push(layer);
}
var descriptor = new pskl.model.piskel.Descriptor(descriptorName, descriptorDescription); ns.Deserializer.prototype.onLayerLoaded_ = function () {
var piskel = new pskl.model.Piskel(width, height, descriptor); this.layersToLoad_ = this.layersToLoad_ - 1;
var loadedLayers = 0; if (this.layersToLoad_ === 0) {
this.layers_.forEach(function (layer) {
var loadLayerImage = function(layer, cb) { this.piskel_.addLayer(layer);
var image = new Image(); }.bind(this));
image.onload = function() { this.callback_(this.piskel_, {fps: this.data_.piskel.fps});
var frames = pskl.utils.LayerUtils.createFramesFromSpritesheet(this, layer.frameCount);
frames.forEach(function (frame) {
layer.model.addFrame(frame);
});
loadedLayers++;
if (loadedLayers == layerCount) {
cb(piskel, {fps: fps});
}
};
image.src = layer.dataUri;
};
for (i = 0; i < layerCount; i++) {
layer = layers[i];
var nlayer = new pskl.model.Layer(layer.name);
layer.model = nlayer;
nlayer.setOpacity(layer.opacity);
piskel.addLayer(nlayer);
loadLayerImage.bind(this, layer, this.callback_)();
} }
}; };
})(); })();

View File

@ -1,175 +1,34 @@
(function () { (function () {
var ns = $.namespace('pskl.utils'); var ns = $.namespace('pskl.utils.serialization');
/**
*********
* META *
*********
* // Piskel
* [0] = model version
* [1] = width
* [2] = height
* [3] = fps
*
* // Descriptor
* [4] = name length
* [5] = description length
*
* // Layers
* [6] = layers count
* [layer data index start] = layer name length
* [layer data index start + 1] = opacity
* [layer data index start + 2] = frame count
* [layer data index start + 3] = base 64 png data url length (upper 16 bits)
* [layer data index start + 4] = base 64 png data url length (lower 16 bits)
*
*********
* DATA *
*********
* [7..name length-1] = name
* [name length..description length-1] = description
* [layer data index start + 4..layer name length-1] = layer name
* [layer name length..base 64 png data url length-1] = base 64 png data url
*
*/
ns.Serializer = { ns.Serializer = {
calculateRequiredBytes : function(piskel, framesData) { serialize : function (piskel) {
var width = piskel.getWidth(); var serializedLayers = piskel.getLayers().map(function (l) {
var height = piskel.getHeight(); return pskl.utils.serialization.Serializer.serializeLayer(l);
var descriptorNameLength = piskel.getDescriptor().name.length; });
var descriptorDescriptionLength = piskel.getDescriptor().description.length; return JSON.stringify({
var layersLength = piskel.getLayers().length; modelVersion : Constants.MODEL_VERSION,
piskel : {
var bytes = 0; name : piskel.getDescriptor().name,
description : piskel.getDescriptor().description,
/********/ fps : pskl.app.piskelController.getFPS(),
/* META */ height : piskel.getHeight(),
/********/ width : piskel.getWidth(),
// Piskel meta layers : serializedLayers
bytes += 4 * 2;
// Descriptor meta
bytes += 2 * 2;
// Layers meta
bytes += 1 * 2;
/********/
/* DATA */
/********/
// Descriptor name
bytes += descriptorNameLength * 2;
// Descriptor description
bytes += descriptorDescriptionLength * 2;
// Layers
for (var i = 0, layers = piskel.getLayers(); i < layers.length; i++) {
bytes += 5 * 2;
bytes += layers[i].name.length * 2;
bytes += framesData[i].length;
if (bytes % 2 == 1) {
bytes++;
} }
} });
return bytes;
}, },
serializePiskel : function (piskel, expanded) { serializeLayer : function (layer) {
var i; var frames = layer.getFrames();
var j; var layerToSerialize = {
var layers; name : layer.getName(),
var dataUri; opacity : layer.getOpacity(),
var dataUriLength; frameCount : frames.length
};
// Render frames var renderer = new pskl.rendering.FramesheetRenderer(frames);
var framesData = []; layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL();
for (i = 0, layers = piskel.getLayers(); i < layers.length; i++) { return JSON.stringify(layerToSerialize);
var renderer = new pskl.rendering.FramesheetRenderer(layers[i].getFrames());
dataUri = renderer.renderAsCanvas().toDataURL().split(',')[1];
dataUriLength = dataUri.length;
framesData.push({uri: dataUri, length: dataUriLength});
}
var bytes = pskl.utils.Serializer.calculateRequiredBytes(piskel, framesData);
var buffer = new ArrayBuffer(bytes);
var arr8 = new Uint8Array(buffer);
var arr16 = new Uint16Array(buffer);
var width = piskel.getWidth();
var height = piskel.getHeight();
var descriptorName = piskel.getDescriptor().name;
var descriptorNameLength = descriptorName.length;
var descriptorDescription = piskel.getDescriptor().description;
var descriptorDescriptionLength = descriptorDescription.length;
/********/
/* META */
/********/
// Piskel meta
arr16[0] = Constants.MODEL_VERSION;
arr16[1] = width;
arr16[2] = height;
arr16[3] = pskl.app.piskelController.getFPS();
// Descriptor meta
arr16[4] = descriptorNameLength;
arr16[5] = descriptorDescriptionLength;
// Layers meta
arr16[6] = piskel.getLayers().length;
/********/
/* DATA */
/********/
// Descriptor name
for (i = 0; i < descriptorNameLength; i++) {
arr16[7 + i] = descriptorName.charCodeAt(i);
}
// Descriptor description
for (i = 0; i < descriptorDescriptionLength; i++) {
arr16[7 + descriptorNameLength + i] = descriptorDescription.charCodeAt(i);
}
// Layers
var layerStartIndex = 7 + descriptorNameLength + descriptorDescriptionLength;
for (i = 0, layers = piskel.getLayers(); i < layers.length; i++) {
var layer = layers[i];
var frames = layer.getFrames();
var layerName = layer.getName();
var layerNameLength = layerName.length;
var opacity = layer.getOpacity();
var frameCount = frames.length;
dataUri = framesData[i].uri;
dataUriLength = framesData[i].length;
// Meta
arr16[layerStartIndex] = layerNameLength;
arr16[layerStartIndex + 1] = Math.floor(opacity * 65535);
arr16[layerStartIndex + 2] = frameCount;
arr16[layerStartIndex + 3] = ((dataUriLength & 0xffff0000) >> 16) >>> 0; // Upper 16
arr16[layerStartIndex + 4] = ((dataUriLength & 0x0000ffff)) >>> 0; // Lower 16
// Name
for (j = 0; j < layerNameLength; j++) {
arr16[layerStartIndex + 5 + j] = layerName.charCodeAt(j);
}
// Data URI
for (j = 0; j < dataUriLength; j++) {
arr8[(layerStartIndex + 5 + layerNameLength) * 2 + j] = dataUri.charCodeAt(j);
}
layerStartIndex += Math.ceil(5 + layerNameLength + (dataUriLength / 2));
}
return buffer;
} }
}; };
})(); })();

View File

@ -1,34 +0,0 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.StringSerializer = {
serializePiskel : function (piskel) {
var serializedLayers = piskel.getLayers().map(function (l) {
return pskl.utils.StringSerializer.serializeLayer(l);
});
return JSON.stringify({
modelVersion : 2,
piskel : {
name : piskel.getDescriptor().name,
description : piskel.getDescriptor().description,
fps : pskl.app.piskelController.getFPS(),
height : piskel.getHeight(),
width : piskel.getWidth(),
layers : serializedLayers
}
});
},
serializeLayer : function (layer) {
var frames = layer.getFrames();
var layerToSerialize = {
name : layer.getName(),
opacity : layer.getOpacity(),
frameCount : frames.length
};
var renderer = new pskl.rendering.FramesheetRenderer(frames);
layerToSerialize.base64PNG = renderer.renderAsCanvas().toDataURL();
return JSON.stringify(layerToSerialize);
}
};
})();

View File

@ -0,0 +1,113 @@
(function () {
var ns = $.namespace('pskl.utils.serialization.arraybuffer');
ns.ArrayBufferDeserializer = {
deserialize : function (data, callback) {
var i;
var j;
var buffer = data;
var arr8 = new Uint8Array(buffer);
var arr16 = new Uint16Array(arr8.buffer);
var sub;
/********/
/* META */
/********/
// Piskel meta
var modelVersion = arr16[0];
var width = arr16[1];
var height = arr16[2];
var fps = arr16[3];
// Descriptor meta
var descriptorNameLength = arr16[4];
var descriptorDescriptionLength = arr16[5];
// Layers meta
var layerCount = arr16[6];
/********/
/* DATA */
/********/
// Descriptor name
var descriptorName = '';
for (i = 0; i < descriptorNameLength; i++) {
descriptorName += String.fromCharCode(arr16[7 + i]);
}
// Descriptor description
var descriptorDescription = '';
for (i = 0; i < descriptorDescriptionLength; i++) {
descriptorDescription = String.fromCharCode(arr16[7 + descriptorNameLength + i]);
}
// Layers
var layerStartIndex = 7 + descriptorNameLength + descriptorDescriptionLength;
var layers = [];
var layer;
for (i = 0; i < layerCount; i++) {
layer = {};
var frames = [];
// Meta
var layerNameLength = arr16[layerStartIndex];
var opacity = arr16[layerStartIndex + 1] / 65535;
var frameCount = arr16[layerStartIndex + 2];
var dataUriLengthFirstHalf = arr16[layerStartIndex + 3];
var dataUriLengthSecondHalf = arr16[layerStartIndex + 4];
var dataUriLength = (dataUriLengthSecondHalf >>> 0) | (dataUriLengthFirstHalf << 16 >>> 0);
// Name
var layerName = '';
for (j = 0; j < layerNameLength; j++) {
layerName += String.fromCharCode(arr16[layerStartIndex + 5 + j]);
}
// Data URI
var dataUri = '';
for (j = 0; j < dataUriLength; j++) {
dataUri += String.fromCharCode(arr8[(layerStartIndex + 5 + layerNameLength) * 2 + j]);
}
dataUri = 'data:image/png;base64,' + dataUri;
layerStartIndex += Math.ceil(5 + layerNameLength + (dataUriLength / 2));
layer.name = layerName;
layer.opacity = opacity;
layer.frameCount = frameCount;
layer.dataUri = dataUri;
layers.push(layer);
}
var descriptor = new pskl.model.piskel.Descriptor(descriptorName, descriptorDescription);
var piskel = new pskl.model.Piskel(width, height, descriptor);
var loadedLayers = 0;
var loadLayerImage = function(layer, cb) {
var image = new Image();
image.onload = function() {
var frames = pskl.utils.LayerUtils.createFramesFromSpritesheet(this, layer.frameCount);
frames.forEach(function (frame) {
layer.model.addFrame(frame);
});
loadedLayers++;
if (loadedLayers == layerCount) {
cb(piskel, {fps: fps});
}
};
image.src = layer.dataUri;
};
for (i = 0; i < layerCount; i++) {
layer = layers[i];
var nlayer = new pskl.model.Layer(layer.name);
layer.model = nlayer;
nlayer.setOpacity(layer.opacity);
piskel.addLayer(nlayer);
loadLayerImage.bind(this, layer, callback)();
}
}
};
})();

View File

@ -0,0 +1,175 @@
(function () {
var ns = $.namespace('pskl.utils.serialization.arraybuffer');
/**
*********
* META *
*********
* // Piskel
* [0] = model version
* [1] = width
* [2] = height
* [3] = fps
*
* // Descriptor
* [4] = name length
* [5] = description length
*
* // Layers
* [6] = layers count
* [layer data index start] = layer name length
* [layer data index start + 1] = opacity
* [layer data index start + 2] = frame count
* [layer data index start + 3] = base 64 png data url length (upper 16 bits)
* [layer data index start + 4] = base 64 png data url length (lower 16 bits)
*
*********
* DATA *
*********
* [7..name length-1] = name
* [name length..description length-1] = description
* [layer data index start + 4..layer name length-1] = layer name
* [layer name length..base 64 png data url length-1] = base 64 png data url
*
*/
ns.ArrayBufferSerializer = {
calculateRequiredBytes : function(piskel, framesData) {
var width = piskel.getWidth();
var height = piskel.getHeight();
var descriptorNameLength = piskel.getDescriptor().name.length;
var descriptorDescriptionLength = piskel.getDescriptor().description.length;
var layersLength = piskel.getLayers().length;
var bytes = 0;
/********/
/* META */
/********/
// Piskel meta
bytes += 4 * 2;
// Descriptor meta
bytes += 2 * 2;
// Layers meta
bytes += 1 * 2;
/********/
/* DATA */
/********/
// Descriptor name
bytes += descriptorNameLength * 2;
// Descriptor description
bytes += descriptorDescriptionLength * 2;
// Layers
for (var i = 0, layers = piskel.getLayers(); i < layers.length; i++) {
bytes += 5 * 2;
bytes += layers[i].name.length * 2;
bytes += framesData[i].length;
if (bytes % 2 == 1) {
bytes++;
}
}
return bytes;
},
serialize : function (piskel, expanded) {
var i;
var j;
var layers;
var dataUri;
var dataUriLength;
// Render frames
var framesData = [];
for (i = 0, layers = piskel.getLayers(); i < layers.length; i++) {
var renderer = new pskl.rendering.FramesheetRenderer(layers[i].getFrames());
dataUri = renderer.renderAsCanvas().toDataURL().split(',')[1];
dataUriLength = dataUri.length;
framesData.push({uri: dataUri, length: dataUriLength});
}
var bytes = ns.ArrayBufferSerializer.calculateRequiredBytes(piskel, framesData);
var buffer = new ArrayBuffer(bytes);
var arr8 = new Uint8Array(buffer);
var arr16 = new Uint16Array(buffer);
var width = piskel.getWidth();
var height = piskel.getHeight();
var descriptorName = piskel.getDescriptor().name;
var descriptorNameLength = descriptorName.length;
var descriptorDescription = piskel.getDescriptor().description;
var descriptorDescriptionLength = descriptorDescription.length;
/********/
/* META */
/********/
// Piskel meta
arr16[0] = Constants.MODEL_VERSION;
arr16[1] = width;
arr16[2] = height;
arr16[3] = pskl.app.piskelController.getFPS();
// Descriptor meta
arr16[4] = descriptorNameLength;
arr16[5] = descriptorDescriptionLength;
// Layers meta
arr16[6] = piskel.getLayers().length;
/********/
/* DATA */
/********/
// Descriptor name
for (i = 0; i < descriptorNameLength; i++) {
arr16[7 + i] = descriptorName.charCodeAt(i);
}
// Descriptor description
for (i = 0; i < descriptorDescriptionLength; i++) {
arr16[7 + descriptorNameLength + i] = descriptorDescription.charCodeAt(i);
}
// Layers
var layerStartIndex = 7 + descriptorNameLength + descriptorDescriptionLength;
for (i = 0, layers = piskel.getLayers(); i < layers.length; i++) {
var layer = layers[i];
var frames = layer.getFrames();
var layerName = layer.getName();
var layerNameLength = layerName.length;
var opacity = layer.getOpacity();
var frameCount = frames.length;
dataUri = framesData[i].uri;
dataUriLength = framesData[i].length;
// Meta
arr16[layerStartIndex] = layerNameLength;
arr16[layerStartIndex + 1] = Math.floor(opacity * 65535);
arr16[layerStartIndex + 2] = frameCount;
arr16[layerStartIndex + 3] = ((dataUriLength & 0xffff0000) >> 16) >>> 0; // Upper 16
arr16[layerStartIndex + 4] = ((dataUriLength & 0x0000ffff)) >>> 0; // Lower 16
// Name
for (j = 0; j < layerNameLength; j++) {
arr16[layerStartIndex + 5 + j] = layerName.charCodeAt(j);
}
// Data URI
for (j = 0; j < dataUriLength; j++) {
arr8[(layerStartIndex + 5 + layerNameLength) * 2 + j] = dataUri.charCodeAt(j);
}
layerStartIndex += Math.ceil(5 + layerNameLength + (dataUriLength / 2));
}
return buffer;
}
};
})();

View File

@ -1,79 +0,0 @@
(function () {
var ns = $.namespace('pskl.utils.serialization.backward');
ns.Deserializer_v2 = function (data, callback) {
this.layersToLoad_ = 0;
this.data_ = data;
this.callback_ = callback;
this.piskel_ = null;
this.layers_ = [];
};
ns.Deserializer_v2.prototype.deserialize = function () {
var data = this.data_;
var piskelData = data.piskel;
var name = piskelData.name || 'Deserialized piskel';
var description = piskelData.description || '';
var descriptor = new pskl.model.piskel.Descriptor(name, description);
this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor);
this.layersToLoad_ = piskelData.layers.length;
if (piskelData.expanded) {
piskelData.layers.forEach(this.loadExpandedLayer.bind(this));
} else {
piskelData.layers.forEach(this.deserializeLayer.bind(this));
}
};
ns.Deserializer_v2.prototype.deserializeLayer = function (layerString, index) {
var layerData = JSON.parse(layerString);
var layer = new pskl.model.Layer(layerData.name);
layer.setOpacity(layerData.opacity);
// 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.createFramesFromSpritesheet(image, layerData.frameCount);
// 6 - add each image to the layer
this.addFramesToLayer(frames, layer, index);
}.bind(this);
// 3 - set the source of the image
image.src = base64PNG;
return layer;
};
ns.Deserializer_v2.prototype.loadExpandedLayer = function (layerData, index) {
var width = this.piskel_.getWidth();
var height = this.piskel_.getHeight();
var layer = new pskl.model.Layer(layerData.name);
layer.setOpacity(layerData.opacity);
var frames = layerData.grids.map(function (grid) {
return pskl.model.Frame.fromPixelGrid(grid, width, height);
});
this.addFramesToLayer(frames, layer, index);
return layer;
};
ns.Deserializer_v2.prototype.addFramesToLayer = function (frames, layer, index) {
frames.forEach(layer.addFrame.bind(layer));
this.layers_[index] = layer;
this.onLayerLoaded_();
};
ns.Deserializer_v2.prototype.onLayerLoaded_ = function () {
this.layersToLoad_ = this.layersToLoad_ - 1;
if (this.layersToLoad_ === 0) {
this.layers_.forEach(function (layer) {
this.piskel_.addLayer(layer);
}.bind(this));
this.callback_(this.piskel_, {fps: this.data_.piskel.fps});
}
};
})();

View File

@ -40,11 +40,11 @@
"js/utils/WorkerUtils.js", "js/utils/WorkerUtils.js",
"js/utils/Xhr.js", "js/utils/Xhr.js",
"js/utils/serialization/Serializer.js", "js/utils/serialization/Serializer.js",
"js/utils/serialization/StringSerializer.js",
"js/utils/serialization/Deserializer.js", "js/utils/serialization/Deserializer.js",
"js/utils/serialization/arraybuffer/ArrayBufferDeserializer.js",
"js/utils/serialization/arraybuffer/ArrayBufferSerializer.js",
"js/utils/serialization/backward/Deserializer_v0.js", "js/utils/serialization/backward/Deserializer_v0.js",
"js/utils/serialization/backward/Deserializer_v1.js", "js/utils/serialization/backward/Deserializer_v1.js",
"js/utils/serialization/backward/Deserializer_v2.js",
// GIF Encoding libraries // GIF Encoding libraries
"js/lib/gif/gif.worker.js", "js/lib/gif/gif.worker.js",

View File

@ -22,16 +22,15 @@ describe("History Service suite", function() {
}; };
var createMockHistoryService = function () { var createMockHistoryService = function () {
var mockPiskelController = { var mockPiskelController = { getPiskel : function () {} };
serialize : function () {
return SERIALIZED_PISKEL;
}
};
var mockShortcutService = { var mockShortcutService = {
registerShortcuts : function () {}, registerShortcuts : function () {},
registerShortcut : function () {} registerShortcut : function () {}
}; };
return new pskl.service.HistoryService(mockPiskelController, mockShortcutService); return new pskl.service.HistoryService(mockPiskelController, mockShortcutService,
{ deserialize : function () {}},
{ serialize : function () { return SERIALIZED_PISKEL }}
);
}; };
it("starts at -1", function() { it("starts at -1", function() {

View File

@ -28,10 +28,10 @@ describe("Serialization/Deserialization test", function() {
layer.addFrame(frame); layer.addFrame(frame);
}); });
var serializedPiskel = pskl.utils.Serializer.serializePiskel(piskel); var serializedPiskel = pskl.utils.serialization.Serializer.serialize(piskel);
var deserializer = pskl.utils.serialization.Deserializer; var deserializer = pskl.utils.serialization.Deserializer;
deserializer.deserialize(serializedPiskel, function (p) { deserializer.deserialize(JSON.parse(serializedPiskel), function (p) {
expect(p.getLayerAt(0).getOpacity()).toBe(0); expect(p.getLayerAt(0).getOpacity()).toBe(0);
expect(p.getLayerAt(1).getOpacity()).toBe(0.3); expect(p.getLayerAt(1).getOpacity()).toBe(0.3);
expect(p.getLayerAt(2).getOpacity()).toBe(0.9); expect(p.getLayerAt(2).getOpacity()).toBe(0.9);