mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Merge pull request #473 from juliandescottes/feature-spritesheet-options
Feature spritesheet options
This commit is contained in:
commit
20fd196321
@ -151,7 +151,7 @@
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.export-panel-gif .export-panel-section {
|
||||
.export-panel-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
@ -162,3 +162,19 @@
|
||||
width: 75px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.export-panel-png .textfield {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.png-export-dimension-info {
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#png-export-columns {
|
||||
/* Override default textfield padding-right to keep the number spinners
|
||||
aligned to the right. */
|
||||
padding-right: 0;
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ var Events = {
|
||||
HIDE_PROGRESS: 'HIDE_PROGRESS',
|
||||
|
||||
ZOOM_CHANGED : 'ZOOM_CHANGED',
|
||||
EXPORT_SCALE_CHANGED : 'EXPORT_SCALE_CHANGED',
|
||||
|
||||
CURRENT_COLORS_UPDATED : 'CURRENT_COLORS_UPDATED',
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
this.widthInput = document.querySelector('.export-resize .resize-width');
|
||||
this.heightInput = document.querySelector('.export-resize .resize-height');
|
||||
var scale = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING);
|
||||
var scale = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALE);
|
||||
this.sizeInputWidget = new pskl.widgets.SizeInput({
|
||||
widthInput : this.widthInput,
|
||||
heightInput : this.heightInput,
|
||||
@ -94,7 +94,7 @@
|
||||
if (Math.round(this.getExportZoom()) != value) {
|
||||
this.sizeInputWidget.setWidth(this.piskelController.getWidth() * value);
|
||||
}
|
||||
pskl.UserSettings.set(pskl.UserSettings.EXPORT_SCALING, value);
|
||||
pskl.UserSettings.set(pskl.UserSettings.EXPORT_SCALE, value);
|
||||
}
|
||||
};
|
||||
|
||||
@ -111,6 +111,7 @@
|
||||
}
|
||||
|
||||
this.updateScaleText_(zoom);
|
||||
$.publish(Events.EXPORT_SCALE_CHANGED);
|
||||
|
||||
this.scaleInput.value = Math.round(zoom);
|
||||
if (zoom >= 1 && zoom <= 32) {
|
||||
|
@ -24,10 +24,6 @@
|
||||
this.addEventListener(this.downloadButton, 'click', this.onDownloadButtonClick_);
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.destroy = function () {
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.getZoom_ = function () {
|
||||
return this.exportController.getExportZoom();
|
||||
};
|
||||
|
@ -10,12 +10,11 @@
|
||||
pskl.utils.inherit(ns.MiscExportController, pskl.controller.settings.AbstractSettingController);
|
||||
|
||||
ns.MiscExportController.prototype.init = function () {
|
||||
|
||||
var downloadButton = document.querySelector('.c-download-button');
|
||||
this.addEventListener(downloadButton, 'click', this.onCDownloadButtonClick_);
|
||||
var cDownloadButton = document.querySelector('.c-download-button');
|
||||
this.addEventListener(cDownloadButton, 'click', this.onDownloadCFileClick_);
|
||||
};
|
||||
|
||||
ns.MiscExportController.prototype.onCDownloadButtonClick_ = function (evt) {
|
||||
ns.MiscExportController.prototype.onDownloadCFileClick_ = function (evt) {
|
||||
var fileName = this.getPiskelName_() + '.c';
|
||||
var cName = this.getPiskelName_().replace(' ','_');
|
||||
var width = this.piskelController.getWidth();
|
||||
|
@ -1,41 +1,149 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.settings.exportimage');
|
||||
|
||||
var dimensionInfoPattern = '{{width}} x {{height}} px, {{frames}}<br/>{{rows}}, {{columns}}.';
|
||||
|
||||
// Shortcut to pskl.utils.Template.replace
|
||||
var replace = pskl.utils.Template.replace;
|
||||
|
||||
// Helper to return "X items" or "1 item" if X is 1.
|
||||
var pluralize = function (word, count) {
|
||||
if (count === 1) {
|
||||
return '1 ' + word;
|
||||
}
|
||||
return count + ' ' + word + 's';
|
||||
};
|
||||
|
||||
// Compute the nearest power of two for the provided number.
|
||||
var getNearestPowerOfTwo = function (number) {
|
||||
return Math.pow(2, Math.ceil(Math.log(number) / Math.log(2)));
|
||||
};
|
||||
|
||||
ns.PngExportController = function (piskelController, exportController) {
|
||||
this.piskelController = piskelController;
|
||||
this.exportController = exportController;
|
||||
this.onScaleChanged_ = this.onScaleChanged_.bind(this);
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController);
|
||||
|
||||
ns.PngExportController.prototype.init = function () {
|
||||
this.layoutContainer = document.querySelector('.png-export-layout-section');
|
||||
this.dimensionInfo = document.querySelector('.png-export-dimension-info');
|
||||
this.columnsInput = document.querySelector('#png-export-columns');
|
||||
this.powerTwo = document.querySelector('#png-export-power-two');
|
||||
var downloadButton = document.querySelector('.png-download-button');
|
||||
this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_);
|
||||
|
||||
this.initLayoutSection_();
|
||||
this.updateDimensionLabel_();
|
||||
|
||||
this.addEventListener(downloadButton, 'click', this.onDownloadClick_);
|
||||
this.addEventListener(this.columnsInput, 'input', this.onColumnsChanged_);
|
||||
this.addEventListener(this.powerTwo, 'change', this.onPowerTwoChanged_);
|
||||
$.subscribe(Events.EXPORT_SCALE_CHANGED, this.onScaleChanged_);
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) {
|
||||
var fileName = this.getPiskelName_() + '.png';
|
||||
ns.PngExportController.prototype.destroy = function () {
|
||||
$.unsubscribe(Events.EXPORT_SCALE_CHANGED, this.onScaleChanged_);
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
var outputCanvas = this.getFramesheetAsCanvas();
|
||||
/**
|
||||
* Initalize all controls related to the spritesheet layout.
|
||||
*/
|
||||
ns.PngExportController.prototype.initLayoutSection_ = function () {
|
||||
var frames = this.piskelController.getFrameCount();
|
||||
if (frames === 1) {
|
||||
// Hide the layout section if only one frame is defined.
|
||||
this.layoutContainer.style.display = 'none';
|
||||
} else {
|
||||
this.columnsInput.value = this.getBestFit_();
|
||||
this.powerTwo.checked = pskl.UserSettings.get('EXPORT_PNG_POWER_TWO');
|
||||
}
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.updateDimensionLabel_ = function () {
|
||||
var zoom = this.exportController.getExportZoom();
|
||||
var frames = this.piskelController.getFrameCount();
|
||||
var width = this.piskelController.getWidth() * zoom;
|
||||
var height = this.piskelController.getHeight() * zoom;
|
||||
|
||||
var columns = this.getColumns_();
|
||||
var rows = Math.ceil(frames / columns);
|
||||
width = columns * width;
|
||||
height = rows * height;
|
||||
|
||||
if (this.isPowerTwoEnabled_()) {
|
||||
width = getNearestPowerOfTwo(width);
|
||||
height = getNearestPowerOfTwo(height);
|
||||
}
|
||||
|
||||
this.dimensionInfo.innerHTML = replace(dimensionInfoPattern, {
|
||||
width: width,
|
||||
height: height,
|
||||
rows: pluralize('row', rows),
|
||||
columns: pluralize('column', columns),
|
||||
frames: pluralize('frame', frames),
|
||||
});
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.getColumns_ = function () {
|
||||
return parseInt(this.columnsInput.value || 1, 10);
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.getBestFit_ = function () {
|
||||
var ratio = this.piskelController.getWidth() / this.piskelController.getHeight();
|
||||
var frameCount = this.piskelController.getFrameCount();
|
||||
var bestFit = Math.round(Math.sqrt(frameCount / ratio));
|
||||
|
||||
return Math.max(1, Math.min(bestFit, frameCount));
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.isPowerTwoEnabled_ = function () {
|
||||
return pskl.UserSettings.get('EXPORT_PNG_POWER_TWO');
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onScaleChanged_ = function () {
|
||||
this.updateDimensionLabel_();
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onColumnsChanged_ = function () {
|
||||
if (this.getColumns_() > this.piskelController.getFrameCount()) {
|
||||
this.columnsInput.value = this.piskelController.getFrameCount();
|
||||
} else if (this.getColumns_() < 1) {
|
||||
this.columnsInput.value = 1;
|
||||
}
|
||||
this.updateDimensionLabel_();
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onPowerTwoChanged_ = function () {
|
||||
pskl.UserSettings.set('EXPORT_PNG_POWER_TWO', this.powerTwo.checked);
|
||||
this.updateDimensionLabel_();
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onDownloadClick_ = function (evt) {
|
||||
var name = this.piskelController.getPiskel().getDescriptor().name;
|
||||
var fileName = name + '.png';
|
||||
|
||||
var renderer = new pskl.rendering.PiskelRenderer(this.piskelController);
|
||||
var outputCanvas = renderer.renderAsCanvas(this.getColumns_());
|
||||
var width = outputCanvas.width;
|
||||
var height = outputCanvas.height;
|
||||
|
||||
var zoom = this.exportController.getExportZoom();
|
||||
if (zoom != 1) {
|
||||
var width = outputCanvas.width * zoom;
|
||||
var height = outputCanvas.height * zoom;
|
||||
outputCanvas = pskl.utils.ImageResizer.resize(outputCanvas, width, height, false);
|
||||
outputCanvas = pskl.utils.ImageResizer.resize(outputCanvas, width * zoom, height * zoom, false);
|
||||
}
|
||||
|
||||
if (this.isPowerTwoEnabled_()) {
|
||||
var paddingCanvas = pskl.utils.CanvasUtils.createCanvas(
|
||||
getNearestPowerOfTwo(width * zoom), getNearestPowerOfTwo(height * zoom));
|
||||
paddingCanvas.getContext('2d').drawImage(outputCanvas, 0, 0);
|
||||
outputCanvas = paddingCanvas;
|
||||
}
|
||||
|
||||
pskl.utils.BlobUtils.canvasToBlob(outputCanvas, function(blob) {
|
||||
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
||||
});
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.getPiskelName_ = function () {
|
||||
return this.piskelController.getPiskel().getDescriptor().name;
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.getFramesheetAsCanvas = function () {
|
||||
var renderer = new pskl.rendering.PiskelRenderer(this.piskelController);
|
||||
return renderer.renderAsCanvas();
|
||||
};
|
||||
})();
|
||||
|
@ -13,11 +13,17 @@
|
||||
}
|
||||
};
|
||||
|
||||
ns.FramesheetRenderer.prototype.renderAsCanvas = function () {
|
||||
var canvas = this.createCanvas_();
|
||||
ns.FramesheetRenderer.prototype.renderAsCanvas = function (columns) {
|
||||
columns = columns || this.frames.length;
|
||||
var rows = Math.ceil(this.frames.length / columns);
|
||||
|
||||
var canvas = this.createCanvas_(columns, rows);
|
||||
|
||||
for (var i = 0 ; i < this.frames.length ; i++) {
|
||||
var frame = this.frames[i];
|
||||
this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0);
|
||||
var posX = (i % columns) * frame.getWidth();
|
||||
var posY = Math.floor(i / columns) * frame.getHeight();
|
||||
this.drawFrameInCanvas_(frame, canvas, posX, posY);
|
||||
}
|
||||
return canvas;
|
||||
};
|
||||
@ -32,11 +38,10 @@
|
||||
});
|
||||
};
|
||||
|
||||
ns.FramesheetRenderer.prototype.createCanvas_ = function () {
|
||||
ns.FramesheetRenderer.prototype.createCanvas_ = function (columns, rows) {
|
||||
var sampleFrame = this.frames[0];
|
||||
var count = this.frames.length;
|
||||
var width = count * sampleFrame.getWidth();
|
||||
var height = sampleFrame.getHeight();
|
||||
var width = columns * sampleFrame.getWidth();
|
||||
var height = rows * sampleFrame.getHeight();
|
||||
return pskl.utils.CanvasUtils.createCanvas(width, height);
|
||||
};
|
||||
})();
|
||||
|
@ -11,11 +11,17 @@
|
||||
this.frames = frames;
|
||||
};
|
||||
|
||||
ns.PiskelRenderer.prototype.renderAsCanvas = function () {
|
||||
var canvas = this.createCanvas_();
|
||||
ns.PiskelRenderer.prototype.renderAsCanvas = function (columns) {
|
||||
columns = columns || this.frames.length;
|
||||
var rows = Math.ceil(this.frames.length / columns);
|
||||
|
||||
var canvas = this.createCanvas_(columns, rows);
|
||||
|
||||
for (var i = 0 ; i < this.frames.length ; i++) {
|
||||
var frame = this.frames[i];
|
||||
this.drawFrameInCanvas_(frame, canvas, i * this.piskelController.getWidth(), 0);
|
||||
var posX = (i % columns) * this.piskelController.getWidth();
|
||||
var posY = Math.floor(i / columns) * this.piskelController.getHeight();
|
||||
this.drawFrameInCanvas_(frame, canvas, posX, posY);
|
||||
}
|
||||
return canvas;
|
||||
};
|
||||
@ -25,10 +31,9 @@
|
||||
context.drawImage(frame, offsetWidth, offsetHeight, frame.width, frame.height);
|
||||
};
|
||||
|
||||
ns.PiskelRenderer.prototype.createCanvas_ = function () {
|
||||
var count = this.frames.length;
|
||||
var width = count * this.piskelController.getWidth();
|
||||
var height = this.piskelController.getHeight();
|
||||
ns.PiskelRenderer.prototype.createCanvas_ = function (columns, rows) {
|
||||
var width = columns * this.piskelController.getWidth();
|
||||
var height = rows * this.piskelController.getHeight();
|
||||
return pskl.utils.CanvasUtils.createCanvas(width, height);
|
||||
};
|
||||
})();
|
||||
|
@ -12,7 +12,8 @@
|
||||
ONION_SKIN : 'ONION_SKIN',
|
||||
LAYER_PREVIEW : 'LAYER_PREVIEW',
|
||||
LAYER_OPACITY : 'LAYER_OPACITY',
|
||||
EXPORT_SCALING: 'EXPORT_SCALING',
|
||||
EXPORT_PNG_POWER_TWO: 'EXPORT_PNG_POWER_TWO',
|
||||
EXPORT_SCALE: 'EXPORT_SCALE',
|
||||
EXPORT_TAB: 'EXPORT_TAB',
|
||||
PEN_SIZE : 'PEN_SIZE',
|
||||
RESIZE_SETTINGS: 'RESIZE_SETTINGS',
|
||||
@ -30,8 +31,9 @@
|
||||
'ONION_SKIN' : false,
|
||||
'LAYER_OPACITY' : 0.2,
|
||||
'LAYER_PREVIEW' : true,
|
||||
'EXPORT_SCALING' : 1,
|
||||
'EXPORT_TAB' : 'png',
|
||||
'EXPORT_PNG_POWER_TWO' : false,
|
||||
'EXPORT_SCALE' : 1,
|
||||
'EXPORT_TAB' : 'gif',
|
||||
'PEN_SIZE' : 1,
|
||||
'RESIZE_SETTINGS': {
|
||||
maintainRatio : true,
|
||||
|
@ -15,8 +15,8 @@
|
||||
<input type="text" class="textfield resize-field resize-height" autocomplete="off" name="resize-height"/>
|
||||
</div>
|
||||
<div class="export-tabs">
|
||||
<div class="export-tab" data-tab-id="png">PNG</div>
|
||||
<div class="export-tab" data-tab-id="gif">GIF</div>
|
||||
<div class="export-tab" data-tab-id="png">PNG</div>
|
||||
<div class="export-tab" data-tab-id="zip">Zip</div>
|
||||
<div class="export-tab" data-tab-id="misc">Others</div>
|
||||
</div>
|
||||
|
@ -3,11 +3,11 @@
|
||||
<div class="export-info">
|
||||
Convert your sprite to an animated GIF. Opacity will not be preserved. Colors might be resampled.
|
||||
</div>
|
||||
<div class="export-panel-section">
|
||||
<div class="export-panel-section export-panel-row">
|
||||
<button type="button" class="button button-primary gif-download-button">Download</button>
|
||||
<div>Download as an animated GIF.</div>
|
||||
</div>
|
||||
<div class="export-panel-section">
|
||||
<div class="export-panel-section export-panel-row">
|
||||
<button type="button" class="button button-primary gif-upload-button">Upload</button>
|
||||
<div>Upload as an animated GIF to a public URL.</div>
|
||||
</div>
|
||||
|
@ -1,8 +1,22 @@
|
||||
<script type="text/html" id="templates/settings/export/png.html">
|
||||
<div class="export-panel-png">
|
||||
<div class="export-info">Export your animation as a PNG spritesheet containing all frames.</div>
|
||||
<div class="export-panel-section">
|
||||
<button type="button" class="button button-primary png-download-button">Download PNG</button>
|
||||
<div class="export-panel-section png-export-layout-section">
|
||||
<div style="color: gold; padding-bottom: 5px;">Spritesheet layout options:</div>
|
||||
<div style="display: flex;">
|
||||
<div style="flex: 1; line-height: 20px;">
|
||||
<span>Columns</span>
|
||||
<input type="number" class="textfield" id="png-export-columns" name="png-export-columns">
|
||||
</div>
|
||||
<div style="flex: 1; line-height: 20px;">
|
||||
<label for="png-export-power-two">Power of 2</label>
|
||||
<input type="checkbox" id="png-export-power-two" name="png-export-power-two">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="export-panel-section export-panel-row">
|
||||
<button type="button" class="button button-primary png-download-button">Download</button>
|
||||
<span class="png-export-dimension-info"></span>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user