feature #541: add crop transform tool
This commit is contained in:
parent
4b4cbe47c8
commit
a9e22535d6
10 changed files with 123 additions and 30 deletions
|
@ -25,7 +25,7 @@
|
|||
.transformations-show-more-link {
|
||||
position: absolute;
|
||||
color: #999;
|
||||
right: 8px;
|
||||
right: 10px;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
transition: 0.2s linear;
|
||||
|
|
BIN
src/img/icons/transform/tool-crop.png
Normal file
BIN
src/img/icons/transform/tool-crop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 393 B |
BIN
src/img/icons/transform/tool-crop@2x.png
Normal file
BIN
src/img/icons/transform/tool-crop@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 693 B |
|
@ -8,6 +8,7 @@
|
|||
new pskl.tools.transform.Rotate(),
|
||||
new pskl.tools.transform.Clone(),
|
||||
new pskl.tools.transform.Center(),
|
||||
new pskl.tools.transform.Crop(),
|
||||
];
|
||||
|
||||
this.toolIconBuilder = new pskl.tools.ToolIconBuilder();
|
||||
|
|
|
@ -12,11 +12,15 @@
|
|||
/**
|
||||
* Set the current piskel. Will reset the selected frame and layer unless specified
|
||||
* @param {Object} piskel
|
||||
* @param {Boolean} preserveState if true, keep the selected frame and layer
|
||||
* @param {Object} options:
|
||||
* preserveState {Boolean} if true, keep the selected frame and layer
|
||||
* noSnapshot {Boolean} if true, do not save a snapshot in the piskel
|
||||
* history for this call to setPiskel
|
||||
*/
|
||||
ns.PiskelController.prototype.setPiskel = function (piskel, preserveState) {
|
||||
ns.PiskelController.prototype.setPiskel = function (piskel, options) {
|
||||
this.piskel = piskel;
|
||||
if (!preserveState) {
|
||||
options = options || {};
|
||||
if (!options.preserveState) {
|
||||
this.currentLayerIndex = 0;
|
||||
this.currentFrameIndex = 0;
|
||||
}
|
||||
|
|
|
@ -49,14 +49,25 @@
|
|||
return this.piskelController;
|
||||
};
|
||||
|
||||
ns.PublicPiskelController.prototype.setPiskel = function (piskel, preserveState) {
|
||||
this.piskelController.setPiskel(piskel, preserveState);
|
||||
/**
|
||||
* Set the current piskel. Will reset the selected frame and layer unless specified
|
||||
* @param {Object} piskel
|
||||
* @param {Object} options:
|
||||
* preserveState {Boolean} if true, keep the selected frame and layer
|
||||
* noSnapshot {Boolean} if true, do not save a snapshot in the piskel
|
||||
* history for this call to setPiskel
|
||||
*/
|
||||
ns.PublicPiskelController.prototype.setPiskel = function (piskel, options) {
|
||||
this.piskelController.setPiskel(piskel, options);
|
||||
|
||||
$.publish(Events.FRAME_SIZE_CHANGED);
|
||||
$.publish(Events.PISKEL_RESET);
|
||||
$.publish(Events.PISKEL_SAVE_STATE, {
|
||||
type : pskl.service.HistoryService.SNAPSHOT
|
||||
});
|
||||
|
||||
if (!options || !options.noSnapshot) {
|
||||
$.publish(Events.PISKEL_SAVE_STATE, {
|
||||
type : pskl.service.HistoryService.SNAPSHOT
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ns.PublicPiskelController.prototype.resetWrap_ = function (methodName) {
|
||||
|
|
|
@ -69,7 +69,9 @@
|
|||
resizeContent: this.resizeContentCheckbox.checked
|
||||
});
|
||||
|
||||
pskl.app.piskelController.setPiskel(piskel, true);
|
||||
pskl.app.piskelController.setPiskel(piskel, {
|
||||
preserveState: true
|
||||
});
|
||||
|
||||
$.publish(Events.CLOSE_SETTINGS_DRAWER);
|
||||
};
|
||||
|
|
55
src/js/tools/transform/Crop.js
Normal file
55
src/js/tools/transform/Crop.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
(function () {
|
||||
var ns = $.namespace('pskl.tools.transform');
|
||||
|
||||
ns.Crop = function () {
|
||||
this.toolId = 'tool-crop';
|
||||
this.helpText = 'Crop the sprite';
|
||||
this.tooltipDescriptors = [
|
||||
{
|
||||
description : 'Crop to fit the content or the selection. ' +
|
||||
'Applies to all frames and layers!'
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.Crop, ns.AbstractTransformTool);
|
||||
|
||||
ns.Crop.prototype.applyToolOnFrame_ = function (frame, altKey) {
|
||||
var currentPiskel = pskl.app.piskelController.getPiskel();
|
||||
var frames = currentPiskel.getLayers().map(function (l) {
|
||||
return l.getFrames();
|
||||
}).reduce(function (p, n) {
|
||||
return p.concat(n);
|
||||
});
|
||||
|
||||
var boundaries = pskl.tools.transform.TransformUtils.getBoundaries(frames);
|
||||
if (boundaries.minx >= boundaries.maxx) {
|
||||
return;
|
||||
}
|
||||
|
||||
var width = 1 + boundaries.maxx - boundaries.minx;
|
||||
var height = 1 + boundaries.maxy - boundaries.miny;
|
||||
|
||||
if (width === currentPiskel.getWidth() && height === currentPiskel.getHeight()) {
|
||||
// Do not perform an unnecessary resize if it's a noop.
|
||||
return;
|
||||
}
|
||||
|
||||
frames.forEach(function (frame) {
|
||||
pskl.tools.transform.TransformUtils.moveFramePixels(frame, -boundaries.minx, -boundaries.miny);
|
||||
});
|
||||
|
||||
var piskel = pskl.utils.ResizeUtils.resizePiskel(currentPiskel, {
|
||||
width : 1 + boundaries.maxx - boundaries.minx,
|
||||
height : 1 + boundaries.maxy - boundaries.miny,
|
||||
origin: 'TOP-LEFT',
|
||||
resizeContent: false
|
||||
});
|
||||
|
||||
pskl.app.piskelController.setPiskel(piskel, {
|
||||
preserveState: true,
|
||||
noSnapshot: true
|
||||
});
|
||||
};
|
||||
|
||||
})();
|
|
@ -64,32 +64,34 @@
|
|||
return frame;
|
||||
},
|
||||
|
||||
center : function(frame) {
|
||||
// Figure out the boundary
|
||||
var minx = frame.width;
|
||||
var miny = frame.height;
|
||||
getBoundaries : function(frames) {
|
||||
var minx = frames[0].width;
|
||||
var miny = frames[0].height;
|
||||
var maxx = 0;
|
||||
var maxy = 0;
|
||||
|
||||
var transparentColorInt = pskl.utils.colorToInt(Constants.TRANSPARENT_COLOR);
|
||||
frame.forEachPixel(function (color, x, y) {
|
||||
if (color !== transparentColorInt) {
|
||||
minx = Math.min(minx, x);
|
||||
maxx = Math.max(maxx, x);
|
||||
miny = Math.min(miny, y);
|
||||
maxy = Math.max(maxy, y);
|
||||
}
|
||||
|
||||
frames.forEach(function (frame) {
|
||||
frame.forEachPixel(function (color, x, y) {
|
||||
if (color !== transparentColorInt) {
|
||||
minx = Math.min(minx, x);
|
||||
maxx = Math.max(maxx, x);
|
||||
miny = Math.min(miny, y);
|
||||
maxy = Math.max(maxy, y);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Calculate how much to move the pixels
|
||||
var bw = (maxx - minx + 1) / 2;
|
||||
var bh = (maxy - miny + 1) / 2;
|
||||
var fw = frame.width / 2;
|
||||
var fh = frame.height / 2;
|
||||
return {
|
||||
minx: minx,
|
||||
maxx: maxx,
|
||||
miny: miny,
|
||||
maxy: maxy,
|
||||
};
|
||||
},
|
||||
|
||||
var dx = Math.floor(fw - bw - minx);
|
||||
var dy = Math.floor(fh - bh - miny);
|
||||
|
||||
// Actually move the pixels
|
||||
moveFramePixels : function (frame, dx, dy) {
|
||||
var clone = frame.clone();
|
||||
frame.forEachPixel(function(color, x, y) {
|
||||
var _x = x;
|
||||
|
@ -104,7 +106,24 @@
|
|||
frame.setPixel(_x, _y, Constants.TRANSPARENT_COLOR);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
center : function(frame) {
|
||||
// Figure out the boundary
|
||||
var boundaries = ns.TransformUtils.getBoundaries([frame]);
|
||||
|
||||
// Calculate how much to move the pixels
|
||||
var bw = (boundaries.maxx - boundaries.minx + 1) / 2;
|
||||
var bh = (boundaries.maxy - boundaries.miny + 1) / 2;
|
||||
var fw = frame.width / 2;
|
||||
var fh = frame.height / 2;
|
||||
|
||||
var dx = Math.floor(fw - bw - boundaries.minx);
|
||||
var dy = Math.floor(fh - bh - boundaries.miny);
|
||||
|
||||
// Actually move the pixels
|
||||
|
||||
ns.TransformUtils.moveFramePixels(frame, dx, dy);
|
||||
return frame;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -226,6 +226,7 @@
|
|||
"js/tools/transform/AbstractTransformTool.js",
|
||||
"js/tools/transform/Center.js",
|
||||
"js/tools/transform/Clone.js",
|
||||
"js/tools/transform/Crop.js",
|
||||
"js/tools/transform/Flip.js",
|
||||
"js/tools/transform/Rotate.js",
|
||||
"js/tools/transform/TransformUtils.js",
|
||||
|
|
Loading…
Reference in a new issue