mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
4f54715f70
- 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)
130 lines
4.2 KiB
JavaScript
130 lines
4.2 KiB
JavaScript
(function () {
|
|
var ns = $.namespace("pskl.controller.settings");
|
|
|
|
ns.GifExportController = function (piskelController) {
|
|
this.piskelController = piskelController;
|
|
};
|
|
|
|
/**
|
|
* List of Resolutions applicable for Gif export
|
|
* @static
|
|
* @type {Array} array of Objects {dpi:{Number}, default:{Boolean}}
|
|
*/
|
|
ns.GifExportController.RESOLUTIONS = [
|
|
{
|
|
'dpi' : 1
|
|
},{
|
|
'dpi' : 5
|
|
},{
|
|
'dpi' : 10,
|
|
'default' : true
|
|
},{
|
|
'dpi' : 20
|
|
}
|
|
];
|
|
|
|
ns.GifExportController.prototype.init = function () {
|
|
this.radioTemplate_ = pskl.utils.Template.get("gif-export-radio-template");
|
|
|
|
this.previewContainerEl = document.querySelectorAll(".gif-export-preview")[0];
|
|
this.radioGroupEl = document.querySelectorAll(".gif-export-radio-group")[0];
|
|
|
|
this.uploadForm = $("[name=gif-export-upload-form]");
|
|
this.uploadForm.submit(this.onUploadFormSubmit_.bind(this));
|
|
|
|
this.createRadioElements_();
|
|
};
|
|
|
|
ns.GifExportController.prototype.onUploadFormSubmit_ = function (evt) {
|
|
evt.originalEvent.preventDefault();
|
|
var selectedDpi = this.getSelectedDpi_(),
|
|
fps = this.piskelController.getFPS(),
|
|
dpi = selectedDpi;
|
|
|
|
this.renderAsImageDataAnimatedGIF(dpi, fps, this.onGifRenderingCompleted_.bind(this));
|
|
};
|
|
|
|
ns.GifExportController.prototype.onGifRenderingCompleted_ = function (imageData) {
|
|
this.updatePreview_(imageData);
|
|
this.previewContainerEl.classList.add("preview-upload-ongoing");
|
|
pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this));
|
|
};
|
|
|
|
ns.GifExportController.prototype.onImageUploadCompleted_ = function (imageUrl) {
|
|
this.updatePreview_(imageUrl);
|
|
this.previewContainerEl.classList.remove("preview-upload-ongoing");
|
|
};
|
|
|
|
ns.GifExportController.prototype.updatePreview_ = function (src) {
|
|
this.previewContainerEl.innerHTML = "<div><img style='max-width:240px;' src='"+src+"'/></div>";
|
|
};
|
|
|
|
ns.GifExportController.prototype.getSelectedDpi_ = function () {
|
|
var radiosColl = this.uploadForm.get(0).querySelectorAll("[name=gif-dpi]"),
|
|
radios = Array.prototype.slice.call(radiosColl,0);
|
|
var selectedRadios = radios.filter(function(radio) {return !!radio.checked;});
|
|
|
|
if (selectedRadios.length == 1) {
|
|
return selectedRadios[0].value;
|
|
} else {
|
|
throw "Unexpected error when retrieving selected dpi";
|
|
}
|
|
};
|
|
|
|
ns.GifExportController.prototype.createRadioElements_ = function () {
|
|
var resolutions = ns.GifExportController.RESOLUTIONS;
|
|
for (var i = 0 ; i < resolutions.length ; i++) {
|
|
var radio = this.createRadioForResolution_(resolutions[i]);
|
|
this.radioGroupEl.appendChild(radio);
|
|
}
|
|
};
|
|
|
|
ns.GifExportController.prototype.createRadioForResolution_ = function (resolution) {
|
|
var dpi = resolution.dpi;
|
|
var label = dpi*this.piskelController.getWidth() + "x" + dpi*this.piskelController.getHeight();
|
|
var value = dpi;
|
|
|
|
var radioHTML = pskl.utils.Template.replace(this.radioTemplate_, {value : value, label : label});
|
|
var radioEl = pskl.utils.Template.createFromHTML(radioHTML);
|
|
|
|
if (resolution['default']) {
|
|
var input = radioEl.getElementsByTagName("input")[0];
|
|
input.setAttribute("checked", "checked");
|
|
}
|
|
|
|
return radioEl;
|
|
};
|
|
|
|
ns.GifExportController.prototype.blobToBase64_ = function(blob, cb) {
|
|
var reader = new FileReader();
|
|
reader.onload = function() {
|
|
var dataUrl = reader.result;
|
|
cb(dataUrl);
|
|
};
|
|
reader.readAsDataURL(blob);
|
|
};
|
|
|
|
ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(dpi, fps, cb) {
|
|
var gif = new window.GIF({
|
|
workers: 2,
|
|
quality: 10,
|
|
width: this.piskelController.getWidth()*dpi,
|
|
height: this.piskelController.getHeight()*dpi
|
|
});
|
|
|
|
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
|
var frame = this.piskelController.getFrameAt(i);
|
|
var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, dpi);
|
|
var canvas = canvasRenderer.render();
|
|
gif.addFrame(canvas.getContext('2d'), {
|
|
delay: 1000 / fps
|
|
});
|
|
}
|
|
|
|
gif.on('finished', function(blob) {
|
|
this.blobToBase64_(blob, cb);
|
|
}.bind(this));
|
|
|
|
gif.render();
|
|
};
|
|
})(); |