Add miniPaint as new frontend base
This commit is contained in:
@@ -0,0 +1,305 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_gui_class from './../../core/base-gui.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Dialog_class from './../../libs/popup.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
import alertify from './../../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
|
||||
var instance = null;
|
||||
|
||||
class Image_trim_class {
|
||||
|
||||
constructor() {
|
||||
//singleton
|
||||
if (instance) {
|
||||
return instance;
|
||||
}
|
||||
instance = this;
|
||||
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Base_gui = new Base_gui_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.Dialog = new Dialog_class();
|
||||
|
||||
this.set_events();
|
||||
}
|
||||
|
||||
set_events() {
|
||||
document.addEventListener('keydown', (event) => {
|
||||
var code = event.keyCode;
|
||||
if (this.Helper.is_input(event.target))
|
||||
return;
|
||||
|
||||
if (code == 84) {
|
||||
//trim
|
||||
this.trim();
|
||||
event.preventDefault();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
trim() {
|
||||
var _this = this;
|
||||
var removeWhiteColor = false;
|
||||
if(config.TRANSPARENCY == false)
|
||||
removeWhiteColor = true;
|
||||
|
||||
var settings = {
|
||||
title: 'Trim',
|
||||
params: [
|
||||
{name: "trim_layer", title: "Trim layer:", value: true},
|
||||
{name: "trim_all", title: "Trim borders:", value: true},
|
||||
{name: "power", title: "Power:", value: 0, max: 255},
|
||||
{name: "remove_white", title: "Trim white color?", value: removeWhiteColor},
|
||||
],
|
||||
on_finish: async (params) => {
|
||||
if (params.trim_layer == true) {
|
||||
//first trim
|
||||
let actions = [];
|
||||
actions = actions.concat(this.trim_layer(config.layer.id, params.remove_white, params.power));
|
||||
await app.State.do_action(
|
||||
new app.Actions.Bundle_action('trim_layers', 'Trim Layers', actions)
|
||||
);
|
||||
}
|
||||
if (params.trim_all == true) {
|
||||
//second trim
|
||||
let actions = [];
|
||||
actions = actions.concat(_this.trim_all(params.remove_white, params.power));
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('trim_layers', 'Trim Layers', actions)
|
||||
);
|
||||
}
|
||||
},
|
||||
};
|
||||
this.Dialog.show(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* removes empty (white/transparent) area from top, right, bottom and left sides
|
||||
* This affects layer data
|
||||
*
|
||||
* @param layer_id
|
||||
* @param removeWhiteColor
|
||||
* @param {int} power
|
||||
*/
|
||||
trim_layer(layer_id, removeWhiteColor = false, power = 0) {
|
||||
var layer = this.Base_layers.get_layer(layer_id);
|
||||
|
||||
if (layer.type != 'image') {
|
||||
alertify.error('Skip - layer must be image.');
|
||||
return false;
|
||||
}
|
||||
|
||||
var trim = this.get_trim_info(layer_id, removeWhiteColor, power);
|
||||
trim = trim.relative;
|
||||
|
||||
//if image was stretched
|
||||
var width_ratio = (layer.width / layer.width_original);
|
||||
var height_ratio = (layer.height / layer.height_original);
|
||||
|
||||
//create smaller canvas
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext("2d");
|
||||
canvas.width = trim.width / width_ratio;
|
||||
canvas.height = trim.height / height_ratio;
|
||||
|
||||
//cut required part
|
||||
ctx.translate(-trim.left / width_ratio, -trim.top / height_ratio);
|
||||
canvas.getContext("2d").drawImage(layer.link, 0, 0);
|
||||
ctx.translate(0, 0);
|
||||
|
||||
return [
|
||||
new app.Actions.Update_layer_image_action(canvas, layer.id),
|
||||
new app.Actions.Update_layer_action(layer.id, {
|
||||
x: layer.x + trim.left,
|
||||
y: layer.y + trim.top,
|
||||
width: Math.ceil(canvas.width * width_ratio),
|
||||
height: Math.ceil(canvas.height * height_ratio),
|
||||
width_original: canvas.width,
|
||||
height_original: canvas.height
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* change canvas size, so there is no empty (white/transparent) areas on top, right, bottom and left sides
|
||||
* this affect canvas size and all layers positions
|
||||
*
|
||||
* @param removeWhiteColor
|
||||
* @param {int} power
|
||||
*/
|
||||
trim_all(removeWhiteColor = false, power = 0) {
|
||||
let actions = [];
|
||||
|
||||
var all_top = config.HEIGHT;
|
||||
var all_left = config.WIDTH;
|
||||
var all_bottom = config.HEIGHT;
|
||||
var all_right = config.WIDTH;
|
||||
|
||||
if (removeWhiteColor == undefined) {
|
||||
removeWhiteColor = false;
|
||||
if (config.TRANSPARENCY == false) {
|
||||
removeWhiteColor = true;
|
||||
}
|
||||
}
|
||||
|
||||
//collect info
|
||||
for (let i = 0; i < config.layers.length; i++) {
|
||||
let layer = config.layers[i];
|
||||
|
||||
if (layer.width == null || layer.height == null || layer.x == null || layer.y == null) {
|
||||
//layer without dimensions
|
||||
const trim_info = this.get_trim_info(layer.id, removeWhiteColor, power);
|
||||
|
||||
all_top = Math.min(all_top, trim_info.top);
|
||||
all_left = Math.min(all_left, trim_info.left);
|
||||
all_bottom = Math.min(all_bottom, trim_info.bottom);
|
||||
all_right = Math.min(all_right, trim_info.right);
|
||||
}
|
||||
else{
|
||||
all_top = Math.min(all_top, layer.y);
|
||||
all_left = Math.min(all_left, layer.x);
|
||||
all_bottom = Math.min(all_bottom, config.HEIGHT - layer.height - layer.y);
|
||||
all_right = Math.min(all_right, config.WIDTH - layer.width - layer.x);
|
||||
}
|
||||
}
|
||||
|
||||
//move every layer
|
||||
for (let i = 0; i < config.layers.length; i++) {
|
||||
let layer = config.layers[i];
|
||||
if (layer.x == null || layer.y == null || layer.type == null)
|
||||
continue;
|
||||
|
||||
actions.push(
|
||||
new app.Actions.Update_layer_action(layer.id, {
|
||||
x: layer.x - all_left,
|
||||
y: layer.y - all_top
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
//resize
|
||||
actions.push(
|
||||
new app.Actions.Prepare_canvas_action('undo'),
|
||||
new app.Actions.Update_config_action({
|
||||
WIDTH: Math.max(1, config.WIDTH - all_left - all_right),
|
||||
HEIGHT: Math.max(1, config.HEIGHT - all_top - all_bottom)
|
||||
}),
|
||||
new app.Actions.Prepare_canvas_action('do')
|
||||
);
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* get painted area coords
|
||||
*
|
||||
* @param {int} layer_id
|
||||
* @param {boolean} trim_white
|
||||
* @param {int} power
|
||||
* @returns {object} keys: top, left, bottom, right, width, height, relative
|
||||
*/
|
||||
get_trim_info(layer_id, trim_white, power) {
|
||||
if (trim_white == undefined) {
|
||||
trim_white = false;
|
||||
if (config.TRANSPARENCY == false) {
|
||||
trim_white = true;
|
||||
}
|
||||
}
|
||||
if (power == undefined) {
|
||||
power = 0;
|
||||
}
|
||||
var layer = this.Base_layers.get_layer(layer_id);
|
||||
|
||||
var canvas = this.Base_layers.convert_layer_to_canvas(layer_id, null, false);
|
||||
var ctx = canvas.getContext("2d");
|
||||
var img = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
var imgData = img.data;
|
||||
|
||||
var top = 0;
|
||||
var left = 0;
|
||||
var bottom = 0;
|
||||
var right = 0;
|
||||
|
||||
//check top
|
||||
main1:
|
||||
for (var y = 0; y < img.height; y++) {
|
||||
for (var x = 0; x < img.width; x++) {
|
||||
var k = ((y * (img.width * 4)) + (x * 4));
|
||||
if (imgData[k + 3] <= power)
|
||||
continue; //transparent
|
||||
if (trim_white == true && imgData[k] >= 255 - power && imgData[k + 1] >= 255 - power
|
||||
&& imgData[k + 2] >= 255 - power)
|
||||
continue; //white
|
||||
break main1;
|
||||
}
|
||||
top++;
|
||||
}
|
||||
//check left
|
||||
main2:
|
||||
for (var x = 0; x < img.width; x++) {
|
||||
for (var y = 0; y < img.height; y++) {
|
||||
var k = ((y * (img.width * 4)) + (x * 4));
|
||||
if (imgData[k + 3] <= power)
|
||||
continue; //transparent
|
||||
if (trim_white == true && imgData[k] >= 255 - power && imgData[k + 1] >= 255 - power
|
||||
&& imgData[k + 2] >= 255 - power)
|
||||
continue; //white
|
||||
break main2;
|
||||
}
|
||||
left++;
|
||||
}
|
||||
//check bottom
|
||||
main3:
|
||||
for (var y = img.height - 1; y >= 0; y--) {
|
||||
for (var x = img.width - 1; x >= 0; x--) {
|
||||
var k = ((y * (img.width * 4)) + (x * 4));
|
||||
if (imgData[k + 3] <= power)
|
||||
continue; //transparent
|
||||
if (trim_white == true && imgData[k] >= 255 - power && imgData[k + 1] >= 255 - power
|
||||
&& imgData[k + 2] >= 255 - power)
|
||||
continue; //white
|
||||
break main3;
|
||||
}
|
||||
bottom++;
|
||||
}
|
||||
//check right
|
||||
main4:
|
||||
for (var x = img.width - 1; x >= 0; x--) {
|
||||
for (var y = img.height - 1; y >= 0; y--) {
|
||||
var k = ((y * (img.width * 4)) + (x * 4));
|
||||
if (imgData[k + 3] <= power)
|
||||
continue; //transparent
|
||||
if (trim_white == true && imgData[k] >= 255 - power && imgData[k + 1] >= 255 - power
|
||||
&& imgData[k + 2] >= 255 - power)
|
||||
continue; //white
|
||||
break main4;
|
||||
}
|
||||
right++;
|
||||
}
|
||||
|
||||
var top_rel = top - layer.y;
|
||||
var left_rel = left - layer.x;
|
||||
var bottom_rel = bottom - (config.HEIGHT - layer.y - layer.height);
|
||||
var right_rel = right - (config.WIDTH - layer.x - layer.width);
|
||||
|
||||
return {
|
||||
top: top,
|
||||
left: left,
|
||||
bottom: bottom,
|
||||
right: right,
|
||||
width: canvas.width - left - right,
|
||||
height: canvas.height - top - bottom,
|
||||
relative: {
|
||||
top: top_rel,
|
||||
left: left_rel,
|
||||
bottom: bottom_rel,
|
||||
right: right_rel,
|
||||
width: canvas.width - left - right,
|
||||
height: canvas.height - top - bottom,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default Image_trim_class;
|
||||
Reference in New Issue
Block a user