mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Adding spritesheet import
- Updated the import dialog to allow users to specify the number of frames in the image (which defaults to 1 x and 1 y) - Setting the frame count for x and y will draw a dotted line in the preview that shows where the image will be split into individual frames - When imported with a frame count above 1, the source image will be split into the different frames and loaded just as if it were an animated gif - This allows users to import existing spritesheet pngs, including those produced by the piskel export function
This commit is contained in:
parent
8d85093874
commit
48f24c0cf3
@ -3,16 +3,27 @@
|
||||
/************************************************************************************************/
|
||||
|
||||
.import-section-preview {
|
||||
display : inline-block;
|
||||
height : 60px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
border: 1px dashed #999;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.import-section-preview.no-border {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.import-section-preview canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.dialog-section-title {
|
||||
display : inline-block;
|
||||
width: 55px;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.import-size-field:nth-of-type(2) {
|
||||
|
@ -67,7 +67,7 @@
|
||||
|
||||
#dialog-container.import-image {
|
||||
width: 500px;
|
||||
height: 300px;
|
||||
height: 320px;
|
||||
top : 50%;
|
||||
left : 50%;
|
||||
position : absolute;
|
||||
|
@ -1,6 +1,6 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs');
|
||||
var PREVIEW_HEIGHT = 60;
|
||||
var PREVIEW_HEIGHT = 60;
|
||||
|
||||
ns.ImportImageController = function (piskelController) {
|
||||
this.importedImage_ = null;
|
||||
@ -20,10 +20,15 @@
|
||||
|
||||
this.resizeWidth = $('[name=resize-width]');
|
||||
this.resizeHeight = $('[name=resize-height]');
|
||||
this.smoothResize = $('[name=smooth-resize-checkbox]');
|
||||
this.smoothResize = $('[name=smooth-resize-checkbox]');
|
||||
|
||||
this.frameCountX = $('[name=frame-count-x]');
|
||||
this.frameCountY = $('[name=frame-count-y]');
|
||||
|
||||
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.importImageForm = $('[name=import-image-form]');
|
||||
this.importImageForm.submit(this.onImportFormSubmit_.bind(this));
|
||||
@ -49,7 +54,24 @@
|
||||
}
|
||||
var height = this.importedImage_.height;
|
||||
var width = this.importedImage_.width;
|
||||
if (from === 'width') {
|
||||
|
||||
var frameCountX = parseInt(this.frameCountX.val(), 10);
|
||||
if (frameCountX <= 0 || isNaN(frameCountX)) {
|
||||
this.frameCountX.val(1);
|
||||
frameCountX = 1;
|
||||
}
|
||||
|
||||
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') {
|
||||
this.resizeHeight.val(Math.round(value * height / width));
|
||||
} else {
|
||||
this.resizeWidth.val(Math.round(value * width / height));
|
||||
@ -64,7 +86,7 @@
|
||||
|
||||
// FIXME : We remove the onload callback here because JsGif will insert
|
||||
// the image again and we want to avoid retriggering the image onload
|
||||
this.importedImage_.onload = function () {};
|
||||
this.importedImage_.onload = function () { };
|
||||
|
||||
var fileName = this.extractFileNameFromPath_(this.file_.name);
|
||||
this.fileNameContainer.html(fileName);
|
||||
@ -72,6 +94,9 @@
|
||||
this.resizeWidth.val(w);
|
||||
this.resizeHeight.val(h);
|
||||
|
||||
this.frameCountX.val(1);
|
||||
this.frameCountY.val(1);
|
||||
|
||||
this.importPreview.width('auto');
|
||||
this.importPreview.html('');
|
||||
this.importPreview.append(this.createImagePreview_());
|
||||
@ -101,19 +126,23 @@
|
||||
if (image) {
|
||||
if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) {
|
||||
var gifLoader = new window.SuperGif({
|
||||
gif : image
|
||||
gif: image
|
||||
});
|
||||
|
||||
gifLoader.load({
|
||||
success : function () {
|
||||
success: function () {
|
||||
var images = gifLoader.getFrames().map(function (frame) {
|
||||
return pskl.utils.CanvasUtils.createFromImageData(frame.data);
|
||||
});
|
||||
this.createPiskelFromImages_(images);
|
||||
this.closeDialog();
|
||||
}.bind(this),
|
||||
error : function () {
|
||||
this.createPiskelFromImages_([image]);
|
||||
error: function () {
|
||||
var images = pskl.utils.CanvasUtils.createFramesFromImage(
|
||||
image,
|
||||
this.frameCountX.val(),
|
||||
this.frameCountY.val());
|
||||
this.createPiskelFromImages_(images);
|
||||
this.closeDialog();
|
||||
}.bind(this)
|
||||
});
|
||||
@ -143,4 +172,54 @@
|
||||
pskl.app.piskelController.setPiskel(piskel);
|
||||
pskl.app.previewController.setFPS(Constants.DEFAULT.FPS);
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.drawFramesGrid_ = function () {
|
||||
var canvasWrapper = this.importPreview.children('canvas');
|
||||
var countX = this.frameCountX.val();
|
||||
var countY = this.frameCountY.val();
|
||||
if (countX > 1 || countY > 1) {
|
||||
var width = this.importedImage_.width;
|
||||
var height = this.importedImage_.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(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();
|
||||
|
||||
// Draw the vertical lines
|
||||
for (var x = 0.5; x < width + 1; x += frameW) {
|
||||
context.moveTo(x, 0);
|
||||
context.lineTo(x, height);
|
||||
}
|
||||
|
||||
// Draw the horizontal lines
|
||||
for (var y = 0.5; y < height + 1; y += frameH) {
|
||||
context.moveTo(0, y);
|
||||
context.lineTo(width, y);
|
||||
}
|
||||
|
||||
// Set the line style to dashed
|
||||
context.lineWidth = 1;
|
||||
context.setLineDash([2, 1]);
|
||||
context.strokeStyle = '#000000';
|
||||
context.stroke();
|
||||
|
||||
// Resize the canvas so that it matches the preview height and stretches correctly
|
||||
canvasWrapper.height(PREVIEW_HEIGHT + 1);
|
||||
canvasWrapper.show();
|
||||
this.importPreview.addClass('no-border');
|
||||
} else {
|
||||
canvasWrapper.hide();
|
||||
this.importPreview.removeClass('no-border');
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -33,6 +33,43 @@
|
||||
return canvas;
|
||||
},
|
||||
|
||||
/**
|
||||
* Splits the specified image into several new canvas elements based on the
|
||||
* supplied horizontal (x) and vertical (y) counts.
|
||||
* @param image The source image that will be split
|
||||
* @param {Number} frameCountX The number of frames in the horizontal axis
|
||||
* @param {Number} frameCountY The number of frames in the vertical axis
|
||||
* @returns {Array} An array of canvas elements that contain the split frames
|
||||
*/
|
||||
createFramesFromImage : function (image, frameCountX, frameCountY) {
|
||||
var canvasArray = [];
|
||||
var frameWidth = image.width / frameCountX;
|
||||
var frameHeight = image.height / frameCountY;
|
||||
|
||||
// Loop through the frames prioritizing the spritesheet as horizonal strips
|
||||
for (var y = 0; y < frameCountY; y++) {
|
||||
for (var x = 0; x < frameCountX; x++) {
|
||||
var canvas = pskl.utils.CanvasUtils.createCanvas(frameWidth, frameHeight);
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
// Blit the correct part of the source image into the new canvas
|
||||
context.drawImage(
|
||||
image,
|
||||
x * frameWidth,
|
||||
y * frameHeight,
|
||||
frameWidth,
|
||||
image.height,
|
||||
0,
|
||||
0,
|
||||
frameWidth,
|
||||
image.height);
|
||||
|
||||
canvasArray.push(canvas);
|
||||
}
|
||||
}
|
||||
return canvasArray;
|
||||
},
|
||||
|
||||
/**
|
||||
* By default, all scaling operations on a Canvas 2D Context are performed using antialiasing.
|
||||
* Resizing a 32x32 image to 320x320 will lead to a blurry output.
|
||||
|
@ -14,12 +14,17 @@
|
||||
</div>
|
||||
<div class="import-section">
|
||||
<span class="dialog-section-title">Size :</span>
|
||||
<input type="text" class="textfield import-size-field" name="resize-width"/>x
|
||||
<input type="text" class="textfield import-size-field" name="resize-height"/>
|
||||
<input type="text" class="textfield import-size-field" name="resize-width" />x
|
||||
<input type="text" class="textfield import-size-field" name="resize-height" />
|
||||
</div>
|
||||
<div class="import-section">
|
||||
<span class="dialog-section-title">Frames :</span>
|
||||
<input type="text" class="textfield import-size-field" name="frame-count-x" />x
|
||||
<input type="text" class="textfield import-size-field" name="frame-count-y" />
|
||||
</div>
|
||||
<div class="import-section">
|
||||
<span class="import-section-title">Smooth resize :</span>
|
||||
<input type="checkbox" checked="checked" name="smooth-resize-checkbox" value="1"/>
|
||||
<input type="checkbox" checked="checked" name="smooth-resize-checkbox" value="1" />
|
||||
</div>
|
||||
<input type="submit" name="import-submit" class="button button-primary import-button" value="Import" />
|
||||
</form>
|
||||
|
Loading…
Reference in New Issue
Block a user