Feature : export to ZIP
This commit is contained in:
parent
d42064d2fe
commit
abd5ac5959
11 changed files with 216 additions and 24 deletions
|
@ -6,9 +6,10 @@
|
|||
|
||||
// Piskel externs.
|
||||
var exports;
|
||||
var pskl_exports;
|
||||
var $;
|
||||
var console;
|
||||
var pskl;
|
||||
var pskl;
|
||||
|
||||
// Piskel libs externs.
|
||||
var define;
|
||||
|
|
|
@ -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();
|
||||
|
|
107
src/js/lib/canvastoblob/canvasToBlob.js
Normal file
107
src/js/lib/canvastoblob/canvasToBlob.js
Normal 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
14
src/js/lib/jszip/jszip.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -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);
|
||||
}
|
||||
};
|
||||
})();
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
})();
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
Loading…
Reference in a new issue