mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Updating the spritesheet import to use size
- The import dialog now allows users to select an option between single image or spritesheet importing - The spritesheet option allows setting of the size of an indivdual frame and the offset from the left/top from which to start slicing frames - Selecting the spritesheet option will display a frame slice grid over the preview image to give a quick view of where the frames will be made - When importing the spritesheet blank (transparent) frames and also partial frames will be ignored - This allows users to import spritesheets that have been packed into a larger image with excess padding
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs');
|
||||
var PREVIEW_HEIGHT = 60;
|
||||
|
||||
ns.ImportImageController = function (piskelController) {
|
||||
this.importedImage_ = null;
|
||||
@ -18,17 +17,25 @@
|
||||
|
||||
this.fileNameContainer = $('.import-image-file-name');
|
||||
|
||||
this.importType = $('[name=import-type]');
|
||||
|
||||
this.resizeWidth = $('[name=resize-width]');
|
||||
this.resizeHeight = $('[name=resize-height]');
|
||||
this.smoothResize = $('[name=smooth-resize-checkbox]');
|
||||
|
||||
this.frameCountX = $('[name=frame-count-x]');
|
||||
this.frameCountY = $('[name=frame-count-y]');
|
||||
this.frameSizeX = $('[name=frame-size-x]');
|
||||
this.frameSizeY = $('[name=frame-size-y]');
|
||||
this.frameOffsetX = $('[name=frame-offset-x]');
|
||||
this.frameOffsetY = $('[name=frame-offset-y]');
|
||||
|
||||
this.importType.change(this.onImportTypeChange_.bind(this));
|
||||
|
||||
this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width'));
|
||||
this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height'));
|
||||
this.frameCountX.keyup(this.onResizeInputKeyUp_.bind(this, 'frameCountX'));
|
||||
this.frameCountY.keyup(this.onResizeInputKeyUp_.bind(this, 'frameCountY'));
|
||||
this.frameSizeX.keyup(this.onFrameInputKeyUp_.bind(this, 'frameSizeX'));
|
||||
this.frameSizeY.keyup(this.onFrameInputKeyUp_.bind(this, 'frameSizeY'));
|
||||
this.frameOffsetX.keyup(this.onFrameInputKeyUp_.bind(this, 'frameOffsetX'));
|
||||
this.frameOffsetY.keyup(this.onFrameInputKeyUp_.bind(this, 'frameOffsetY'));
|
||||
|
||||
this.importImageForm = $('[name=import-image-form]');
|
||||
this.importImageForm.submit(this.onImportFormSubmit_.bind(this));
|
||||
@ -36,6 +43,20 @@
|
||||
pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this));
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onImportTypeChange_ = function (evt) {
|
||||
if (this.getImportType_() === 'single') {
|
||||
// Using single image, so remove the frame grid
|
||||
this.hideFrameGrid_();
|
||||
} else {
|
||||
// Using spritesheet import, so draw the frame grid in the preview
|
||||
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);
|
||||
this.drawFrameGrid_(x, y, w, h);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) {
|
||||
evt.originalEvent.preventDefault();
|
||||
this.importImageToPiskel_();
|
||||
@ -47,6 +68,12 @@
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onFrameInputKeyUp_ = function (from, evt) {
|
||||
if (this.importedImage_) {
|
||||
this.synchronizeFrameFields_(evt.target.value, from);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) {
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
@ -55,31 +82,48 @@
|
||||
var height = this.importedImage_.height;
|
||||
var width = this.importedImage_.width;
|
||||
|
||||
// Parse the X frame count
|
||||
var frameCountX = parseInt(this.frameCountX.val(), 10);
|
||||
if (frameCountX <= 0 || isNaN(frameCountX)) {
|
||||
this.frameCountX.val(1);
|
||||
frameCountX = 1;
|
||||
}
|
||||
// Select single image import type since the user changed a value here
|
||||
this.importType.filter('[value="single"]').attr('checked', 'checked');
|
||||
|
||||
// Parse the Y frame count
|
||||
var frameCountY = parseInt(this.frameCountY.val(), 10);
|
||||
if (frameCountY <= 0 || isNaN(frameCountY)) {
|
||||
this.frameCountY.val(1);
|
||||
frameCountY = 1;
|
||||
}
|
||||
|
||||
if (from === 'frameCountX' || from === 'frameCountY') {
|
||||
this.resizeWidth.val(Math.round(width / frameCountX));
|
||||
this.resizeHeight.val(Math.round(height / frameCountY));
|
||||
this.drawFramesGrid_();
|
||||
} else if (from === 'width') {
|
||||
if (from === 'width') {
|
||||
this.resizeHeight.val(Math.round(value * height / width));
|
||||
} else {
|
||||
this.resizeWidth.val(Math.round(value * width / height));
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.synchronizeFrameFields_ = function (value, from) {
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
// Parse the frame input values
|
||||
var frameSizeX = this.sanitizeInputValue_(this.frameSizeX, 1);
|
||||
var frameSizeY = this.sanitizeInputValue_(this.frameSizeY, 1);
|
||||
var frameOffsetX = this.sanitizeInputValue_(this.frameOffsetX, 0);
|
||||
var frameOffsetY = this.sanitizeInputValue_(this.frameOffsetY, 0);
|
||||
|
||||
// Select spritesheet import type since the user changed a value here
|
||||
this.importType.filter('[value="sheet"]').attr('checked', 'checked');
|
||||
|
||||
// Draw the grid
|
||||
this.drawFrameGrid_(frameOffsetX, frameOffsetY, frameSizeX, frameSizeY);
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.sanitizeInputValue_ = function(input, minValue) {
|
||||
var value = parseInt(input.val(), 10);
|
||||
if (value <= minValue || isNaN(value)) {
|
||||
input.val(minValue);
|
||||
value = minValue;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.getImportType_ = function () {
|
||||
return this.importType.filter(':checked').val();
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onImageLoaded_ = function (image) {
|
||||
this.importedImage_ = image;
|
||||
|
||||
@ -96,10 +140,13 @@
|
||||
this.resizeWidth.val(w);
|
||||
this.resizeHeight.val(h);
|
||||
|
||||
this.frameCountX.val(1);
|
||||
this.frameCountY.val(1);
|
||||
this.frameSizeX.val(w);
|
||||
this.frameSizeY.val(h);
|
||||
this.frameOffsetX.val(0);
|
||||
this.frameOffsetY.val(0);
|
||||
|
||||
this.importPreview.width('auto');
|
||||
this.importPreview.height('auto');
|
||||
this.importPreview.html('');
|
||||
this.importPreview.append(this.createImagePreview_());
|
||||
};
|
||||
@ -107,7 +154,6 @@
|
||||
ns.ImportImageController.prototype.createImagePreview_ = function () {
|
||||
var image = document.createElement('IMG');
|
||||
image.src = this.importedImage_.src;
|
||||
image.setAttribute('height', PREVIEW_HEIGHT);
|
||||
return image;
|
||||
};
|
||||
|
||||
@ -131,20 +177,37 @@
|
||||
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);
|
||||
});
|
||||
this.createPiskelFromImages_(images);
|
||||
this.createPiskelFromImages_(images, resizeW, resizeH);
|
||||
this.closeDialog();
|
||||
}.bind(this),
|
||||
error : function () {
|
||||
var images = pskl.utils.CanvasUtils.createFramesFromImage(
|
||||
image,
|
||||
this.frameCountX.val(),
|
||||
this.frameCountY.val());
|
||||
this.createPiskelFromImages_(images);
|
||||
error: function () {
|
||||
if (this.getImportType_() === 'single') {
|
||||
// Single image
|
||||
this.createPiskelFromImages_([image], resizeW, resizeH);
|
||||
} else {
|
||||
// Spritesheet
|
||||
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);
|
||||
}
|
||||
this.closeDialog();
|
||||
}.bind(this)
|
||||
});
|
||||
@ -153,9 +216,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.createFramesFromImages_ = function (images) {
|
||||
var w = this.resizeWidth.val();
|
||||
var h = this.resizeHeight.val();
|
||||
ns.ImportImageController.prototype.createFramesFromImages_ = function (images, w, h) {
|
||||
var smoothing = !!this.smoothResize.prop('checked');
|
||||
|
||||
var frames = images.map(function (image) {
|
||||
@ -165,8 +226,8 @@
|
||||
return frames;
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.createPiskelFromImages_ = function (images) {
|
||||
var frames = this.createFramesFromImages_(images);
|
||||
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);
|
||||
@ -175,38 +236,52 @@
|
||||
pskl.app.previewController.setFPS(Constants.DEFAULT.FPS);
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.drawFramesGrid_ = function () {
|
||||
ns.ImportImageController.prototype.drawFrameGrid_ = function (frameX, frameY, frameW, frameH) {
|
||||
if (!this.importedImage_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the sizes of the source and preview images
|
||||
var width = this.importedImage_.width;
|
||||
var height = this.importedImage_.height;
|
||||
var previewWidth = this.importPreview.width();
|
||||
var previewHeight = this.importPreview.height();
|
||||
|
||||
var canvasWrapper = this.importPreview.children('canvas');
|
||||
var countX = this.frameCountX.val();
|
||||
var countY = this.frameCountY.val();
|
||||
if (countX > 1 || countY > 1) {
|
||||
var width = this.importPreview.width();
|
||||
var height = this.importPreview.height();
|
||||
var frameW = width / countX;
|
||||
var frameH = height / countY;
|
||||
var canvas = canvasWrapper.get(0);
|
||||
if (!canvasWrapper.length) {
|
||||
// Create a new canvas for the grid
|
||||
canvas = pskl.utils.CanvasUtils.createCanvas(
|
||||
previewWidth + 1,
|
||||
previewHeight + 1);
|
||||
this.importPreview.append(canvas);
|
||||
canvasWrapper = $(canvas);
|
||||
}
|
||||
|
||||
var canvas = canvasWrapper.get(0);
|
||||
if (!canvasWrapper.length) {
|
||||
// Create a new canvas for the grid
|
||||
canvas = pskl.utils.CanvasUtils.createCanvas(width + 1, height + 1);
|
||||
this.importPreview.append(canvas);
|
||||
canvasWrapper = $(canvas);
|
||||
}
|
||||
var context = canvas.getContext('2d');
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.beginPath();
|
||||
|
||||
var context = canvas.getContext('2d');
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.beginPath();
|
||||
// Calculate the number of whole frames
|
||||
var countX = Math.floor((width - frameX) / frameW);
|
||||
var countY = Math.floor((height - frameY) / frameH);
|
||||
|
||||
if (countX > 0 && countY > 0) {
|
||||
var scaleX = previewWidth / width;
|
||||
var scaleY = previewHeight / height;
|
||||
var maxWidth = countX * frameW + frameX;
|
||||
var maxHeight = countY * frameH + frameY;
|
||||
|
||||
// Draw the vertical lines
|
||||
for (var x = 0.5; x < width + 1; x += frameW) {
|
||||
context.moveTo(x, 0);
|
||||
context.lineTo(x, height);
|
||||
for (var x = frameX + 0.5; x < maxWidth + 1 && x < width + 1; x += frameW) {
|
||||
context.moveTo(x * scaleX, frameY * scaleY);
|
||||
context.lineTo(x * scaleX, maxHeight * scaleY);
|
||||
}
|
||||
|
||||
// Draw the horizontal lines
|
||||
for (var y = 0.5; y < height + 1; y += frameH) {
|
||||
context.moveTo(0, y);
|
||||
context.lineTo(width, y);
|
||||
for (var y = frameY + 0.5; y < maxHeight + 1 && y < height + 1; y += frameH) {
|
||||
context.moveTo(frameX * scaleX, y * scaleY);
|
||||
context.lineTo(maxWidth * scaleX, y * scaleY);
|
||||
}
|
||||
|
||||
// Set the line style to dashed
|
||||
@ -215,13 +290,17 @@
|
||||
context.strokeStyle = '#000000';
|
||||
context.stroke();
|
||||
|
||||
// Resize the canvas so that it matches the preview height and stretches correctly
|
||||
canvasWrapper.height(PREVIEW_HEIGHT + 1);
|
||||
// Show the canvas
|
||||
canvasWrapper.show();
|
||||
this.importPreview.addClass('no-border');
|
||||
} else {
|
||||
canvasWrapper.hide();
|
||||
this.importPreview.removeClass('no-border');
|
||||
this.hideFrameGrid_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.hideFrameGrid_ = function() {
|
||||
this.importPreview.children('canvas').hide();
|
||||
this.importPreview.removeClass('no-border');
|
||||
};
|
||||
|
||||
})();
|
||||
|
Reference in New Issue
Block a user