mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
move arraybuffer serializer to dedicated subfolder
This commit is contained in:
parent
2a7957bce2
commit
73986c4e61
@ -7,7 +7,7 @@ var Constants = {
|
||||
LAYER_OPACITY : 0.2
|
||||
},
|
||||
|
||||
MODEL_VERSION : 3,
|
||||
MODEL_VERSION : 2,
|
||||
|
||||
MAX_HEIGHT : 1024,
|
||||
MAX_WIDTH : 1024,
|
||||
|
@ -279,6 +279,6 @@
|
||||
};
|
||||
|
||||
ns.PiskelController.prototype.serialize = function () {
|
||||
return pskl.utils.Serializer.serializePiskel(this.piskel);
|
||||
return pskl.utils.serialization.Serializer.serialize(this.piskel);
|
||||
};
|
||||
})();
|
||||
|
@ -34,7 +34,7 @@
|
||||
// Do not save an unchanged piskel
|
||||
if (hash !== this.lastHash) {
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
@ -1,10 +1,11 @@
|
||||
(function () {
|
||||
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.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.currentIndex = -1;
|
||||
@ -53,7 +54,8 @@
|
||||
var isSnapshot = action.type === ns.HistoryService.SNAPSHOT;
|
||||
var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0;
|
||||
if (isSnapshot || isAtAutoSnapshotInterval) {
|
||||
state.piskel = this.piskelController.serialize();
|
||||
var piskel = this.piskelController.getPiskel();
|
||||
state.piskel = this.serializer.serialize(piskel);
|
||||
}
|
||||
|
||||
this.stateQueue.push(state);
|
||||
|
@ -24,7 +24,7 @@
|
||||
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);
|
||||
piskel.savePath = savePath;
|
||||
piskel.setName(this.extractFilename_(savePath));
|
||||
|
@ -5,7 +5,7 @@
|
||||
ns.FileDownloadStorageService.prototype.init = function () {};
|
||||
|
||||
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();
|
||||
|
||||
pskl.utils.BlobUtils.stringToBlob(serialized, function(blob) {
|
||||
|
@ -11,7 +11,7 @@
|
||||
var descriptor = piskel.getDescriptor();
|
||||
var deferred = Q.defer();
|
||||
|
||||
var serialized = pskl.utils.StringSerializer.serializePiskel(piskel);
|
||||
var serialized = pskl.utils.serialization.Serializer.serialize(piskel);
|
||||
|
||||
var data = {
|
||||
framesheet : serialized,
|
||||
|
@ -14,7 +14,7 @@
|
||||
var name = piskel.getDescriptor().name;
|
||||
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)) {
|
||||
var confirmOverwrite = window.confirm('There is already a piskel saved as ' + name + '. Overwrite ?');
|
||||
if (!confirmOverwrite) {
|
||||
|
@ -2,43 +2,18 @@
|
||||
var ns = $.namespace('pskl.utils.serialization');
|
||||
|
||||
ns.Deserializer = function (data, callback) {
|
||||
this.layersToLoad_ = 0;
|
||||
this.data_ = data;
|
||||
this.callback_ = callback;
|
||||
this.piskel_ = null;
|
||||
this.layers_ = [];
|
||||
};
|
||||
|
||||
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;
|
||||
if (modelVersion == Constants.MODEL_VERSION) {
|
||||
if (data.modelVersion == Constants.MODEL_VERSION) {
|
||||
deserializer = new ns.Deserializer(data, callback);
|
||||
} else if (modelVersion == 2) {
|
||||
deserializer = new ns.backward.Deserializer_v2(data, callback);
|
||||
} else if (modelVersion == 1) {
|
||||
} else if (data.modelVersion == 1) {
|
||||
deserializer = new ns.backward.Deserializer_v1(data, callback);
|
||||
} else {
|
||||
deserializer = new ns.backward.Deserializer_v0(data, callback);
|
||||
@ -47,110 +22,70 @@
|
||||
};
|
||||
|
||||
ns.Deserializer.prototype.deserialize = function () {
|
||||
var i;
|
||||
var j;
|
||||
var buffer = this.data_;
|
||||
var arr8 = new Uint8Array(buffer);
|
||||
var arr16 = new Uint16Array(arr8.buffer);
|
||||
var sub;
|
||||
var data = this.data_;
|
||||
var piskelData = data.piskel;
|
||||
var name = piskelData.name || 'Deserialized piskel';
|
||||
var description = piskelData.description || '';
|
||||
|
||||
/********/
|
||||
/* META */
|
||||
/********/
|
||||
// Piskel meta
|
||||
var modelVersion = arr16[0];
|
||||
var width = arr16[1];
|
||||
var height = arr16[2];
|
||||
var fps = arr16[3];
|
||||
var descriptor = new pskl.model.piskel.Descriptor(name, description);
|
||||
this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor);
|
||||
|
||||
// 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]);
|
||||
this.layersToLoad_ = piskelData.layers.length;
|
||||
if (piskelData.expanded) {
|
||||
piskelData.layers.forEach(this.loadExpandedLayer.bind(this));
|
||||
} else {
|
||||
piskelData.layers.forEach(this.deserializeLayer.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
// Descriptor description
|
||||
var descriptorDescription = '';
|
||||
for (i = 0; i < descriptorDescriptionLength; i++) {
|
||||
descriptorDescription = String.fromCharCode(arr16[7 + descriptorNameLength + i]);
|
||||
}
|
||||
ns.Deserializer.prototype.deserializeLayer = function (layerString, index) {
|
||||
var layerData = JSON.parse(layerString);
|
||||
var layer = new pskl.model.Layer(layerData.name);
|
||||
layer.setOpacity(layerData.opacity);
|
||||
|
||||
// Layers
|
||||
var layerStartIndex = 7 + descriptorNameLength + descriptorDescriptionLength;
|
||||
var layers = [];
|
||||
var layer;
|
||||
for (i = 0; i < layerCount; i++) {
|
||||
layer = {};
|
||||
var frames = [];
|
||||
// 1 - create an image to load the base64PNG representing the layer
|
||||
var base64PNG = layerData.base64PNG;
|
||||
var image = new Image();
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
// Name
|
||||
var layerName = '';
|
||||
for (j = 0; j < layerNameLength; j++) {
|
||||
layerName += String.fromCharCode(arr16[layerStartIndex + 5 + j]);
|
||||
}
|
||||
// 3 - set the source of the image
|
||||
image.src = base64PNG;
|
||||
return layer;
|
||||
};
|
||||
|
||||
// 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;
|
||||
ns.Deserializer.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;
|
||||
};
|
||||
|
||||
layerStartIndex += Math.ceil(5 + layerNameLength + (dataUriLength / 2));
|
||||
ns.Deserializer.prototype.addFramesToLayer = function (frames, layer, index) {
|
||||
frames.forEach(layer.addFrame.bind(layer));
|
||||
|
||||
layer.name = layerName;
|
||||
layer.opacity = opacity;
|
||||
layer.frameCount = frameCount;
|
||||
layer.dataUri = dataUri;
|
||||
layers.push(layer);
|
||||
}
|
||||
this.layers_[index] = layer;
|
||||
this.onLayerLoaded_();
|
||||
};
|
||||
|
||||
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, this.callback_)();
|
||||
ns.Deserializer.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});
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -1,175 +1,34 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.utils');
|
||||
|
||||
/**
|
||||
*********
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
var ns = $.namespace('pskl.utils.serialization');
|
||||
|
||||
ns.Serializer = {
|
||||
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++;
|
||||
serialize : function (piskel) {
|
||||
var serializedLayers = piskel.getLayers().map(function (l) {
|
||||
return pskl.utils.serialization.Serializer.serializeLayer(l);
|
||||
});
|
||||
return JSON.stringify({
|
||||
modelVersion : Constants.MODEL_VERSION,
|
||||
piskel : {
|
||||
name : piskel.getDescriptor().name,
|
||||
description : piskel.getDescriptor().description,
|
||||
fps : pskl.app.piskelController.getFPS(),
|
||||
height : piskel.getHeight(),
|
||||
width : piskel.getWidth(),
|
||||
layers : serializedLayers
|
||||
}
|
||||
}
|
||||
|
||||
return bytes;
|
||||
});
|
||||
},
|
||||
|
||||
serializePiskel : 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 = 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;
|
||||
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);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
})();
|
@ -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)();
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
175
src/js/utils/serialization/arraybuffer/ArrayBufferSerializer.js
Normal file
175
src/js/utils/serialization/arraybuffer/ArrayBufferSerializer.js
Normal 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;
|
||||
}
|
||||
};
|
||||
})();
|
@ -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});
|
||||
}
|
||||
};
|
||||
})();
|
@ -40,11 +40,11 @@
|
||||
"js/utils/WorkerUtils.js",
|
||||
"js/utils/Xhr.js",
|
||||
"js/utils/serialization/Serializer.js",
|
||||
"js/utils/serialization/StringSerializer.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_v1.js",
|
||||
"js/utils/serialization/backward/Deserializer_v2.js",
|
||||
|
||||
// GIF Encoding libraries
|
||||
"js/lib/gif/gif.worker.js",
|
||||
|
@ -22,16 +22,15 @@ describe("History Service suite", function() {
|
||||
};
|
||||
|
||||
var createMockHistoryService = function () {
|
||||
var mockPiskelController = {
|
||||
serialize : function () {
|
||||
return SERIALIZED_PISKEL;
|
||||
}
|
||||
};
|
||||
var mockPiskelController = { getPiskel : function () {} };
|
||||
var mockShortcutService = {
|
||||
registerShortcuts : 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() {
|
||||
|
@ -28,10 +28,10 @@ describe("Serialization/Deserialization test", function() {
|
||||
layer.addFrame(frame);
|
||||
});
|
||||
|
||||
var serializedPiskel = pskl.utils.Serializer.serializePiskel(piskel);
|
||||
var serializedPiskel = pskl.utils.serialization.Serializer.serialize(piskel);
|
||||
|
||||
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(1).getOpacity()).toBe(0.3);
|
||||
expect(p.getLayerAt(2).getOpacity()).toBe(0.9);
|
||||
|
Loading…
Reference in New Issue
Block a user