mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Merge pull request #140 from juliandescottes/import-picture-panel
Import picture panel
This commit is contained in:
commit
2ba451d42c
69
css/forms.css
Normal file
69
css/forms.css
Normal file
@ -0,0 +1,69 @@
|
||||
.textfield {
|
||||
background : black;
|
||||
border : 1px solid #888;
|
||||
border-radius : 2px;
|
||||
padding : 3px 10px;
|
||||
color : white;
|
||||
}
|
||||
|
||||
.textfield[disabled=disabled] {
|
||||
background : #3a3a3a;
|
||||
}
|
||||
|
||||
.textfield-small {
|
||||
width : 50px;
|
||||
}
|
||||
|
||||
.button {
|
||||
height: 24px;
|
||||
box-sizing: border-box;
|
||||
|
||||
background-color: #3f3f3f;
|
||||
border: 1px solid #333;
|
||||
border-top-color: #666;
|
||||
border-bottom-color: #222;
|
||||
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
|
||||
color: white;
|
||||
text-shadow: 0px -1px 0 black;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
|
||||
transition: background-color 0.2s linear;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
text-decoration: none;
|
||||
background-color: #484848;
|
||||
color: gold;
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
background-color: rgb(255,215,0); /* gold */
|
||||
|
||||
border-color: rgb(179, 164, 0);
|
||||
border-top-color: white;
|
||||
border-bottom-color: rgb(151, 133, 0);
|
||||
|
||||
color: black;
|
||||
text-shadow: 0px 1px 0 #fff;
|
||||
}
|
||||
|
||||
.button-primary:hover {
|
||||
background-color: rgb(255,235,20);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.button[disabled=disabled],
|
||||
.button[disabled=disabled]:hover {
|
||||
cursor:default;
|
||||
background-color: #aaa;
|
||||
color: #777;
|
||||
text-shadow: 0px 1px 0 #bbb;
|
||||
border-color: #666;
|
||||
border-top-color: #999;
|
||||
border-bottom-color: #555;
|
||||
}
|
@ -31,14 +31,14 @@
|
||||
}
|
||||
|
||||
.right-sticky-section.expanded .tool-icon {
|
||||
margin-right: 1px;
|
||||
padding-right: 1px;
|
||||
}
|
||||
|
||||
.right-sticky-section .tool-icon.has-expanded-drawer {
|
||||
position: relative;
|
||||
background-color: #444;
|
||||
margin-right: 0;
|
||||
padding-right: 1px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.settings-section {
|
||||
@ -81,7 +81,7 @@
|
||||
top: -2px;
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
left: -2px;
|
||||
left: -2px;
|
||||
}
|
||||
|
||||
.background-picker:hover:after {
|
||||
@ -93,11 +93,18 @@
|
||||
}
|
||||
|
||||
/* Gif Export Setting panel*/
|
||||
.export-gif-upload-button {
|
||||
.gif-upload-button,
|
||||
.gif-render-button {
|
||||
/*float : right;*/
|
||||
margin-top : 10px;
|
||||
margin-right : 10px;
|
||||
}
|
||||
|
||||
.export-gif-preview {
|
||||
.gif-export-radio-group {
|
||||
margin:10px 0;
|
||||
}
|
||||
|
||||
.gif-export-preview {
|
||||
margin-top:20px;
|
||||
max-width:240px;
|
||||
position:relative;
|
||||
@ -115,4 +122,46 @@
|
||||
-moz-box-sizing:border-box;
|
||||
background: rgba(0,0,0,0.5);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Import panel */
|
||||
.import-section {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.import-section-disabled {
|
||||
color : #888;
|
||||
}
|
||||
|
||||
.import-section-preview {
|
||||
display : inline-block;
|
||||
height : 60px;
|
||||
width: 60px;
|
||||
border : 1px dashed #999;
|
||||
border-radius: 3px;
|
||||
margin-left : 10px;
|
||||
}
|
||||
|
||||
.import-resize-field {
|
||||
width: 30px;
|
||||
margin: 0px 8px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.file-input-button {
|
||||
margin: 0px 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.file-input-status {
|
||||
display: inline-block;
|
||||
width: 130px;
|
||||
overflow: hidden;
|
||||
|
||||
height: 1.5rem;
|
||||
word-break : break-all;
|
||||
vertical-align: middle;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
text-shadow: none;
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
body {
|
||||
background: radial-gradient(circle, #000, #373737);
|
||||
/* 16/06/2013 : -webkit still needed for
|
||||
@ -8,6 +6,11 @@ body {
|
||||
background: -webkit-radial-gradient(circle, #000, #373737);
|
||||
}
|
||||
|
||||
/* Browser fixes */
|
||||
::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Application layout
|
||||
*/
|
||||
@ -246,35 +249,19 @@ body {
|
||||
}
|
||||
|
||||
.layers-button {
|
||||
height: 24px;
|
||||
margin: 0;
|
||||
width: 25%;
|
||||
float : left;
|
||||
border: none;
|
||||
box-sizing: border-box;
|
||||
border-top: 1px solid #666;
|
||||
border-right: 1px solid #333;
|
||||
border-bottom: 1px solid #333;
|
||||
background-color: #3f3f3f;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
text-shadow: 0px -1px 0 #000;
|
||||
transition: background-color 0.2s linear;
|
||||
}
|
||||
|
||||
/* @override */
|
||||
.button.layers-button {
|
||||
border-left-width: 0;
|
||||
}
|
||||
|
||||
.layers-button:last-child {
|
||||
border-right-width: 0;
|
||||
}
|
||||
|
||||
.layers-button:hover {
|
||||
text-decoration: none;
|
||||
background-color: #484848;
|
||||
color: gold;
|
||||
}
|
||||
/**
|
||||
* User messages
|
||||
*/
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
.tool-icon:hover {
|
||||
background-color: #444;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tool icons:
|
||||
@ -209,6 +209,13 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tool-icon.import-icon {
|
||||
background-image: url(../img/import-icon.png);
|
||||
background-position: 10px 5px;
|
||||
background-size: 26px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.upload-cloud-icon .label {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
BIN
img/import-icon.png
Normal file
BIN
img/import-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 720 B |
@ -9,6 +9,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="css/reset.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/forms.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/settings.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/tools.css">
|
||||
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap.css">
|
||||
@ -45,8 +46,9 @@
|
||||
<iframe src="templates/settings.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
|
||||
<div class="drawer vertical-centerer">
|
||||
<div class="drawer-content" id="drawer-container">
|
||||
<iframe src="templates/settings-application.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings-export-gif.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings/application.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings/export-gif.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
<iframe src="templates/settings/import.html" onload="iframeloader.onLoad(event)" data-iframe-loader="store"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -39,6 +39,9 @@ var Events = {
|
||||
*/
|
||||
USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED",
|
||||
|
||||
/* Listened to by SettingsController */
|
||||
CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER",
|
||||
|
||||
/**
|
||||
* The framesheet was reseted and is now probably drastically different.
|
||||
* Number of frames, content of frames, color used for the palette may have changed.
|
||||
|
@ -33,7 +33,7 @@
|
||||
this.layersListController = new pskl.controller.LayersListController(this.piskelController);
|
||||
this.layersListController.init();
|
||||
|
||||
this.settingsController = new pskl.controller.SettingsController(this.piskelController);
|
||||
this.settingsController = new pskl.controller.settings.SettingsController(this.piskelController);
|
||||
this.settingsController.init();
|
||||
|
||||
this.selectionManager = new pskl.selection.SelectionManager(this.piskelController);
|
||||
@ -94,7 +94,7 @@
|
||||
finishInitAppEngine_ : function () {
|
||||
if (pskl.framesheetData_ && pskl.framesheetData_.content) {
|
||||
var piskel = pskl.utils.Serializer.createPiskel(pskl.framesheetData_.content);
|
||||
piskel.app.PiskelController.setPiskel(piskel);
|
||||
pskl.app.piskelController.setPiskel(piskel);
|
||||
pskl.app.animationController.setFPS(pskl.framesheetData_.fps);
|
||||
}
|
||||
},
|
||||
|
@ -24,9 +24,9 @@
|
||||
];
|
||||
|
||||
ns.GifExportController.prototype.init = function () {
|
||||
this.radioTemplate_ = pskl.utils.Template.get("export-gif-radio-template");
|
||||
this.radioTemplate_ = pskl.utils.Template.get("gif-export-radio-template");
|
||||
|
||||
this.previewContainerEl = document.querySelectorAll(".export-gif-preview div")[0];
|
||||
this.previewContainerEl = document.querySelectorAll(".gif-export-preview")[0];
|
||||
this.radioGroupEl = document.querySelectorAll(".gif-export-radio-group")[0];
|
||||
|
||||
this.uploadForm = $("[name=gif-export-upload-form]");
|
||||
@ -56,7 +56,7 @@
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.updatePreview_ = function (src) {
|
||||
this.previewContainerEl.innerHTML = "<img style='max-width:240px;' src='"+src+"'/>";
|
||||
this.previewContainerEl.innerHTML = "<div><img style='max-width:240px;' src='"+src+"'/></div>";
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.getSelectedDpi_ = function () {
|
||||
|
168
js/controller/settings/ImportController.js
Normal file
168
js/controller/settings/ImportController.js
Normal file
@ -0,0 +1,168 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.settings');
|
||||
var DEFAULT_FILE_STATUS = 'No file selected ...';
|
||||
var PREVIEW_HEIGHT = 60;
|
||||
|
||||
ns.ImportController = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
this.importedImage_ = null;
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.init = function () {
|
||||
this.importForm = $("[name=import-form]");
|
||||
this.hiddenFileInput = $("[name=file-upload-input]");
|
||||
this.fileInputButton = $(".file-input-button");
|
||||
this.fileInputStatus = $(".file-input-status");
|
||||
this.fileInputStatus.html(DEFAULT_FILE_STATUS);
|
||||
|
||||
this.importPreview = $(".import-section-preview");
|
||||
|
||||
this.resizeWidth = $("[name=resize-width]");
|
||||
this.resizeHeight = $("[name=resize-height]");
|
||||
this.smoothResize = $("[name=smooth-resize-checkbox]");
|
||||
this.submitButton = $("[name=import-submit]");
|
||||
|
||||
this.importForm.submit(this.onImportFormSubmit_.bind(this));
|
||||
this.hiddenFileInput.change(this.onFileUploadChange_.bind(this));
|
||||
this.fileInputButton.click(this.onFileInputClick_.bind(this));
|
||||
|
||||
this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width'));
|
||||
this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height'));
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.reset_ = function () {
|
||||
this.importForm.get(0).reset();
|
||||
this.fileInputStatus.html(DEFAULT_FILE_STATUS);
|
||||
$.publish(Events.CLOSE_SETTINGS_DRAWER);
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.onResizeInputKeyUp_ = function (from, evt) {
|
||||
if (this.importedImage_) {
|
||||
this.synchronizeResizeFields_(evt.target.value, from);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.synchronizeResizeFields_ = function (value, from) {
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
value = 0;
|
||||
}
|
||||
var height = this.importedImage_.height, width = this.importedImage_.width;
|
||||
if (from === 'width') {
|
||||
this.resizeHeight.val(Math.round(value * height / width));
|
||||
} else {
|
||||
this.resizeWidth.val(Math.round(value * width / height));
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.onImportFormSubmit_ = function (evt) {
|
||||
evt.originalEvent.preventDefault();
|
||||
this.importImageToPiskel_();
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.onFileUploadChange_ = function (evt) {
|
||||
this.importFromFile_();
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.onFileInputClick_ = function (evt) {
|
||||
this.hiddenFileInput.click();
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.importFromFile_ = function () {
|
||||
var files = this.hiddenFileInput.get(0).files;
|
||||
if (files.length == 1) {
|
||||
var file = files[0];
|
||||
if (this.isImage_(file)) {
|
||||
this.readImageFile_(file);
|
||||
this.enableDisabledSections_();
|
||||
} else {
|
||||
this.reset_();
|
||||
throw "File is not an image : " + file.type;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.enableDisabledSections_ = function () {
|
||||
this.resizeWidth.removeAttr('disabled');
|
||||
this.resizeHeight.removeAttr('disabled');
|
||||
this.smoothResize.removeAttr('disabled');
|
||||
this.submitButton.removeAttr('disabled');
|
||||
|
||||
this.fileInputButton.removeClass('button-primary');
|
||||
this.fileInputButton.blur();
|
||||
|
||||
$('.import-section-disabled').removeClass('import-section-disabled');
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.readImageFile_ = function (imageFile) {
|
||||
pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an image from the given source (url or data-url), and onload forward to onImageLoaded
|
||||
* TODO : should be a generic utility method, should take a callback
|
||||
* @param {String} imageSource url or data-url, will be used as src for the image
|
||||
*/
|
||||
ns.ImportController.prototype.processImageSource_ = function (imageSource) {
|
||||
this.importedImage_ = new Image();
|
||||
this.importedImage_.onload = this.onImageLoaded_.bind(this);
|
||||
this.importedImage_.src = imageSource;
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.onImageLoaded_ = function (evt) {
|
||||
var w = this.importedImage_.width,
|
||||
h = this.importedImage_.height;
|
||||
var filePath = this.hiddenFileInput.val();
|
||||
var fileName = this.extractFileNameFromPath_(filePath);
|
||||
this.fileInputStatus.html(fileName);
|
||||
|
||||
this.resizeWidth.val(w);
|
||||
this.resizeHeight.val(h);
|
||||
|
||||
this.importPreview.width("auto");
|
||||
this.importPreview.append(this.createImagePreview_());
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.createImagePreview_ = function () {
|
||||
var image = document.createElement('IMG');
|
||||
image.src = this.importedImage_.src;
|
||||
image.setAttribute('height', PREVIEW_HEIGHT);
|
||||
return image;
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.extractFileNameFromPath_ = function (path) {
|
||||
var parts = [];
|
||||
if (path.indexOf('/') !== -1) {
|
||||
parts = path.split('/');
|
||||
} else if (path.indexOf('\\') !== -1) {
|
||||
parts = path.split('\\');
|
||||
} else {
|
||||
parts = [path];
|
||||
}
|
||||
return parts[parts.length-1];
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.importImageToPiskel_ = function () {
|
||||
if (this.importedImage_) {
|
||||
if (window.confirm("You are about to create a new Piskel, unsaved changes will be lost.")) {
|
||||
var w = this.resizeWidth.val(),
|
||||
h = this.resizeHeight.val(),
|
||||
smoothing = !!this.smoothResize.prop('checked');
|
||||
|
||||
var image = pskl.utils.ImageResizer.resize(this.importedImage_, w, h, smoothing);
|
||||
var frame = pskl.utils.FrameUtils.createFromImage(image);
|
||||
|
||||
var piskel = pskl.utils.Serializer.createPiskel([frame]);
|
||||
pskl.app.piskelController.setPiskel(piskel);
|
||||
pskl.app.animationController.setFPS(Constants.DEFAULT.FPS);
|
||||
|
||||
this.reset_();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportController.prototype.isImage_ = function (file) {
|
||||
return file.type.indexOf('image') === 0;
|
||||
};
|
||||
|
||||
})();
|
@ -1,14 +1,18 @@
|
||||
(function () {
|
||||
var ns = $.namespace("pskl.controller");
|
||||
|
||||
var ns = $.namespace("pskl.controller.settings");
|
||||
|
||||
var settings = {
|
||||
user : {
|
||||
template : 'templates/settings-application.html',
|
||||
controller : ns.settings.ApplicationSettingsController
|
||||
'user' : {
|
||||
template : 'templates/settings/application.html',
|
||||
controller : ns.ApplicationSettingsController
|
||||
},
|
||||
gif : {
|
||||
template : 'templates/settings-export-gif.html',
|
||||
controller : ns.settings.GifExportController
|
||||
'gif' : {
|
||||
template : 'templates/settings/export-gif.html',
|
||||
controller : ns.GifExportController
|
||||
},
|
||||
'import' : {
|
||||
template : 'templates/settings/import.html',
|
||||
controller : ns.ImportController
|
||||
}
|
||||
};
|
||||
|
||||
@ -44,14 +48,16 @@
|
||||
this.closeDrawer();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
$.subscribe(Events.CLOSE_SETTINGS_DRAWER, this.closeDrawer.bind(this));
|
||||
};
|
||||
|
||||
ns.SettingsController.prototype.loadSetting = function (setting) {
|
||||
this.drawerContainer.innerHTML = pskl.utils.Template.get(settings[setting].template);
|
||||
(new settings[setting].controller(this.piskelController)).init();
|
||||
|
||||
|
||||
this.settingsContainer.addClass(EXP_DRAWER_CLS);
|
||||
|
||||
|
||||
$('.' + SEL_SETTING_CLS).removeClass(SEL_SETTING_CLS);
|
||||
$('[data-setting='+setting+']').addClass(SEL_SETTING_CLS);
|
||||
|
||||
@ -66,5 +72,5 @@
|
||||
this.expanded = false;
|
||||
this.currentSetting = null;
|
||||
};
|
||||
|
||||
|
||||
})();
|
13
js/utils/FileUtils.js
Normal file
13
js/utils/FileUtils.js
Normal file
@ -0,0 +1,13 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.utils');
|
||||
|
||||
ns.FileUtils = {
|
||||
readFile : function (file, callback) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(event){
|
||||
callback(event.target.result);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
};
|
||||
})();
|
@ -20,6 +20,62 @@
|
||||
frameA.setPixel(col, row, p);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a pskl.model.Frame from an Image object.
|
||||
* Transparent pixels will either be converted to completely opaque or completely transparent pixels.
|
||||
* @param {Image} image source image
|
||||
* @return {pskl.model.Frame} corresponding frame
|
||||
*/
|
||||
createFromImage : function (image) {
|
||||
var w = image.width,
|
||||
h = image.height;
|
||||
var canvas = pskl.CanvasUtils.createCanvas(w, h);
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
context.drawImage(image, 0,0,w,h,0,0,w,h);
|
||||
var imgData = context.getImageData(0,0,w,h).data;
|
||||
// Draw the zoomed-up pixels to a different canvas context
|
||||
var frame = [];
|
||||
for (var x=0;x<image.width;++x){
|
||||
frame[x] = [];
|
||||
for (var y=0;y<image.height;++y){
|
||||
// Find the starting index in the one-dimensional image data
|
||||
var i = (y*image.width + x)*4;
|
||||
var r = imgData[i ];
|
||||
var g = imgData[i+1];
|
||||
var b = imgData[i+2];
|
||||
var a = imgData[i+3];
|
||||
if (a < 125) {
|
||||
frame[x][y] = "TRANSPARENT";
|
||||
} else {
|
||||
frame[x][y] = this.rgbToHex(r,g,b);
|
||||
}
|
||||
}
|
||||
}
|
||||
return frame;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a rgb(Number, Number, Number) color to hexadecimal representation
|
||||
* @param {Number} r red value, between 0 and 255
|
||||
* @param {Number} g green value, between 0 and 255
|
||||
* @param {Number} b blue value, between 0 and 255
|
||||
* @return {String} hex representation of the color '#ABCDEF'
|
||||
*/
|
||||
rgbToHex : function (r, g, b) {
|
||||
return "#" + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a color component (as a Number between 0 and 255) to its string hexa representation
|
||||
* @param {Number} c component value, between 0 and 255
|
||||
* @return {String} eg. '0A'
|
||||
*/
|
||||
componentToHex : function (c) {
|
||||
var hex = c.toString(16);
|
||||
return hex.length == 1 ? "0" + hex : hex;
|
||||
}
|
||||
};
|
||||
})();
|
||||
})();
|
||||
|
30
js/utils/ImageResizer.js
Normal file
30
js/utils/ImageResizer.js
Normal file
@ -0,0 +1,30 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.utils');
|
||||
|
||||
ns.ImageResizer = {
|
||||
resize : function (image, targetWidth, targetHeight, smoothingEnabled) {
|
||||
var canvas = pskl.CanvasUtils.createCanvas(targetWidth, targetHeight);
|
||||
var context = canvas.getContext('2d');
|
||||
context.save();
|
||||
|
||||
if (!smoothingEnabled) {
|
||||
this.disableSmoothingOnContext(context);
|
||||
}
|
||||
|
||||
context.translate(canvas.width / 2, canvas.height / 2);
|
||||
context.scale(targetWidth / image.width, targetHeight / image.height);
|
||||
context.drawImage(image, -image.width / 2, -image.height / 2);
|
||||
context.restore();
|
||||
|
||||
return canvas;
|
||||
},
|
||||
|
||||
disableSmoothingOnContext : function (context) {
|
||||
context.imageSmoothingEnabled = false;
|
||||
context.mozImageSmoothingEnabled = false;
|
||||
context.oImageSmoothingEnabled = false;
|
||||
context.webkitImageSmoothingEnabled = false;
|
||||
context.msImageSmoothingEnabled = false;
|
||||
}
|
||||
};
|
||||
})();
|
@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
var ns = $.namespace("pskl");
|
||||
var ns = $.namespace("pskl.utils");
|
||||
|
||||
ns.utils.Template = {
|
||||
ns.Template = {
|
||||
get : function (templateId) {
|
||||
var template = document.getElementById(templateId);
|
||||
if (template) {
|
||||
|
@ -14,7 +14,9 @@ exports.scripts = [
|
||||
// Libraries
|
||||
"js/utils/core.js",
|
||||
"js/utils/CanvasUtils.js",
|
||||
"js/utils/FileUtils.js",
|
||||
"js/utils/FrameUtils.js",
|
||||
"js/utils/ImageResizer.js",
|
||||
"js/utils/PixelUtils.js",
|
||||
"js/utils/Serializer.js",
|
||||
"js/utils/Template.js",
|
||||
@ -49,9 +51,13 @@ exports.scripts = [
|
||||
"js/controller/ToolController.js",
|
||||
"js/controller/PaletteController.js",
|
||||
"js/controller/NotificationController.js",
|
||||
|
||||
// Settings sub-controllers
|
||||
"js/controller/settings/ApplicationSettingsController.js",
|
||||
"js/controller/settings/GifExportController.js",
|
||||
"js/controller/SettingsController.js",
|
||||
"js/controller/settings/ImportController.js",
|
||||
// Settings controller
|
||||
"js/controller/settings/SettingsController.js",
|
||||
|
||||
// Services
|
||||
"js/service/LocalStorageService.js",
|
||||
|
105
resources/import-icon.svg
Normal file
105
resources/import-icon.svg
Normal file
@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="744.09448819"
|
||||
height="1052.3622047"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
inkscape:export-filename="C:\Users\Julian\Desktop\import-icon.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"
|
||||
sodipodi:docname="New document 1">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient3776"
|
||||
osb:paint="solid">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3778" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.959798"
|
||||
inkscape:cx="211.98241"
|
||||
inkscape:cy="421.19661"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g3937"
|
||||
showgrid="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:object-nodes="false"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1148"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<g
|
||||
id="g3937"
|
||||
transform="matrix(0.09331433,0,0,0.09331433,132.76469,588.24921)"
|
||||
style="stroke:#ffffff;stroke-opacity:1">
|
||||
<g
|
||||
id="g3959"
|
||||
inkscape:export-filename="C:\Users\Julian\Desktop\import-icon.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<rect
|
||||
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:30;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect2985"
|
||||
width="384.28558"
|
||||
height="384.28564"
|
||||
x="161.42857"
|
||||
y="249.50504"
|
||||
ry="45.714287" />
|
||||
<g
|
||||
transform="matrix(1.1961461,0,0,2.4281875,-3.7905251,90.097124)"
|
||||
id="g3765"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-opacity:1">
|
||||
<g
|
||||
id="g3769"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-opacity:1">
|
||||
<path
|
||||
sodipodi:nodetypes="cccczscscc"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 400,142.55868 -100,56.94635 -100,-57.33935 60,0.1965 c 0,0 0,-84.96745 0,-107.61226 0,-22.64481 55.79903,-25.2405808 80.01042,-22.177879 38.98433,4.931455 46.17248,30.649944 46.17248,30.649944 0,0 -46.97367,-31.662831 -46.18302,0.888182 0.65678,27.039499 0,98.252013 0,98.252013 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:6;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect3758" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
@ -1,10 +1,10 @@
|
||||
<div class="layers-list-container">
|
||||
<h3 class="layers-title">Layers</h3>
|
||||
<div class="layers-button-container">
|
||||
<button class="layers-button" data-action="add" >Add</button>
|
||||
<button class="layers-button" data-action="delete" >Delete</button>
|
||||
<button class="layers-button layers-button-arrow" data-action="up" >↑</button>
|
||||
<button class="layers-button layers-button-arrow" data-action="down" >↓</button>
|
||||
<button class="button layers-button" data-action="add" >Add</button>
|
||||
<button class="button layers-button" data-action="delete" >Delete</button>
|
||||
<button class="button layers-button layers-button-arrow" data-action="up" >↑</button>
|
||||
<button class="button layers-button layers-button-arrow" data-action="down" >↓</button>
|
||||
</div>
|
||||
<script type="text/template" id="layer-item-template">
|
||||
<li class="layer-item" data-layer-name="{{layername}}">{{layername}}</li>
|
||||
|
@ -3,19 +3,29 @@
|
||||
data-setting="user"
|
||||
class="tool-icon gear-icon"
|
||||
title="Preferences"
|
||||
rel="tooltip" data-placement="left"></div>
|
||||
rel="tooltip" data-placement="left">
|
||||
</div>
|
||||
|
||||
<a
|
||||
<div
|
||||
data-setting="import"
|
||||
class="tool-icon import-icon"
|
||||
title="Import an existing picture"
|
||||
rel="tooltip" data-placement="left">
|
||||
</div>
|
||||
|
||||
<!-- <a
|
||||
class="tool-icon gallery-icon"
|
||||
title="Visit gallery"
|
||||
href="http://juliandescottes.github.io/piskel-website/"
|
||||
rel="tooltip" data-placement="left" target="_blank"></a>
|
||||
rel="tooltip" data-placement="left" target="_blank">
|
||||
</a> -->
|
||||
|
||||
<div
|
||||
class="tool-icon save-icon"
|
||||
title="Save to gallery"
|
||||
onclick="pskl.app.storeSheet()"
|
||||
rel="tooltip" data-placement="left" ></div>
|
||||
rel="tooltip" data-placement="left" >
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-setting="gif"
|
||||
|
@ -5,13 +5,14 @@
|
||||
<div class="settings-item">
|
||||
<label>Select resolution:</label>
|
||||
<form action="" method="POST" name="gif-export-upload-form">
|
||||
<script type="text/template" id="export-gif-radio-template">
|
||||
<script type="text/template" id="gif-export-radio-template">
|
||||
<label style="display:block"><input type="radio" name="gif-dpi" value="{{value}}"/>
|
||||
{{label}}</label>
|
||||
</script>
|
||||
<div class="gif-export-radio-group"></div>
|
||||
<input type="submit" class="export-gif-upload-button" value="Upload" />
|
||||
<input type="submit" class="button button-primary gif-upload-button" value="Upload" />
|
||||
<button type="button" class="button gif-render-button">Render</button>
|
||||
</form>
|
||||
<div class="export-gif-preview"><div></div></div>
|
||||
<div class="gif-export-preview"></div>
|
||||
</div>
|
||||
</div>
|
31
templates/settings/import.html
Normal file
31
templates/settings/import.html
Normal file
@ -0,0 +1,31 @@
|
||||
<div class="settings-section">
|
||||
<div class="settings-title">
|
||||
Import Picture
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<form action="" method="POST" name="import-form">
|
||||
<div class="import-section">
|
||||
<span class="import-section-title">File :</span>
|
||||
<button type="button" class="button button-primary file-input-button">Browse</button>
|
||||
<span class="file-input-status"></span>
|
||||
<input style="display:none"
|
||||
type="file" name="file-upload-input"
|
||||
value="file" accept="image/*"/>
|
||||
</div>
|
||||
<div class="import-section import-section-disabled">
|
||||
<span class="import-section-title" style="vertical-align:top">Preview :</span>
|
||||
<div class="import-section-preview"></div>
|
||||
</div>
|
||||
<div class="import-section import-section-disabled">
|
||||
<span class="import-section-title">Size :</span>
|
||||
<input type="text" disabled="disabled" class="textfield import-resize-field" name="resize-width"/>x
|
||||
<input type="text" disabled="disabled" class="textfield import-resize-field" name="resize-height"/>
|
||||
</div>
|
||||
<div class="import-section import-section-disabled">
|
||||
<span class="import-section-title">Smooth resize :</span>
|
||||
<input type="checkbox" disabled="disabled" checked="checked" name="smooth-resize-checkbox" value="1"/>
|
||||
</div>
|
||||
<input type="submit" name="import-submit" disabled="disabled" class="button button-primary import-button" value="Import" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
Loading…
x
Reference in New Issue
Block a user