diff --git a/src/js/app.js b/src/js/app.js index ae27888c..6d87087e 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -19,7 +19,10 @@ this.shortcutService = new pskl.service.keyboard.ShortcutService(); this.shortcutService.init(); - var size = this.readSizeFromURL_(); + var size = { + height : Constants.DEFAULT.HEIGHT, + width : Constants.DEFAULT.WIDTH + }; var descriptor = new pskl.model.piskel.Descriptor('New Piskel', ''); var piskel = new pskl.model.Piskel(size.width, size.height, descriptor); @@ -111,35 +114,27 @@ this.initTooltips_(); - if (this.isAppEngineVersion) { - this.finishInitAppEngine_(); - } else { - this.finishInitGithub_(); + var piskelData = this.getPiskelInitData_(); + if (piskelData && piskelData.piskel) { + this.loadPiskel_(piskelData.piskel, piskelData.descriptor, piskelData.fps); } }, - finishInitGithub_ : function () { - var framesheetId = this.readFramesheetIdFromURL_(); - if (framesheetId) { - $.publish(Events.SHOW_NOTIFICATION, [{ - "content" : "Loading animation with id : [" + framesheetId + "]" - }]); - this.loadFramesheetFromService(framesheetId); - } + loadPiskel_ : function (serializedPiskel, descriptor, fps) { + pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) { + piskel.setDescriptor(descriptor); + pskl.app.piskelController.setPiskel(piskel); + pskl.app.animationController.setFPS(fps); + }); }, - finishInitAppEngine_ : function () { - if (pskl.appEnginePiskelData_ && pskl.appEnginePiskelData_.piskel) { - pskl.utils.serialization.Deserializer.deserialize(pskl.appEnginePiskelData_.piskel, function (piskel) { - piskel.setDescriptor(pskl.appEnginePiskelData_.descriptor); - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(pskl.appEnginePiskelData_.fps); - }); - } + getPiskelInitData_ : function () { + return pskl.appEnginePiskelData_; }, isLoggedIn : function () { - return pskl.appEnginePiskelData_ && pskl.appEnginePiskelData_.isLoggedIn; + var piskelData = this.getPiskelInitData_(); + return piskelData && piskelData.isLoggedIn; }, initTooltips_ : function () { @@ -154,69 +149,6 @@ this.previewFilmController.render(delta); }, - readSizeFromURL_ : function () { - var sizeParam = this.readUrlParameter_("size"); - var size; - // parameter expected as size=64x48 => size=widthxheight - var parts = sizeParam.split("x"); - if (parts && parts.length == 2 && !isNaN(parts[0]) && !isNaN(parts[1])) { - var width = parseInt(parts[0], 10), - height = parseInt(parts[1], 10); - - size = { - height : Math.min(height, Constants.MAX_HEIGHT), - width : Math.min(width, Constants.MAX_WIDTH) - }; - } else { - size = { - height : Constants.DEFAULT.HEIGHT, - width : Constants.DEFAULT.WIDTH - }; - } - return size; - }, - - readFramesheetIdFromURL_ : function () { - return this.readUrlParameter_("frameId"); - }, - - readUrlParameter_ : function (paramName) { - var searchString = window.location.search.substring(1); - var params = searchString.split("&"); - for (var i = 0; i < params.length; i++) { - var param = params[i].split("="); - if (param[0] == paramName) { - return window.unescape(param[1]); - } - } - return ""; - }, - - loadFramesheetFromService : function (frameId) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', Constants.STATIC.URL.GET + '?l=' + frameId, true); - xhr.responseType = 'text'; - xhr.onload = function (e) { - var res = JSON.parse(this.responseText); - pskl.utils.serialization.Deserializer.deserialize(res.framesheet, function (piskel) { - pskl.app.piskelController.setPiskel(piskel); - pskl.app.animationController.setFPS(res.fps); - - $.publish(Events.HIDE_NOTIFICATION); - }); - }; - - xhr.onerror = function () { - $.publish(Events.HIDE_NOTIFICATION); - }; - - xhr.send(); - }, - - store : function (callbacks) { - this.storageService.store(callbacks); - }, - getFirstFrameAsPng : function () { var firstFrame = this.piskelController.getFrameAt(0); var canvasRenderer = new pskl.rendering.CanvasRenderer(firstFrame, 1); @@ -229,21 +161,6 @@ var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); var framesheetCanvas = renderer.renderAsCanvas(); return framesheetCanvas.toDataURL("image/png"); - }, - - uploadAsSpritesheetPNG : function () { - var imageData = this.getFramesheetAsPng(); - this.imageUploadService.upload(imageData, this.openWindow.bind(this)); - }, - - openWindow : function (url) { - var options = [ - "dialog=yes", "scrollbars=no", "status=no", - "width=" + this.piskelController.getWidth() * this.piskelController.getFrameCount(), - "height=" + this.piskelController.getHeight() - ].join(","); - - window.open(url, "piskel-export", options); } }; })(); diff --git a/src/js/controller/settings/GifExportController.js b/src/js/controller/settings/GifExportController.js index 8f5fdeb4..4eaa052a 100644 --- a/src/js/controller/settings/GifExportController.js +++ b/src/js/controller/settings/GifExportController.js @@ -34,8 +34,13 @@ this.previewContainerEl = document.querySelector(".gif-export-preview"); this.radioGroupEl = document.querySelector(".gif-export-radio-group"); - this.uploadForm = $("[name=gif-export-upload-form]"); - this.uploadForm.submit(this.onUploadFormSubmit_.bind(this)); + this.uploadButton = $(".gif-upload-button"); + this.uploadButton.click(this.onUploadButtonClick_.bind(this)); + + this.downloadButton = $(".gif-download-button"); + this.downloadButton.click(this.onDownloadButtonClick_.bind(this)); + + this.exportForm = $(".gif-export-form"); this.exportProgressStatusEl = document.querySelector('.gif-export-progress-status'); this.exportProgressBarEl = document.querySelector('.gif-export-progress-bar'); @@ -43,15 +48,27 @@ this.createRadioElements_(); }; - ns.GifExportController.prototype.onUploadFormSubmit_ = function (evt) { + ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) { evt.originalEvent.preventDefault(); - var selectedZoom = this.getSelectedZoom_(), - fps = this.piskelController.getFPS(), - zoom = selectedZoom; + var zoom = this.getSelectedZoom_(), + fps = this.piskelController.getFPS(); this.renderAsImageDataAnimatedGIF(zoom, fps, this.onGifRenderingCompleted_.bind(this)); }; + ns.GifExportController.prototype.onDownloadButtonClick_ = function (evt) { + var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif'; + var zoom = this.getSelectedZoom_(), + fps = this.piskelController.getFPS(); + + this.renderAsImageDataAnimatedGIF(zoom, fps, function (imageData) { + pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this)); + pskl.utils.ImageToBlob.imageDataToBlob(imageData, "image/gif", function(blob) { + pskl.utils.FileUtils.downloadAsFile(fileName, blob); + }); + }.bind(this)); + }; + ns.GifExportController.prototype.onGifRenderingCompleted_ = function (imageData) { this.updatePreview_(imageData); this.previewContainerEl.classList.add("preview-upload-ongoing"); @@ -62,7 +79,6 @@ this.updatePreview_(imageUrl); this.updateStatus_(imageUrl); this.previewContainerEl.classList.remove("preview-upload-ongoing"); - }; ns.GifExportController.prototype.updatePreview_ = function (src) { @@ -70,7 +86,7 @@ }; ns.GifExportController.prototype.getSelectedZoom_ = function () { - var radiosColl = this.uploadForm.get(0).querySelectorAll("[name=gif-zoom-level]"), + var radiosColl = this.exportForm.get(0).querySelectorAll("[name=gif-zoom-level]"), radios = Array.prototype.slice.call(radiosColl,0); var selectedRadios = radios.filter(function(radio) {return !!radio.checked;}); @@ -105,15 +121,6 @@ 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(zoom, fps, cb) { var colorCount = pskl.app.currentColorsService.getCurrentColors().length; var preserveColors = colorCount < MAX_GIF_COLORS; @@ -140,7 +147,7 @@ gif.on('finished', function(blob) { this.hideProgressStatus_(); - this.blobToBase64_(blob, cb); + pskl.utils.FileUtils.readFile(blob, cb); }.bind(this)); gif.render(); diff --git a/src/js/controller/settings/PngExportController.js b/src/js/controller/settings/PngExportController.js index 5afba0b9..d0b1fb0e 100644 --- a/src/js/controller/settings/PngExportController.js +++ b/src/js/controller/settings/PngExportController.js @@ -16,21 +16,19 @@ document.querySelector(".zip-generate-button").addEventListener('click', this.onZipButtonClick_.bind(this)); - this.updatePreview_(this.getFramesheetAsBase64Png()); + this.setPreviewSrc_(this.getFramesheetAsCanvas().toDataURL("image/png")); }; 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.ImageToBlob.canvasToBlob(this.getFramesheetAsCanvas(), 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)); + pskl.app.imageUploadService.upload(this.getFramesheetAsCanvas().toDataURL("image/png"), this.onImageUploadCompleted_.bind(this)); }; ns.PngExportController.prototype.onZipButtonClick_ = function () { @@ -59,10 +57,9 @@ return this.piskelController.getPiskel().getDescriptor().name; }; - ns.PngExportController.prototype.getFramesheetAsBase64Png = function () { + ns.PngExportController.prototype.getFramesheetAsCanvas = function () { var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); - var framesheetCanvas = renderer.renderAsCanvas(); - return framesheetCanvas.toDataURL("image/png"); + return renderer.renderAsCanvas(); }; ns.PngExportController.prototype.onImageUploadCompleted_ = function (imageUrl) { @@ -84,7 +81,7 @@ } }; - ns.PngExportController.prototype.updatePreview_ = function (src) { + ns.PngExportController.prototype.setPreviewSrc_ = function (src) { this.previewContainerEl.innerHTML = ""; }; diff --git a/src/js/controller/settings/SaveController.js b/src/js/controller/settings/SaveController.js index fc083339..d0cfc38a 100644 --- a/src/js/controller/settings/SaveController.js +++ b/src/js/controller/settings/SaveController.js @@ -49,7 +49,7 @@ this.piskelController.getPiskel().setDescriptor(descriptor); this.beforeSaving_(); - pskl.app.store({ + pskl.app.storageService.store({ success : this.onSaveSuccess_.bind(this), error : this.onSaveError_.bind(this), after : this.afterSaving_.bind(this) diff --git a/src/js/lib/canvastoblob/canvasToBlob.js b/src/js/lib/canvastoblob/canvasToBlob.js deleted file mode 100644 index 6ff79c83..00000000 --- a/src/js/lib/canvastoblob/canvasToBlob.js +++ /dev/null @@ -1,107 +0,0 @@ -/* 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)); \ No newline at end of file diff --git a/src/js/service/GithubStorageService.js b/src/js/service/GithubStorageService.js index 87b34cda..ecbce59c 100644 --- a/src/js/service/GithubStorageService.js +++ b/src/js/service/GithubStorageService.js @@ -8,24 +8,6 @@ ns.GithubStorageService.prototype.init = function () {}; ns.GithubStorageService.prototype.store = function (callbacks) { - var xhr = new XMLHttpRequest(); - var formData = new FormData(); - formData.append('framesheet_content', this.piskelController.serialize()); - formData.append('fps_speed', this.piskelController.getFPS()); - - xhr.open('POST', Constants.STATIC.URL.SAVE, true); - - xhr.onload = function(e) { - if (this.status == 200) { - var baseUrl = window.location.href.replace(window.location.search, ""); - window.location.href = baseUrl + "?frameId=" + this.responseText; - } else { - this.onerror(e); - } - }; - xhr.onerror = function(e) { - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Saving failed ("+this.status+")"}]); - }; - xhr.send(formData); + throw "Github save is no longer available. Use local save instead"; }; })(); \ No newline at end of file diff --git a/src/js/utils/Base64.js b/src/js/utils/Base64.js new file mode 100644 index 00000000..8e8273f8 --- /dev/null +++ b/src/js/utils/Base64.js @@ -0,0 +1,51 @@ +(function () { + var ns = $.namespace('pskl.utils'); + + var base64_ranks; + 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 + ]); + } + + ns.Base64 = { + decode : function(base64) { + var outptr = 0; + var last = [0, 0]; + var state = 0; + var save = 0; + + var undef; + var len = base64.length, i = 0; + var buffer = new Uint8Array(len / 4 * 3 | 0); + while (len--) { + var code = base64.charCodeAt(i++); + var 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; + } + }; +})(); \ No newline at end of file diff --git a/src/js/utils/ImageToBlob.js b/src/js/utils/ImageToBlob.js new file mode 100644 index 00000000..157c3c64 --- /dev/null +++ b/src/js/utils/ImageToBlob.js @@ -0,0 +1,38 @@ +(function () { + var ns = $.namespace('pskl.utils'); + + var BASE64_REGEX = /\s*;\s*base64\s*(?:;|$)/i; + + ns.ImageToBlob = { + imageDataToBlob : function(dataURI, type, callback) { + var header_end = dataURI.indexOf(","), + data = dataURI.substring(header_end + 1), + isBase64 = 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(); + blob.encoding = isBase64 ? "base64" : "URI"; + blob.data = data; + blob.size = data.length; + } else if (Uint8Array) { + var blobData = isBase64 ? pskl.utils.Base64.decode(data) : decodeURIComponent(data); + blob = new Blob([blobData], {type: type}); + } + callback(blob); + }, + + canvasToBlob : function(canvas, callback, type /*, ...args*/) { + type = type || "image/png"; + + if (this.mozGetAsFile) { + callback(this.mozGetAsFile("canvas", type)); + } else { + var args = Array.prototype.slice.call(arguments, 2); + var dataURI = this.toDataURL.apply(this, args); + pskl.utils.ImageToBlob.imageDataToBlob(dataURI, type, callback); + } + } + }; +})(); \ No newline at end of file diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index c3f4c034..2b4dacbe 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -11,7 +11,6 @@ // 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", @@ -24,12 +23,14 @@ // Libraries "js/utils/core.js", "js/utils/UserAgent.js", + "js/utils/Base64.js", "js/utils/CanvasUtils.js", "js/utils/Dom.js", "js/utils/Math.js", "js/utils/FileUtils.js", "js/utils/FrameUtils.js", "js/utils/LayerUtils.js", + "js/utils/ImageToBlob.js", "js/utils/ImageResizer.js", "js/utils/PixelUtils.js", "js/utils/Template.js", diff --git a/src/templates/settings/application.html b/src/templates/settings/application.html index fdde7954..ed2b07bc 100644 --- a/src/templates/settings/application.html +++ b/src/templates/settings/application.html @@ -29,9 +29,9 @@ -