Feature : export to ZIP

This commit is contained in:
jdescottes 2014-04-11 01:12:01 +02:00
parent d42064d2fe
commit abd5ac5959
11 changed files with 216 additions and 24 deletions

View file

@ -6,9 +6,10 @@
// Piskel externs.
var exports;
var pskl_exports;
var $;
var console;
var pskl;
var pskl;
// Piskel libs externs.
var define;

View file

@ -11,19 +11,54 @@
this.previewContainerEl = document.querySelectorAll(".png-export-preview")[0];
this.uploadStatusContainerEl = document.querySelectorAll(".png-upload-status")[0];
this.uploadForm = $("[name=png-export-upload-form]");
this.uploadForm.submit(this.onUploadFormSubmit_.bind(this));
document.querySelector(".png-upload-button").addEventListener('click', this.onPngUploadButtonClick_.bind(this));
document.querySelector(".png-download-button").addEventListener('click', this.onPngDownloadButtonClick_.bind(this));
document.querySelector(".zip-generate-button").addEventListener('click', this.onZipButtonClick_.bind(this));
this.updatePreview_(this.getFramesheetAsBase64Png());
};
ns.PngExportController.prototype.onUploadFormSubmit_ = function (evt) {
evt.originalEvent.preventDefault();
ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) {
var fileName = this.getPiskelName_() + '.png';
var renderer = new pskl.rendering.PiskelRenderer(this.piskelController);
var canvas = renderer.renderAsCanvas();
canvas.toBlob(function(blob) {
pskl.utils.FileUtils.downloadAsFile(fileName, blob);
});
};
ns.PngExportController.prototype.onPngUploadButtonClick_ = function (evt) {
this.previewContainerEl.classList.add("preview-upload-ongoing");
pskl.app.imageUploadService.upload(this.getFramesheetAsBase64Png(), this.onImageUploadCompleted_.bind(this));
};
ns.PngExportController.prototype.onZipButtonClick_ = function () {
var zip = new window.JSZip();
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
var frame = this.piskelController.getFrameAt(i);
var canvas = this.getFrameAsCanvas_(frame);
var filename = "sprite_" + (i+1) + ".png";
zip.file(filename, pskl.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
}
var fileName = this.getPiskelName_() + '.zip';
var fileContent = zip.generate({type:"blob"});
pskl.utils.FileUtils.downloadAsFile(fileName, fileContent);
};
ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) {
var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1);
canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR);
return canvasRenderer.render();
};
ns.PngExportController.prototype.getPiskelName_ = function () {
return this.piskelController.piskel.getDescriptor().name;
};
ns.PngExportController.prototype.getFramesheetAsBase64Png = function () {
var renderer = new pskl.rendering.PiskelRenderer(this.piskelController);
var framesheetCanvas = renderer.renderAsCanvas();

View file

@ -0,0 +1,107 @@
/* canvas-toBlob.js
* A canvas.toBlob() implementation.
* 2011-07-13
*
* By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr
* License: X11/MIT
* See LICENSE.md
*/
/*global self */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */
/*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */
(function(view) {
"use strict";
var
Uint8Array = view.Uint8Array
, HTMLCanvasElement = view.HTMLCanvasElement
, is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i
, base64_ranks
, decode_base64 = function(base64) {
var
len = base64.length
, buffer = new Uint8Array(len / 4 * 3 | 0)
, i = 0
, outptr = 0
, last = [0, 0]
, state = 0
, save = 0
, rank
, code
, undef
;
while (len--) {
code = base64.charCodeAt(i++);
rank = base64_ranks[code-43];
if (rank !== 255 && rank !== undef) {
last[1] = last[0];
last[0] = code;
save = (save << 6) | rank;
state++;
if (state === 4) {
buffer[outptr++] = save >>> 16;
if (last[1] !== 61 /* padding character */) {
buffer[outptr++] = save >>> 8;
}
if (last[0] !== 61 /* padding character */) {
buffer[outptr++] = save;
}
state = 0;
}
}
}
// 2/3 chance there's going to be some null bytes at the end, but that
// doesn't really matter with most image formats.
// If it somehow matters for you, truncate the buffer up outptr.
return buffer.buffer;
}
;
if (Uint8Array) {
base64_ranks = new Uint8Array([
62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1
, -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35
, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
]);
}
if (HTMLCanvasElement && !HTMLCanvasElement.prototype.toBlob) {
HTMLCanvasElement.prototype.toBlob = function(callback, type /*, ...args*/) {
if (!type) {
type = "image/png";
} if (this.mozGetAsFile) {
callback(this.mozGetAsFile("canvas", type));
return;
}
var
args = Array.prototype.slice.call(arguments, 1)
, dataURI = this.toDataURL.apply(this, args)
, header_end = dataURI.indexOf(",")
, data = dataURI.substring(header_end + 1)
, is_base64 = is_base64_regex.test(dataURI.substring(0, header_end))
, blob
;
if (Blob.fake) {
// no reason to decode a data: URI that's just going to become a data URI again
blob = new Blob
if (is_base64) {
blob.encoding = "base64";
} else {
blob.encoding = "URI";
}
blob.data = data;
blob.size = data.length;
} else if (Uint8Array) {
if (is_base64) {
blob = new Blob([decode_base64(data)], {type: type});
} else {
blob = new Blob([decodeURIComponent(data)], {type: type});
}
}
callback(blob);
};
}
}(self));

14
src/js/lib/jszip/jszip.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -44,6 +44,12 @@
getImageDataFromCanvas : function (canvas) {
var sourceContext = canvas.getContext('2d');
return sourceContext.getImageData(0, 0, canvas.width, canvas.height).data;
},
getBase64FromCanvas : function (canvas, format) {
format = format || "png";
var data = canvas.toDataURL("image/" + format);
return data.substr(data.indexOf(',')+1);
}
};
})();

