mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
0d81865f3b | |||
12cfe16cb4 | |||
e773f9ae6d | |||
5c46cfe20a | |||
2d9001db6e | |||
8ff15fd0e1 | |||
8e4ea8437f | |||
48f24c0cf3 | |||
8d85093874 | |||
1beeb8d6e4 | |||
f9b07b29a9 | |||
9bc330e5e8 | |||
a51e20b370 | |||
ef6ef6256e | |||
4edbc29e72 | |||
b72c775a04 | |||
034057dcd2 | |||
016316518d |
@ -2,17 +2,64 @@
|
|||||||
/* Import dialog */
|
/* Import dialog */
|
||||||
/************************************************************************************************/
|
/************************************************************************************************/
|
||||||
|
|
||||||
|
#dialog-container.import-image {
|
||||||
|
width: 550px;
|
||||||
|
height: 360px;
|
||||||
|
top : 50%;
|
||||||
|
left : 50%;
|
||||||
|
position : absolute;
|
||||||
|
margin-left: -250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show #dialog-container.import-image {
|
||||||
|
margin-top: -150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-subsection {
|
||||||
|
margin-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-section:not(.import-subsection) > .dialog-section-title {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-section-preview-title {
|
||||||
|
position: absolute;
|
||||||
|
margin-left: 50%;
|
||||||
|
margin-top: -28px;
|
||||||
|
}
|
||||||
|
|
||||||
.import-section-preview {
|
.import-section-preview {
|
||||||
display : inline-block;
|
position: absolute;
|
||||||
height : 60px;
|
display: inline-block;
|
||||||
width: 60px;
|
|
||||||
border: 1px dashed #999;
|
border: 1px dashed #999;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
|
margin-left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-section-preview img {
|
||||||
|
max-width: 220px;
|
||||||
|
max-height: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-section-preview.no-border {
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-section-preview canvas {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-section-title {
|
.dialog-section-title {
|
||||||
display : inline-block;
|
display : inline-block;
|
||||||
width: 55px;
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-section-radio {
|
||||||
|
margin-top: 15px;
|
||||||
|
vertical-align: sub;
|
||||||
}
|
}
|
||||||
|
|
||||||
.import-size-field:nth-of-type(2) {
|
.import-size-field:nth-of-type(2) {
|
||||||
@ -23,12 +70,17 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
height: 2rem;
|
width: 200px;
|
||||||
word-break : break-all;
|
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
||||||
|
word-break : break-all;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
|
color: gold;
|
||||||
}
|
}
|
||||||
|
|
||||||
[name=smooth-resize-checkbox] {
|
[name=smooth-resize-checkbox] {
|
||||||
@ -36,12 +88,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dialog-import-body {
|
.dialog-import-body {
|
||||||
padding:10px 20px;
|
padding: 10px 20px;
|
||||||
font-size:1.5em
|
font-size:1.3em
|
||||||
}
|
}
|
||||||
|
|
||||||
.import-button {
|
.import-button {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
height: auto;
|
height: 28px;
|
||||||
padding: 5px 10px;
|
padding: 0px 10px;
|
||||||
|
margin-top: 15px;
|
||||||
}
|
}
|
@ -65,19 +65,6 @@
|
|||||||
margin-top: -250px;
|
margin-top: -250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dialog-container.import-image {
|
|
||||||
width: 500px;
|
|
||||||
height: 300px;
|
|
||||||
top : 50%;
|
|
||||||
left : 50%;
|
|
||||||
position : absolute;
|
|
||||||
margin-left: -250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.show #dialog-container.import-image {
|
|
||||||
margin-top: -150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-wrapper {
|
.dialog-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position : relative;
|
position : relative;
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
border-radius : 2px;
|
border-radius : 2px;
|
||||||
padding : 3px 10px;
|
padding : 3px 10px;
|
||||||
color : white;
|
color : white;
|
||||||
|
|
||||||
|
height: 23px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textfield[disabled=disabled] {
|
.textfield[disabled=disabled] {
|
||||||
|
@ -3,7 +3,7 @@ html, body {
|
|||||||
margin : 0;
|
margin : 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
cursor : default;
|
cursor : default;
|
||||||
font-family: arial;
|
font-family: Arial;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
@ -19,6 +19,12 @@ ul, li {
|
|||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Firefox overrides this with -moz-use-system-font */
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
input[type="submit"] {
|
||||||
|
font-family: Arial;
|
||||||
|
}
|
||||||
|
|
||||||
/* Force apparition of scrollbars on leopard */
|
/* Force apparition of scrollbars on leopard */
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
.tiled-preview-checkbox {
|
/*******************************/
|
||||||
vertical-align: -2px;
|
/* Application Setting panel */
|
||||||
margin-left: 0;
|
/*******************************/
|
||||||
}
|
|
||||||
|
@ -5,17 +5,6 @@
|
|||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resize-content-checkbox {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.resize-ratio-checkbox,
|
|
||||||
.resize-smooth-checkbox {
|
|
||||||
vertical-align: -2px;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*****************/
|
/*****************/
|
||||||
/* ANCHOR WIDGET */
|
/* ANCHOR WIDGET */
|
||||||
/*****************/
|
/*****************/
|
||||||
|
@ -50,3 +50,8 @@ body {
|
|||||||
.uppercase {
|
.uppercase {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.checkbox-fix {
|
||||||
|
vertical-align: -2px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
(function () {
|
(function () {
|
||||||
var ns = $.namespace('pskl.controller.dialogs');
|
var ns = $.namespace('pskl.controller.dialogs');
|
||||||
var PREVIEW_HEIGHT = 60;
|
|
||||||
|
|
||||||
ns.ImportImageController = function (piskelController) {
|
ns.ImportImageController = function (piskelController) {
|
||||||
this.importedImage_ = null;
|
this.importedImage_ = null;
|
||||||
@ -18,12 +17,25 @@
|
|||||||
|
|
||||||
this.fileNameContainer = $('.import-image-file-name');
|
this.fileNameContainer = $('.import-image-file-name');
|
||||||
|
|
||||||
|
this.importType = $('[name=import-type]');
|
||||||
|
|
||||||
this.resizeWidth = $('[name=resize-width]');
|
this.resizeWidth = $('[name=resize-width]');
|
||||||
this.resizeHeight = $('[name=resize-height]');
|
this.resizeHeight = $('[name=resize-height]');
|
||||||
this.smoothResize = $('[name=smooth-resize-checkbox]');
|
this.smoothResize = $('[name=smooth-resize-checkbox]');
|
||||||
|
|
||||||
|
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.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width'));
|
||||||
this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height'));
|
this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height'));
|
||||||
|
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 = $('[name=import-image-form]');
|
||||||
this.importImageForm.submit(this.onImportFormSubmit_.bind(this));
|
this.importImageForm.submit(this.onImportFormSubmit_.bind(this));
|
||||||
@ -31,6 +43,20 @@
|
|||||||
pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this));
|
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) {
|
ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) {
|
||||||
evt.originalEvent.preventDefault();
|
evt.originalEvent.preventDefault();
|
||||||
this.importImageToPiskel_();
|
this.importImageToPiskel_();
|
||||||
@ -42,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) {
|
ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) {
|
||||||
value = parseInt(value, 10);
|
value = parseInt(value, 10);
|
||||||
if (isNaN(value)) {
|
if (isNaN(value)) {
|
||||||
@ -49,6 +81,10 @@
|
|||||||
}
|
}
|
||||||
var height = this.importedImage_.height;
|
var height = this.importedImage_.height;
|
||||||
var width = this.importedImage_.width;
|
var width = this.importedImage_.width;
|
||||||
|
|
||||||
|
// Select single image import type since the user changed a value here
|
||||||
|
this.importType.filter('[value="single"]').attr('checked', 'checked');
|
||||||
|
|
||||||
if (from === 'width') {
|
if (from === 'width') {
|
||||||
this.resizeHeight.val(Math.round(value * height / width));
|
this.resizeHeight.val(Math.round(value * height / width));
|
||||||
} else {
|
} else {
|
||||||
@ -56,6 +92,38 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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) {
|
ns.ImportImageController.prototype.onImageLoaded_ = function (image) {
|
||||||
this.importedImage_ = image;
|
this.importedImage_ = image;
|
||||||
|
|
||||||
@ -68,11 +136,18 @@
|
|||||||
|
|
||||||
var fileName = this.extractFileNameFromPath_(this.file_.name);
|
var fileName = this.extractFileNameFromPath_(this.file_.name);
|
||||||
this.fileNameContainer.html(fileName);
|
this.fileNameContainer.html(fileName);
|
||||||
|
this.fileNameContainer.attr('title', fileName);
|
||||||
|
|
||||||
this.resizeWidth.val(w);
|
this.resizeWidth.val(w);
|
||||||
this.resizeHeight.val(h);
|
this.resizeHeight.val(h);
|
||||||
|
|
||||||
|
this.frameSizeX.val(w);
|
||||||
|
this.frameSizeY.val(h);
|
||||||
|
this.frameOffsetX.val(0);
|
||||||
|
this.frameOffsetY.val(0);
|
||||||
|
|
||||||
this.importPreview.width('auto');
|
this.importPreview.width('auto');
|
||||||
|
this.importPreview.height('auto');
|
||||||
this.importPreview.html('');
|
this.importPreview.html('');
|
||||||
this.importPreview.append(this.createImagePreview_());
|
this.importPreview.append(this.createImagePreview_());
|
||||||
};
|
};
|
||||||
@ -80,7 +155,6 @@
|
|||||||
ns.ImportImageController.prototype.createImagePreview_ = function () {
|
ns.ImportImageController.prototype.createImagePreview_ = function () {
|
||||||
var image = document.createElement('IMG');
|
var image = document.createElement('IMG');
|
||||||
image.src = this.importedImage_.src;
|
image.src = this.importedImage_.src;
|
||||||
image.setAttribute('height', PREVIEW_HEIGHT);
|
|
||||||
return image;
|
return image;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,16 +178,32 @@
|
|||||||
gif : image
|
gif : image
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var resizeW = this.resizeWidth.val();
|
||||||
|
var resizeH = this.resizeHeight.val();
|
||||||
|
|
||||||
gifLoader.load({
|
gifLoader.load({
|
||||||
success : function () {
|
success : function () {
|
||||||
var images = gifLoader.getFrames().map(function (frame) {
|
var images = gifLoader.getFrames().map(function (frame) {
|
||||||
return pskl.utils.CanvasUtils.createFromImageData(frame.data);
|
return pskl.utils.CanvasUtils.createFromImageData(frame.data);
|
||||||
});
|
});
|
||||||
this.createPiskelFromImages_(images);
|
|
||||||
|
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();
|
this.closeDialog();
|
||||||
}.bind(this),
|
}.bind(this),
|
||||||
error : function () {
|
error: function () {
|
||||||
this.createPiskelFromImages_([image]);
|
if (this.getImportType_() === 'single') {
|
||||||
|
// Single image
|
||||||
|
this.createPiskelFromImages_([image], resizeW, resizeH);
|
||||||
|
} else {
|
||||||
|
// Spritesheet
|
||||||
|
this.createImagesFromSheet_(image);
|
||||||
|
}
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
});
|
});
|
||||||
@ -122,9 +212,24 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.ImportImageController.prototype.createFramesFromImages_ = function (images) {
|
ns.ImportImageController.prototype.createImagesFromSheet_ = function (image) {
|
||||||
var w = this.resizeWidth.val();
|
var x = this.sanitizeInputValue_(this.frameOffsetX, 0);
|
||||||
var h = this.resizeHeight.val();
|
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 smoothing = !!this.smoothResize.prop('checked');
|
||||||
|
|
||||||
var frames = images.map(function (image) {
|
var frames = images.map(function (image) {
|
||||||
@ -134,8 +239,8 @@
|
|||||||
return frames;
|
return frames;
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.ImportImageController.prototype.createPiskelFromImages_ = function (images) {
|
ns.ImportImageController.prototype.createPiskelFromImages_ = function (images, w, h) {
|
||||||
var frames = this.createFramesFromImages_(images);
|
var frames = this.createFramesFromImages_(images, w, h);
|
||||||
var layer = pskl.model.Layer.fromFrames('Layer 1', frames);
|
var layer = pskl.model.Layer.fromFrames('Layer 1', frames);
|
||||||
var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', '');
|
var descriptor = new pskl.model.piskel.Descriptor('Imported piskel', '');
|
||||||
var piskel = pskl.model.Piskel.fromLayers([layer], descriptor);
|
var piskel = pskl.model.Piskel.fromLayers([layer], descriptor);
|
||||||
@ -143,4 +248,72 @@
|
|||||||
pskl.app.piskelController.setPiskel(piskel);
|
pskl.app.piskelController.setPiskel(piskel);
|
||||||
pskl.app.previewController.setFPS(Constants.DEFAULT.FPS);
|
pskl.app.previewController.setFPS(Constants.DEFAULT.FPS);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 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 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 = 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 = 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
|
||||||
|
context.lineWidth = 1;
|
||||||
|
context.setLineDash([2, 1]);
|
||||||
|
context.strokeStyle = '#000000';
|
||||||
|
context.stroke();
|
||||||
|
|
||||||
|
// Show the canvas
|
||||||
|
canvasWrapper.show();
|
||||||
|
this.importPreview.addClass('no-border');
|
||||||
|
} else {
|
||||||
|
this.hideFrameGrid_();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ImportImageController.prototype.hideFrameGrid_ = function() {
|
||||||
|
this.importPreview.children('canvas').hide();
|
||||||
|
this.importPreview.removeClass('no-border');
|
||||||
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController);
|
pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController);
|
||||||
|
|
||||||
ns.PngExportController.prototype.init = function () {
|
ns.PngExportController.prototype.init = function () {
|
||||||
this.pngFilePrefixInput = document.getElementById('zip-prefix-name');
|
this.pngFilePrefixInput = document.querySelector('.zip-prefix-name');
|
||||||
this.pngFilePrefixInput.value = 'sprite_';
|
this.pngFilePrefixInput.value = 'sprite_';
|
||||||
|
|
||||||
|
this.splitByLayersCheckbox = document.querySelector('.zip-split-layers-checkbox');
|
||||||
|
|
||||||
var downloadButton = document.querySelector('.png-download-button');
|
var downloadButton = document.querySelector('.png-download-button');
|
||||||
this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_);
|
this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_);
|
||||||
|
|
||||||
@ -30,12 +32,10 @@
|
|||||||
ns.PngExportController.prototype.onZipButtonClick_ = function () {
|
ns.PngExportController.prototype.onZipButtonClick_ = function () {
|
||||||
var zip = new window.JSZip();
|
var zip = new window.JSZip();
|
||||||
|
|
||||||
for (var i = 0 ; i < this.piskelController.getFrameCount() ; i++) {
|
if (this.splitByLayersCheckbox.checked) {
|
||||||
var frame = this.piskelController.getFrameAt(i);
|
this.splittedExport_(zip);
|
||||||
var canvas = this.getFrameAsCanvas_(frame);
|
} else {
|
||||||
var basename = this.pngFilePrefixInput.value;
|
this.mergedExport_(zip);
|
||||||
var filename = basename + (i + 1) + '.png';
|
|
||||||
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileName = this.getPiskelName_() + '.zip';
|
var fileName = this.getPiskelName_() + '.zip';
|
||||||
@ -47,6 +47,30 @@
|
|||||||
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ns.PngExportController.prototype.mergedExport_ = function (zip) {
|
||||||
|
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
||||||
|
var frame = this.piskelController.getFrameAt(i);
|
||||||
|
var canvas = this.getFrameAsCanvas_(frame);
|
||||||
|
var basename = this.pngFilePrefixInput.value;
|
||||||
|
var filename = basename + (i + 1) + '.png';
|
||||||
|
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PngExportController.prototype.splittedExport_ = function (zip) {
|
||||||
|
var layers = this.piskelController.getLayers();
|
||||||
|
for (var j = 0; this.piskelController.hasLayerAt(j); j++) {
|
||||||
|
var layer = this.piskelController.getLayerAt(j);
|
||||||
|
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
||||||
|
var frame = layer.getFrameAt(i);
|
||||||
|
var canvas = this.getFrameAsCanvas_(frame);
|
||||||
|
var basename = this.pngFilePrefixInput.value;
|
||||||
|
var filename = 'l' + j + '_' + basename + (i + 1) + '.png';
|
||||||
|
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) {
|
ns.PngExportController.prototype.getFrameAsCanvas_ = function (frame) {
|
||||||
var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1);
|
var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, 1);
|
||||||
canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR);
|
canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR);
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -7,7 +7,15 @@
|
|||||||
40 : 'down',
|
40 : 'down',
|
||||||
46 : 'del',
|
46 : 'del',
|
||||||
189 : '-',
|
189 : '-',
|
||||||
|
// 109 for numpad -
|
||||||
|
109 : '-',
|
||||||
|
// 173 on Firefox for minus key
|
||||||
|
173 : '-',
|
||||||
187 : '+',
|
187 : '+',
|
||||||
|
// 107 for numpad +
|
||||||
|
107 : '+',
|
||||||
|
// 61 on Firefox for =/+ key
|
||||||
|
61 : '+',
|
||||||
188 : '<',
|
188 : '<',
|
||||||
190 : '>'
|
190 : '>'
|
||||||
};
|
};
|
||||||
|
@ -33,6 +33,66 @@
|
|||||||
return canvas;
|
return canvas;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the specified image into several new canvas elements based on the
|
||||||
|
* supplied offset and frame sizes
|
||||||
|
* @param image The source image that will be split
|
||||||
|
* @param {Number} offsetX The padding from the left side of the source image
|
||||||
|
* @param {Number} offsetY The padding from the top side of the source image
|
||||||
|
* @param {Number} width The width of an individual frame
|
||||||
|
* @param {Number} height The height of an individual frame
|
||||||
|
* @param {Boolean} useHorizonalStrips True if the frames should be layed out from left to
|
||||||
|
* right, False if it should use top to bottom
|
||||||
|
* @param {Boolean} ignoreEmptyFrames True to ignore empty frames, false to keep them
|
||||||
|
* @returns {Array} An array of canvas elements that contain the split frames
|
||||||
|
*/
|
||||||
|
createFramesFromImage : function (image, offsetX, offsetY, width, height, useHorizonalStrips, ignoreEmptyFrames) {
|
||||||
|
var canvasArray = [];
|
||||||
|
var x = offsetX;
|
||||||
|
var y = offsetY;
|
||||||
|
var blankData = pskl.utils.CanvasUtils.createCanvas(width, height).toDataURL();
|
||||||
|
|
||||||
|
while (x + width <= image.width && y + height <= image.height) {
|
||||||
|
// Create a new canvas element
|
||||||
|
var canvas = pskl.utils.CanvasUtils.createCanvas(width, height);
|
||||||
|
var context = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// Blit the correct part of the source image into the new canvas
|
||||||
|
context.drawImage(
|
||||||
|
image,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
|
||||||
|
if (!ignoreEmptyFrames || canvas.toDataURL() !== blankData) {
|
||||||
|
canvasArray.push(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useHorizonalStrips) {
|
||||||
|
// Move from left to right
|
||||||
|
x += width;
|
||||||
|
if (x + width > image.width) {
|
||||||
|
x = offsetX;
|
||||||
|
y += height;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Move from top to bottom
|
||||||
|
y += height;
|
||||||
|
if (y + height > image.height) {
|
||||||
|
x += width;
|
||||||
|
y = offsetY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvasArray;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By default, all scaling operations on a Canvas 2D Context are performed using antialiasing.
|
* 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.
|
* Resizing a 32x32 image to 320x320 will lead to a blurry output.
|
||||||
|
@ -9,19 +9,41 @@
|
|||||||
<span class="dialog-section-title">Name :</span><span class="import-image-file-name"></span>
|
<span class="dialog-section-title">Name :</span><span class="import-image-file-name"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="import-section">
|
<div class="import-section">
|
||||||
<span class="dialog-section-title" style="vertical-align:top">Info :</span>
|
<div class="import-section-preview-title">Preview :</div>
|
||||||
<div class="import-section-preview"></div>
|
<div class="import-section-preview"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="import-section">
|
<div class="import-section">
|
||||||
<span class="dialog-section-title">Size :</span>
|
<label class="dialog-section-radio-label">
|
||||||
|
<input class="dialog-section-radio" name="import-type" value="single" type="radio" checked="checked">
|
||||||
|
Import as single image
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="import-section import-subsection">
|
||||||
|
<span class="dialog-section-title">Resize to</span>
|
||||||
<input type="text" class="textfield import-size-field" name="resize-width"/>x
|
<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-height"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="import-section">
|
<div class="import-section import-subsection">
|
||||||
<span class="import-section-title">Smooth resize :</span>
|
<span class="import-section-title">Smooth resize</span>
|
||||||
<input type="checkbox" checked="checked" name="smooth-resize-checkbox" value="1"/>
|
<input type="checkbox" class="checkbox-fix" checked="checked" name="smooth-resize-checkbox" value="1"/>
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" name="import-submit" class="button button-primary import-button" value="Import" />
|
<div class="import-section">
|
||||||
|
<label class="dialog-section-radio-label">
|
||||||
|
<input class="dialog-section-radio" name="import-type" value="sheet" type="radio">
|
||||||
|
Import as spritesheet
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="import-section import-subsection">
|
||||||
|
<span class="dialog-section-title">Frame size</span>
|
||||||
|
<input type="text" class="textfield import-size-field" name="frame-size-x"/>x
|
||||||
|
<input type="text" class="textfield import-size-field" name="frame-size-y"/>
|
||||||
|
</div>
|
||||||
|
<div class="import-section import-subsection">
|
||||||
|
<span class="dialog-section-title">Offset</span>
|
||||||
|
<input type="text" class="textfield import-size-field" name="frame-offset-x"/>x
|
||||||
|
<input type="text" class="textfield import-size-field" name="frame-offset-y"/>
|
||||||
|
</div>
|
||||||
|
<input type="submit" name="import-submit" class="button button-primary import-button" value="Import"/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
<div class="settings-item">
|
<div class="settings-item">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" value="1" class="tiled-preview-checkbox" name="tiled-preview-checkbox"/>
|
<input type="checkbox" value="1" class="tiled-preview-checkbox checkbox-fix" name="tiled-preview-checkbox"/>
|
||||||
Repeated preview
|
Repeated preview
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,8 +13,14 @@
|
|||||||
<span class="settings-description">ZIP with one PNG file per frame.</span>
|
<span class="settings-description">ZIP with one PNG file per frame.</span>
|
||||||
<span class="settings-description" style="display:block">File names will start with the prefix below.</span>
|
<span class="settings-description" style="display:block">File names will start with the prefix below.</span>
|
||||||
<div class="settings-item">
|
<div class="settings-item">
|
||||||
<label for="zip-prefix-name">Prefix:</label>
|
<label>Prefix</label>
|
||||||
<input id="zip-prefix-name" type="text" class="textfield" placeholder="PNG file prefix ...">
|
<input class="zip-prefix-name textfield" type="text" placeholder="PNG file prefix ...">
|
||||||
|
</div>
|
||||||
|
<div class="settings-item">
|
||||||
|
<label>
|
||||||
|
<input class="zip-split-layers-checkbox checkbox-fix" type="checkbox" />
|
||||||
|
Split by layers
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
|
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,13 +17,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="resize-section">
|
<div class="resize-section">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" class="resize-ratio-checkbox" value="true" checked="true"/>
|
<input type="checkbox" class="resize-ratio-checkbox checkbox-fix" value="true" checked="true"/>
|
||||||
<span>Maintain aspect ratio</span>
|
<span>Maintain aspect ratio</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="resize-section">
|
<div class="resize-section">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" class="resize-content-checkbox" value="true"/>
|
<input type="checkbox" class="resize-content-checkbox checkbox-fix" value="true"/>
|
||||||
<span>Resize canvas content</span>
|
<span>Resize canvas content</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user