From e37d93f7f9187816f4e1af91cdfd39de5e2aa279 Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Tue, 14 Jun 2016 13:28:25 -0700 Subject: [PATCH 1/4] Extract import logic to ImportService Isolates import dialog logic from actual import logic, which makes headless import eaiser to implement. --- src/js/app.js | 2 + .../dialogs/ImportImageController.js | 88 +++---------- src/js/service/ImportService.js | 121 ++++++++++++++++++ src/piskel-script-list.js | 1 + 4 files changed, 139 insertions(+), 73 deletions(-) create mode 100644 src/js/service/ImportService.js diff --git a/src/js/app.js b/src/js/app.js index d3ace910..ee3bb4d1 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -124,6 +124,8 @@ this.storageService = new pskl.service.storage.StorageService(this.piskelController); this.storageService.init(); + this.importService = new pskl.service.ImportService(this.piskelController, this.previewController); + this.imageUploadService = new pskl.service.ImageUploadService(); this.imageUploadService.init(); diff --git a/src/js/controller/dialogs/ImportImageController.js b/src/js/controller/dialogs/ImportImageController.js index 7a433c98..8613e3fe 100644 --- a/src/js/controller/dialogs/ImportImageController.js +++ b/src/js/controller/dialogs/ImportImageController.js @@ -171,84 +171,26 @@ }; ns.ImportImageController.prototype.importImageToPiskel_ = function () { - var image = this.importedImage_; - if (image) { + if (this.importedImage_) { if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) { - var gifLoader = new window.SuperGif({ - gif : image - }); - - var resizeW = this.resizeWidth.val(); - var resizeH = this.resizeHeight.val(); - - gifLoader.load({ - success : function () { - var images = gifLoader.getFrames().map(function (frame) { - return pskl.utils.CanvasUtils.createFromImageData(frame.data); - }); - - if (this.getImportType_() === 'single' || images.length > 1) { - // Single image import or animated gif - this.createPiskelFromImages_(images, resizeW, resizeH); - } else { - // Spritesheet - this.createImagesFromSheet_(images[0]); - } - this.closeDialog(); - }.bind(this), - error: function () { - if (this.getImportType_() === 'single') { - // Single image - this.createPiskelFromImages_([image], resizeW, resizeH); - } else { - // Spritesheet - this.createImagesFromSheet_(image); - } - this.closeDialog(); - }.bind(this) - }); - + pskl.app.importService.newPiskelFromImage( + this.importedImage_, + { + importType: this.getImportType_(), + frameSizeX: this.getImportType_() === 'single' ? + this.resizeWidth.val() : this.sanitizeInputValue_(this.frameSizeX, 1), + frameSizeY: this.getImportType_() === 'single' ? + this.resizeHeight.val() : this.sanitizeInputValue_(this.frameSizeY, 1), + frameOffsetX: this.sanitizeInputValue_(this.frameOffsetX, 0), + frameOffsetY: this.sanitizeInputValue_(this.frameOffsetY, 0), + smoothing: !!this.smoothResize.prop('checked') + }, + this.closeDialog.bind(this) + ); } } }; - ns.ImportImageController.prototype.createImagesFromSheet_ = function (image) { - var x = this.sanitizeInputValue_(this.frameOffsetX, 0); - var y = this.sanitizeInputValue_(this.frameOffsetY, 0); - var w = this.sanitizeInputValue_(this.frameSizeX, 1); - var h = this.sanitizeInputValue_(this.frameSizeY, 1); - - var images = pskl.utils.CanvasUtils.createFramesFromImage( - image, - x, - y, - w, - h, - /*useHorizonalStrips=*/ true, - /*ignoreEmptyFrames=*/ true); - this.createPiskelFromImages_(images, w, h); - }; - - ns.ImportImageController.prototype.createFramesFromImages_ = function (images, w, h) { - var smoothing = !!this.smoothResize.prop('checked'); - - var frames = images.map(function (image) { - var resizedImage = pskl.utils.ImageResizer.resize(image, w, h, smoothing); - return pskl.utils.FrameUtils.createFromImage(resizedImage); - }); - return frames; - }; - - ns.ImportImageController.prototype.createPiskelFromImages_ = function (images, w, h) { - var frames = this.createFramesFromImages_(images, w, h); - var layer = pskl.model.Layer.fromFrames('Layer 1', frames); - var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', ''); - var piskel = pskl.model.Piskel.fromLayers([layer], descriptor); - - pskl.app.piskelController.setPiskel(piskel); - pskl.app.previewController.setFPS(Constants.DEFAULT.FPS); - }; - ns.ImportImageController.prototype.drawFrameGrid_ = function (frameX, frameY, frameW, frameH) { if (!this.importedImage_) { return; diff --git a/src/js/service/ImportService.js b/src/js/service/ImportService.js new file mode 100644 index 00000000..5586ce11 --- /dev/null +++ b/src/js/service/ImportService.js @@ -0,0 +1,121 @@ +/* Image and Animation import service supporting the import dialogs, + * file dropper service, and headless import API. */ +(function () { + /** + * @param {!PiskelController} piskelController + * @param {!PreviewController} previewController + * @constructor + */ + var ImportService = $.namespace('pskl.service').ImportService = + function (piskelController, previewController) { + this.piskelController_ = piskelController; + this.previewController_ = previewController; + }; + + /** + * @param {!Image} image + * @param {!Object} options + * @param {!string} options.importType - 'single' if not spritesheet + * @param {!number} options.frameSizeX + * @param {!number} options.frameSizeY + * @param {number} [options.frameOffsetX] only used in spritesheet imports. + * @param {number} [options.frameOffsetY] only used in spritesheet imports. + * @param {!boolean} options.smoothing + * @param {function} [onComplete] + */ + ImportService.prototype.newPiskelFromImage = function (image, options, onComplete) { + onComplete = onComplete || function () {}; + var importType = options.importType; + var frameSizeX = options.frameSizeX; + var frameSizeY = options.frameSizeY; + var frameOffsetX = options.frameOffsetX; + var frameOffsetY = options.frameOffsetY; + + var gifLoader = new window.SuperGif({ + gif: image + }); + + gifLoader.load({ + success: function () { + var images = gifLoader.getFrames().map(function (frame) { + return pskl.utils.CanvasUtils.createFromImageData(frame.data); + }); + + if (importType === 'single' || images.length > 1) { + // Single image import or animated gif + this.createPiskelFromImages_(images, frameSizeX, frameSizeY, options.smoothing); + } else { + // Spritesheet + var frameImages = this.createImagesFromSheet_(images[0]); + this.createPiskelFromImages_(frameImages, frameSizeX, frameSizeY, options.smoothing); + } + onComplete(); + }.bind(this), + error: function () { + if (importType === 'single') { + // Single image + this.createPiskelFromImages_([image], frameSizeX, frameSizeY, options.smoothing); + } else { + // Spritesheet + var frameImages = this.createImagesFromSheet_(image, frameSizeX, frameSizeY, frameOffsetX, frameOffsetY); + this.createPiskelFromImages_(frameImages, frameSizeX, frameSizeY, options.smoothing); + } + onComplete(); + }.bind(this) + }); + }; + + /** + * @param {!Image} image + * @param {!number} frameSizeX + * @param {!number} frameSizeY + * @param {!number} frameOffsetX + * @param {!number} frameOffsetY + * @returns {canvas[]} + * @private + */ + ImportService.prototype.createImagesFromSheet_ = function (image, + frameSizeX, frameSizeY, frameOffsetX, frameOffsetY) { + return pskl.utils.CanvasUtils.createFramesFromImage( + image, + frameOffsetX, + frameOffsetY, + frameSizeX, + frameSizeY, + /*useHorizonalStrips=*/ true, + /*ignoreEmptyFrames=*/ true); + }; + + /** + * @param {canvas[]} images + * @param {!number} frameSizeX + * @param {!number} frameSizeY + * @param {!boolean} smoothing + * @private + */ + ImportService.prototype.createPiskelFromImages_ = function (images, + frameSizeX, frameSizeY, smoothing) { + var frames = this.createFramesFromImages_(images, frameSizeX, frameSizeY, smoothing); + var layer = pskl.model.Layer.fromFrames('Layer 1', frames); + var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', ''); + var piskel = pskl.model.Piskel.fromLayers([layer], descriptor); + + this.piskelController_.setPiskel(piskel); + this.previewController_.setFPS(Constants.DEFAULT.FPS); + }; + + /** + * @param {!canvas[]} images + * @param {!number} frameSizeX + * @param {!number} frameSizeY + * @param {!boolean} smoothing + * @returns {pskl.model.Frame[]} + * @private + */ + ImportService.prototype.createFramesFromImages_ = function (images, frameSizeX, frameSizeY, smoothing) { + return images.map(function (image) { + var resizedImage = pskl.utils.ImageResizer.resize(image, frameSizeX, frameSizeY, smoothing); + return pskl.utils.FrameUtils.createFromImage(resizedImage); + }); + }; +})(); diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index f49fea02..f9f2fafd 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -169,6 +169,7 @@ "js/service/keyboard/Shortcut.js", "js/service/keyboard/Shortcuts.js", "js/service/keyboard/ShortcutService.js", + "js/service/ImportService.js", "js/service/ImageUploadService.js", "js/service/CurrentColorsService.js", "js/service/FileDropperService.js", From e1cba9f13bd33dc58516e176ee289fd93bd8182a Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Thu, 16 Jun 2016 18:09:47 -0700 Subject: [PATCH 2/4] Re-adopt ns convention for module definition --- src/js/service/ImportService.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/js/service/ImportService.js b/src/js/service/ImportService.js index 5586ce11..885b72f9 100644 --- a/src/js/service/ImportService.js +++ b/src/js/service/ImportService.js @@ -1,12 +1,13 @@ /* Image and Animation import service supporting the import dialogs, * file dropper service, and headless import API. */ (function () { + var ns = $.namespace('pskl.service'); /** * @param {!PiskelController} piskelController * @param {!PreviewController} previewController * @constructor */ - var ImportService = $.namespace('pskl.service').ImportService = + ns.ImportService = function (piskelController, previewController) { this.piskelController_ = piskelController; this.previewController_ = previewController; @@ -23,7 +24,7 @@ * @param {!boolean} options.smoothing * @param {function} [onComplete] */ - ImportService.prototype.newPiskelFromImage = function (image, options, onComplete) { + ns.ImportService.prototype.newPiskelFromImage = function (image, options, onComplete) { onComplete = onComplete || function () {}; var importType = options.importType; var frameSizeX = options.frameSizeX; @@ -74,7 +75,7 @@ * @returns {canvas[]} * @private */ - ImportService.prototype.createImagesFromSheet_ = function (image, + ns.ImportService.prototype.createImagesFromSheet_ = function (image, frameSizeX, frameSizeY, frameOffsetX, frameOffsetY) { return pskl.utils.CanvasUtils.createFramesFromImage( image, @@ -93,7 +94,7 @@ * @param {!boolean} smoothing * @private */ - ImportService.prototype.createPiskelFromImages_ = function (images, + ns.ImportService.prototype.createPiskelFromImages_ = function (images, frameSizeX, frameSizeY, smoothing) { var frames = this.createFramesFromImages_(images, frameSizeX, frameSizeY, smoothing); var layer = pskl.model.Layer.fromFrames('Layer 1', frames); @@ -112,7 +113,7 @@ * @returns {pskl.model.Frame[]} * @private */ - ImportService.prototype.createFramesFromImages_ = function (images, frameSizeX, frameSizeY, smoothing) { + ns.ImportService.prototype.createFramesFromImages_ = function (images, frameSizeX, frameSizeY, smoothing) { return images.map(function (image) { var resizedImage = pskl.utils.ImageResizer.resize(image, frameSizeX, frameSizeY, smoothing); return pskl.utils.FrameUtils.createFromImage(resizedImage); From efbfeca200c461e7f9ae8311879ff13256c059b5 Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Thu, 16 Jun 2016 18:12:13 -0700 Subject: [PATCH 3/4] Improved comments --- src/js/service/ImportService.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/js/service/ImportService.js b/src/js/service/ImportService.js index 885b72f9..bdca439b 100644 --- a/src/js/service/ImportService.js +++ b/src/js/service/ImportService.js @@ -1,8 +1,8 @@ -/* Image and Animation import service supporting the import dialogs, - * file dropper service, and headless import API. */ +/* @file Image and Animation import service supporting the import dialog. */ (function () { var ns = $.namespace('pskl.service'); /** + * Image an animation import service supporting the import dialog. * @param {!PiskelController} piskelController * @param {!PreviewController} previewController * @constructor @@ -14,6 +14,8 @@ }; /** + * Given an image object and some options, create a new Piskel and open it + * for editing. * @param {!Image} image * @param {!Object} options * @param {!string} options.importType - 'single' if not spritesheet From 7e112776b6965e28dca7423e598ccf8edf615d75 Mon Sep 17 00:00:00 2001 From: Brad Buchanan Date: Thu, 16 Jun 2016 18:13:08 -0700 Subject: [PATCH 4/4] Use Constants.EMPTY_FUNCTION --- src/js/service/ImportService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/service/ImportService.js b/src/js/service/ImportService.js index bdca439b..44d1513b 100644 --- a/src/js/service/ImportService.js +++ b/src/js/service/ImportService.js @@ -27,7 +27,7 @@ * @param {function} [onComplete] */ ns.ImportService.prototype.newPiskelFromImage = function (image, options, onComplete) { - onComplete = onComplete || function () {}; + onComplete = onComplete || Constants.EMPTY_FUNCTION; var importType = options.importType; var frameSizeX = options.frameSizeX; var frameSizeY = options.frameSizeY;