View file

@ -8,6 +8,21 @@
callback(event.target.result);
};
reader.readAsDataURL(file);
},
downloadAsFile : function (filename, content) {
var saveAs = window.saveAs || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator));
if (saveAs) {
saveAs(content, filename);
} else {
var downloadLink = document.createElement('a');
content = window.URL.createObjectURL(content);
downloadLink.setAttribute('href', content);
downloadLink.setAttribute('download', filename);
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);
}
}
};
})();
})();

View file

@ -6,7 +6,7 @@
window.setTimeout(function () {loadingMask.parentNode.removeChild(loadingMask);}, 600)
pskl.app.init();
// cleanup
delete window.exports;
delete window.pskl_exports;
delete window.loadDebugScripts;
delete window.done;
};
@ -37,20 +37,20 @@
};
if (window.location.href.indexOf("debug") != -1) {
window.exports = {};
window.pskl_exports = {};
var scriptIndex = 0;
window.loadNextScript = function () {
if (scriptIndex == window.exports.scripts.length) {
if (scriptIndex == window.pskl_exports.scripts.length) {
window.onPiskelReady();
} else {
loadScript(window.exports.scripts[scriptIndex], "loadNextScript()");
loadScript(window.pskl_exports.scripts[scriptIndex], "loadNextScript()");
scriptIndex ++;
}
};
loadScript("piskel-script-list.js", "loadNextScript()");
window.loadStyles = function () {
var styles = window.exports.styles;
var styles = window.pskl_exports.styles;
for (var i = 0 ; i < styles.length ; i++) {
loadStyle(styles[i]);
}

View file

@ -1,11 +1,17 @@
// This list is used both by the grunt build and index.html (in debug mode)
exports.scripts = [
(typeof exports != "undefined" ? exports : pskl_exports).scripts = [
// Core libraries
"js/lib/jquery-1.8.0.js","js/lib/jquery-ui-1.10.3.custom.js","js/lib/pubsub.js","js/lib/bootstrap/bootstrap.js",
// GIF Encoding libraries
"js/lib/gif/gif.worker.js",
"js/lib/gif/gif.js",
// JSZip https://github.com/Stuk/jszip
"js/lib/jszip/jszip.min.js",
"js/lib/canvastoblob/canvasToBlob.js",
// Spectrum color-picker library
"js/lib/spectrum/spectrum.js",

View file

@ -1,6 +1,6 @@
// This list is used both by the grunt build and index.html (in debug mode)
exports.styles = [
(typeof exports != "undefined" ? exports : pskl_exports).styles = [
"css/reset.css",
"css/style.css",
"css/forms.css",

View file

@ -37,16 +37,16 @@
<div
data-setting="gif"
class="tool-icon upload-cloud-icon"
title="Upload as an animated GIF"
title="Export Animation"
rel="tooltip" data-placement="left">
<span class="label">GIF</span>
<span class="label">ANIM</span>
</div>
<div
data-setting="png"
class="tool-icon upload-cloud-icon"
title="Upload as a spritesheet PNG"
title="Export Spritesheet"
rel="tooltip" data-placement="left">
<span class="label">PNG</span>
<span class="label">SHEET</span>
</div>
</div>

View file

@ -1,15 +1,23 @@
<div class="settings-section">
<div class="settings-title">
Export to PNG
Export Spritesheet as PNG
</div>
<div class="settings-item">
<span>Preview : </span>
<div class="png-export-preview"></div>
<form action="" method="POST" name="png-export-upload-form">
<div class="png-export-radio-group"></div>
<input type="submit" class="button button-primary png-upload-button" value="Upload" />
<!-- <input type="button" class="button png-download-button" value="Download" /> -->
<div class="png-upload-status"></div>
</form>
<div class="png-export-radio-group"></div>
<input type="button" class="button button-primary png-download-button" value="Download PNG" />
<input type="button" class="button png-upload-button" value="Upload PNG" />
<!-- <input type="button" class="button png-download-button" value="Download" /> -->
<div class="png-upload-status"></div>
</div>
<div class="settings-title">
Export Spritesheet as ZIP
</div>
<div class="settings-item">
<span>A ZIP archive will be created with one PNG file per frame.</span>
<div style="margin-top:10px;">
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
</div>
</div>
</div>