paintplus: vendor the app source and rename from EditmaskwithAI
Bring the full EditmaskwithAI application into the repo under paintplus/ (429 files) so the service is self-contained — the installer copies the vendored source to ~/docker/paintplus/src instead of cloning at runtime. Rename to PaintPlus (service + branding; app logic untouched): - services/editmaskwithai.sh -> services/paintplus.sh (register_service paintplus, install_paintplus, ~/docker/paintplus, Caddy paintplus:8000, Authelia option preserved) - container names -> paintplus across docker-compose*.yml; dev network -> paintplus-network - browser <title> -> "PaintPlus - AI Image Editor"; README heading -> PaintPlus with upstream provenance note - README utilities table: editmaskwithai -> paintplus Backend/frontend code (help strings referencing the old container name, the ai_photo_edit.db filename) is intentionally left as-is to avoid touching application logic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nb2vJ8W7bHKx1JXVvpCraH
This commit is contained in:
@@ -0,0 +1,708 @@
|
||||
import app from './../../app.js';
|
||||
import config from './../../config.js';
|
||||
import Base_layers_class from './../../core/base-layers.js';
|
||||
import Base_gui_class from './../../core/base-gui.js';
|
||||
import Dialog_class from './../../libs/popup.js';
|
||||
import Helper_class from './../../libs/helpers.js';
|
||||
import Clipboard_class from './../../libs/clipboard.js';
|
||||
import alertify from './../../../../node_modules/alertifyjs/build/alertify.min.js';
|
||||
import EXIF from './../../../../node_modules/exif-js/exif.js';
|
||||
import GUI_tools_class from "../../core/gui/gui-tools";
|
||||
import semver_compare from './../../../../node_modules/semver-compare/';
|
||||
|
||||
var instance = null;
|
||||
|
||||
/**
|
||||
* manages files / open
|
||||
*
|
||||
* @author ViliusL
|
||||
*/
|
||||
class File_open_class {
|
||||
|
||||
constructor() {
|
||||
//singleton
|
||||
if (instance) {
|
||||
return instance;
|
||||
}
|
||||
instance = this;
|
||||
|
||||
var _this = this;
|
||||
this.POP = new Dialog_class();
|
||||
this.Base_layers = new Base_layers_class();
|
||||
this.Base_gui = new Base_gui_class();
|
||||
this.Helper = new Helper_class();
|
||||
this.GUI_tools = new GUI_tools_class();
|
||||
|
||||
//clipboard class
|
||||
this.Clipboard_class = new Clipboard_class(function (data, w, h) {
|
||||
_this.on_paste(data, w, h);
|
||||
});
|
||||
|
||||
this.events();
|
||||
|
||||
this.maybe_file_open_url_handler();
|
||||
}
|
||||
|
||||
events() {
|
||||
var _this = this;
|
||||
|
||||
window.ondrop = function (e) {
|
||||
//drop
|
||||
e.preventDefault();
|
||||
_this.open_handler(e);
|
||||
};
|
||||
window.ondragover = function (e) {
|
||||
e.preventDefault();
|
||||
};
|
||||
document.addEventListener('keydown', (event) => {
|
||||
var code = event.key.toLowerCase();
|
||||
if (this.Helper.is_input(event.target))
|
||||
return;
|
||||
|
||||
if (code == "o") {
|
||||
//open
|
||||
this.open_file();
|
||||
event.preventDefault();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
on_paste(data, width, height) {
|
||||
var new_layer = {
|
||||
name: 'Paste',
|
||||
type: 'image',
|
||||
data: data,
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Insert_layer_action(new_layer)
|
||||
);
|
||||
}
|
||||
|
||||
open_file() {
|
||||
var _this = this;
|
||||
|
||||
alertify.success('You can also drag and drop items into browser.');
|
||||
|
||||
document.getElementById("tmp").innerHTML = '';
|
||||
var a = document.createElement('input');
|
||||
a.setAttribute("id", "file_open");
|
||||
a.type = 'file';
|
||||
a.multiple = 'multiple';
|
||||
document.getElementById("tmp").appendChild(a);
|
||||
document.getElementById('file_open').addEventListener('change', function (e) {
|
||||
_this.open_handler(e);
|
||||
}, false);
|
||||
|
||||
//force click
|
||||
document.querySelector('#file_open').click();
|
||||
}
|
||||
|
||||
open_webcam(){
|
||||
var _this = this;
|
||||
var video = document.createElement('video');
|
||||
video.autoplay = true;
|
||||
video.style.maxWidth = '100%';
|
||||
var track = null;
|
||||
|
||||
function handleSuccess(stream) {
|
||||
track = stream.getTracks()[0];
|
||||
video.srcObject = stream;
|
||||
}
|
||||
|
||||
function handleError(error) {
|
||||
alertify.error('Sorry, cold not load getUserMedia() data: ' + error);
|
||||
}
|
||||
|
||||
var settings = {
|
||||
title: 'Webcam',
|
||||
params: [
|
||||
{title: "Stream:", html: '<div id="webcam_container"></div>'},
|
||||
],
|
||||
on_load: function(params){
|
||||
document.getElementById('webcam_container').appendChild(video);
|
||||
},
|
||||
on_finish: function(params){
|
||||
//capture data
|
||||
var width = video.videoWidth;
|
||||
var height = video.videoHeight;
|
||||
|
||||
var tmpCanvas = document.createElement('canvas');
|
||||
var tmpCanvasCtx = tmpCanvas.getContext("2d");
|
||||
tmpCanvas.width = width;
|
||||
tmpCanvas.height = height;
|
||||
tmpCanvasCtx.drawImage(video, 0, 0);
|
||||
|
||||
//create requested layer
|
||||
var new_layer = {
|
||||
name: "Webcam #" + _this.Base_layers.auto_increment,
|
||||
type: 'image',
|
||||
data: tmpCanvas.toDataURL("image/png"),
|
||||
width: width,
|
||||
height: height,
|
||||
width_original: width,
|
||||
height_original: height,
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_file_webcam', 'Open File Webcam', [
|
||||
new app.Actions.Insert_layer_action(new_layer),
|
||||
new app.Actions.Autoresize_canvas_action(width, height, null, true, true)
|
||||
])
|
||||
);
|
||||
|
||||
//destroy
|
||||
if(track != null){
|
||||
track.stop();
|
||||
}
|
||||
video.pause();
|
||||
video.src = "";
|
||||
video.load();
|
||||
},
|
||||
on_cancel: function(params){
|
||||
if(track != null){
|
||||
track.stop();
|
||||
}
|
||||
video.pause();
|
||||
video.src = "";
|
||||
video.load();
|
||||
},
|
||||
};
|
||||
this.POP.show(settings);
|
||||
|
||||
navigator.mediaDevices.getUserMedia({audio: false, video: true})
|
||||
.then(handleSuccess)
|
||||
.catch(handleError);
|
||||
}
|
||||
|
||||
open_dir() {
|
||||
var _this = this;
|
||||
|
||||
document.getElementById("tmp").innerHTML = '';
|
||||
var a = document.createElement('input');
|
||||
a.setAttribute("id", "file_open_dir");
|
||||
a.type = 'file';
|
||||
a.webkitdirectory = 'webkitdirectory';
|
||||
document.getElementById("tmp").appendChild(a);
|
||||
document.getElementById('file_open_dir').addEventListener('change', function (e) {
|
||||
_this.open_handler(e);
|
||||
}, false);
|
||||
|
||||
//force click
|
||||
document.querySelector('#file_open_dir').click();
|
||||
}
|
||||
|
||||
/**
|
||||
* opens data URLs, like: "data:image/png;base64,xxxxxx"
|
||||
*
|
||||
* data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAG0lEQVQYV2N89+7df0FBQQbG/////3///j0DAF9wCsg9spQfAAAAAElFTkSuQmCC
|
||||
*/
|
||||
open_data_url() {
|
||||
var _this = this;
|
||||
|
||||
var settings = {
|
||||
title: 'Open data URL',
|
||||
params: [
|
||||
{name: "data", title: "Data URL:", type: "textarea", value: ""},
|
||||
],
|
||||
on_finish: function (params) {
|
||||
_this.file_open_data_url_handler(params.data);
|
||||
},
|
||||
};
|
||||
this.POP.show(settings);
|
||||
}
|
||||
|
||||
file_open_data_url_handler(data) {
|
||||
var _this = this;
|
||||
if (data == '')
|
||||
return;
|
||||
|
||||
var img = new Image();
|
||||
img.crossOrigin = "Anonymous";
|
||||
img.onload = function () {
|
||||
var new_layer = {
|
||||
name: "Data URL",
|
||||
type: 'image',
|
||||
link: img,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
width_original: img.width,
|
||||
height_original: img.height,
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_file_data_url', 'Open File Data URL', [
|
||||
new app.Actions.Insert_layer_action(new_layer),
|
||||
new app.Actions.Autoresize_canvas_action(img.width, img.height, null, true, true)
|
||||
])
|
||||
);
|
||||
img.onload = function () {
|
||||
config.need_render = true;
|
||||
};
|
||||
};
|
||||
img.onerror = function (ex) {
|
||||
alertify.error('Sorry, image could not be loaded. Try copy image and paste it.');
|
||||
};
|
||||
img.src = data;
|
||||
}
|
||||
|
||||
open_url() {
|
||||
var _this = this;
|
||||
|
||||
var settings = {
|
||||
title: 'Open URL',
|
||||
params: [
|
||||
{name: "url", title: "URL:", value: ""},
|
||||
],
|
||||
on_finish: function (params) {
|
||||
_this.file_open_url_handler(params);
|
||||
},
|
||||
};
|
||||
this.POP.show(settings);
|
||||
}
|
||||
|
||||
async open_handler(e) {
|
||||
var _this = this;
|
||||
var files = e.target.files;
|
||||
|
||||
var auto_increment = this.Base_layers.auto_increment;
|
||||
|
||||
if (files == undefined) {
|
||||
//drag and drop
|
||||
files = e.dataTransfer.files;
|
||||
}
|
||||
|
||||
//sort
|
||||
var orders = [];
|
||||
for (var i = 0, f; i < files.length; i++) {
|
||||
orders.push(files[i].name);
|
||||
}
|
||||
orders.sort();
|
||||
var order_map = [];
|
||||
for (var i in orders) {
|
||||
order_map[orders[i]] = parseInt(i);
|
||||
}
|
||||
|
||||
//check if dropped directory
|
||||
var dir_opened = false;
|
||||
if (e.dataTransfer && e.dataTransfer.items) {
|
||||
var items = e.dataTransfer.items;
|
||||
for (var i=0; i<items.length; i++) {
|
||||
var item = items[i].webkitGetAsEntry();
|
||||
if(item && item.isDirectory){
|
||||
dir_opened = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0, f; i < files.length; i++) {
|
||||
f = files[i];
|
||||
if (!f.type.match('image.*') && !f.name.match('.json')) {
|
||||
if(dir_opened == false) {
|
||||
alertify.error('Wrong file type, must be image or json.');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (files.length == 1) {
|
||||
this.SAVE_NAME = f.name.split('.')[f.name.split('.').length - 2];
|
||||
}
|
||||
|
||||
var FR = new FileReader();
|
||||
FR.file = files[i];
|
||||
|
||||
FR.onload = function (event) {
|
||||
if (this.file.type.match('image.*')) {
|
||||
var order = auto_increment + order_map[this.file.name];
|
||||
//image
|
||||
var new_layer = {
|
||||
name: this.file.name,
|
||||
type: 'image',
|
||||
data: event.target.result,
|
||||
order: order,
|
||||
_exif: _this.extract_exif(this.file)
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_image', 'Open Image', [
|
||||
new app.Actions.Insert_layer_action(new_layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
else {
|
||||
//json
|
||||
var response = _this.load_json(event.target.result);
|
||||
if (response === true) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
if (f.type == "text/plain")
|
||||
FR.readAsText(f);
|
||||
else if (f.name.match('.json'))
|
||||
FR.readAsText(f);
|
||||
else
|
||||
FR.readAsDataURL(f);
|
||||
|
||||
//sleep after last image import, it maybe not be finished yet
|
||||
await new Promise(r => setTimeout(r, 10));
|
||||
}
|
||||
|
||||
//try to open dropped directory
|
||||
if (e.dataTransfer && e.dataTransfer.items) {
|
||||
var items = e.dataTransfer.items;
|
||||
for (var i=0; i<items.length; i++) {
|
||||
var item = items[i].webkitGetAsEntry();
|
||||
if (item && item.isDirectory == true) {
|
||||
this.traverseFileTree(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traverseFileTree(item, path) {
|
||||
var _this = this;
|
||||
var auto_increment = this.Base_layers.auto_increment;
|
||||
|
||||
path = path || "";
|
||||
if (item.isFile) {
|
||||
item.file(async function(file) {
|
||||
var FR = new FileReader();
|
||||
FR.file = file;
|
||||
|
||||
FR.onload = function (event) {
|
||||
if (this.file.type.match('image.*')
|
||||
//below is fix for firefox, it has empty type
|
||||
|| (this.file.type == '' && this.file.name.match(/\.(png|jpg|jpeg|webp|gif|avif)/g))) {
|
||||
//image
|
||||
var new_layer = {
|
||||
name: this.file.name,
|
||||
type: 'image',
|
||||
data: event.target.result,
|
||||
_exif: _this.extract_exif(this.file)
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_image', 'Open Image', [
|
||||
new app.Actions.Insert_layer_action(new_layer)
|
||||
])
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
FR.readAsDataURL(file);
|
||||
|
||||
//sleep after last image import, it maybe not be finished yet
|
||||
await new Promise(r => setTimeout(r, 10));
|
||||
|
||||
});
|
||||
}
|
||||
else if (item.isDirectory) {
|
||||
// Get folder contents
|
||||
var dirReader = item.createReader();
|
||||
dirReader.readEntries(function(entries) {
|
||||
for (var i=0; i<entries.length; i++) {
|
||||
_this.traverseFileTree(entries[i], path + item.name + "/");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
open_template_test(){
|
||||
var _this = this;
|
||||
|
||||
this.Base_layers.debug_rendering = true;
|
||||
|
||||
window.fetch("images/test-collection.json").then(function(response) {
|
||||
return response.json();
|
||||
}).then(function(json) {
|
||||
_this.load_json(json, false);
|
||||
}).catch(function(ex) {
|
||||
alertify.error('Sorry, image could not be loaded.');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* check if url has url params, for example: https://viliusle.github.io/miniPaint/?image=http://i.imgur.com/ATda8Ae.jpg
|
||||
*/
|
||||
maybe_file_open_url_handler() {
|
||||
var _this = this;
|
||||
var url_params = this.Helper.get_url_parameters();
|
||||
|
||||
if (url_params.image != undefined) {
|
||||
this.open_resource(url_params.image);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* includes provided resource (image or json)
|
||||
*
|
||||
* @param string resource_url
|
||||
*/
|
||||
open_resource(resource_url) {
|
||||
var _this = this;
|
||||
|
||||
if(resource_url.toLowerCase().indexOf('.json') == resource_url.length - 5){
|
||||
//load json
|
||||
window.fetch(resource_url).then(function(response) {
|
||||
return response.json();
|
||||
}).then(function(json) {
|
||||
_this.load_json(json, false);
|
||||
}).catch(function(ex) {
|
||||
alertify.error('Sorry, image could not be loaded.');
|
||||
});
|
||||
}
|
||||
else{
|
||||
//load image
|
||||
var data = {
|
||||
url: resource_url,
|
||||
};
|
||||
this.file_open_url_handler(data);
|
||||
}
|
||||
}
|
||||
|
||||
//handler for open url. Example url: http://i.imgur.com/ATda8Ae.jpg
|
||||
file_open_url_handler(user_response) {
|
||||
var _this = this;
|
||||
var url = user_response.url;
|
||||
if (url == '')
|
||||
return;
|
||||
|
||||
var layer_name = url.replace(/^.*[\\\/]/, '');
|
||||
|
||||
var img = new Image();
|
||||
img.crossOrigin = "Anonymous";
|
||||
img.onload = function () {
|
||||
var new_layer = {
|
||||
name: layer_name,
|
||||
type: 'image',
|
||||
link: img,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
width_original: img.width,
|
||||
height_original: img.height,
|
||||
};
|
||||
img.onload = function () {
|
||||
config.need_render = true;
|
||||
};
|
||||
app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_file_url', 'Open File URL', [
|
||||
new app.Actions.Insert_layer_action(new_layer),
|
||||
new app.Actions.Autoresize_canvas_action(img.width, img.height, null, true, true)
|
||||
])
|
||||
);
|
||||
};
|
||||
img.onerror = function (ex) {
|
||||
alertify.error('Sorry, image could not be loaded. Try copy image and paste it.');
|
||||
};
|
||||
img.src = url;
|
||||
}
|
||||
|
||||
async load_json(data) {
|
||||
var json;
|
||||
if(typeof data == 'string')
|
||||
json = JSON.parse(data);
|
||||
else
|
||||
json = data;
|
||||
if (json.info.version == undefined) {
|
||||
json.info.version = "3.0.0";
|
||||
}
|
||||
|
||||
//migration
|
||||
if(semver_compare(json.info.version, '4.0.0') < 0) {
|
||||
//convert from v3 to v4
|
||||
for (var i in json.layers) {
|
||||
//layers data
|
||||
json.layers[i].id = (parseInt(i) + 1);
|
||||
json.layers[i].opacity = json.layers[i].opacity * 100 || 100;
|
||||
json.layers[i].type = "image";
|
||||
json.layers[i].width = json.info.width;
|
||||
json.layers[i].height = json.info.height;
|
||||
json.layers[i].visible = (json.layers[i].visible == true); //convert to boolean
|
||||
delete json.layers[i].title;
|
||||
}
|
||||
json.data = [];
|
||||
for (var i in json.image_data) {
|
||||
//image data
|
||||
var new_id = null;
|
||||
for (var j in json.layers) {
|
||||
if (json.layers[j].name == json.image_data[i].name) {
|
||||
new_id = json.layers[j].id;
|
||||
}
|
||||
}
|
||||
if (new_id == null)
|
||||
continue;
|
||||
json.data.push(
|
||||
{
|
||||
id: new_id,
|
||||
data: json.image_data[i].data,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
if(semver_compare(json.info.version, '4.5.0') < 0) {
|
||||
//migrate "rectangle", "circle" and "line" types to "shape"
|
||||
for (var i in json.layers) {
|
||||
var old_type = json.layers[i].type;
|
||||
|
||||
if(old_type == 'line' && json.layers[i].params.type.value == "Arrow"){
|
||||
//migrate line (type=arrow) to arrow.
|
||||
json.layers[i].type = 'arrow';
|
||||
delete json.layers[i].params.type;
|
||||
json.layers[i].render_function = ["arrow", "render"];
|
||||
}
|
||||
if(old_type == 'rectangle' || old_type == 'circle'){
|
||||
//migrate params
|
||||
json.layers[i].params.border_size = json.layers[i].params.size;
|
||||
delete json.layers[i].params.size;
|
||||
|
||||
if(json.layers[i].params.fill == true) {
|
||||
json.layers[i].params.border = false;
|
||||
}
|
||||
else{
|
||||
json.layers[i].params.border = true;
|
||||
}
|
||||
json.layers[i].params.border_color = json.layers[i].color;
|
||||
json.layers[i].params.fill_color = json.layers[i].color;
|
||||
|
||||
json.layers[i].color = null;
|
||||
}
|
||||
if(old_type == 'circle'){
|
||||
//rename circle to ellipse
|
||||
json.layers[i].type = 'ellipse';
|
||||
json.layers[i].render_function = ["ellipse", "render"];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(semver_compare(json.info.version, '4.8.0') < 0) {
|
||||
//migrate "borders" layer to rectangle
|
||||
for (var i in json.layers) {
|
||||
var old_type = json.layers[i].type;
|
||||
|
||||
if(old_type == 'borders'){
|
||||
json.layers[i].type = 'rectangle';
|
||||
json.layers[i].name += ' (legacy)';
|
||||
json.layers[i].params = {
|
||||
radius: 0,
|
||||
fill: false,
|
||||
square: false,
|
||||
border_size: json.layers[i].params.size,
|
||||
border: true,
|
||||
border_color: json.layers[i].color,
|
||||
fill_color: "#000000",
|
||||
};
|
||||
json.layers[i].render_function = ["rectangle", "render"];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(semver_compare(json.info.version, '4.11.0') < 0) {
|
||||
//migrate star and star24 objects
|
||||
for (var i in json.layers) {
|
||||
var old_type = json.layers[i].type;
|
||||
|
||||
if(old_type == 'star' && typeof json.layers[i].params.corners == "undefined"){
|
||||
json.layers[i].params.corners = 5;
|
||||
json.layers[i].params.inner_radius = 40;
|
||||
json.layers[i].render_function = ["star", "render"];
|
||||
}
|
||||
else if(old_type == 'star24'){
|
||||
json.layers[i].type = 'star';
|
||||
json.layers[i].params.corners = 24;
|
||||
json.layers[i].params.inner_radius = 80;
|
||||
json.layers[i].render_function = ["star", "render"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const actions = [];
|
||||
|
||||
//reset zoom
|
||||
await this.Base_gui.GUI_preview.zoom(100); //reset zoom
|
||||
|
||||
//set attributes
|
||||
actions.push(
|
||||
new app.Actions.Refresh_action_attributes_action('undo'),
|
||||
new app.Actions.Prepare_canvas_action('undo'),
|
||||
new app.Actions.Update_config_action({
|
||||
ZOOM: 1,
|
||||
WIDTH: parseInt(json.info.width),
|
||||
HEIGHT: parseInt(json.info.height),
|
||||
user_fonts: json.user_fonts || {}
|
||||
}),
|
||||
new app.Actions.Reset_layers_action(),
|
||||
new app.Actions.Prepare_canvas_action('do'),
|
||||
new app.Actions.Refresh_action_attributes_action('do')
|
||||
);
|
||||
|
||||
var max_id_order = 0;
|
||||
for (var i in json.layers) {
|
||||
var value = json.layers[i];
|
||||
|
||||
if(value.id > max_id_order)
|
||||
max_id_order = value.id;
|
||||
if(typeof value.order != undefined && value.order > max_id_order)
|
||||
max_id_order = value.order;
|
||||
|
||||
if (value.type == 'image') {
|
||||
//add image data
|
||||
value.link = null;
|
||||
for (var j in json.data) {
|
||||
if (json.data[j].id == value.id) {
|
||||
value.data = json.data[j].data;
|
||||
}
|
||||
}
|
||||
}
|
||||
actions.push(
|
||||
new app.Actions.Insert_layer_action(value, false)
|
||||
);
|
||||
}
|
||||
if (json.info.layer_active != undefined) {
|
||||
actions.push(
|
||||
new app.Actions.Select_layer_action(json.info.layer_active, true)
|
||||
);
|
||||
}
|
||||
if (json.info.guides != undefined) {
|
||||
config.guides = json.info.guides;
|
||||
}
|
||||
actions.push(
|
||||
new app.Actions.Set_object_property_action(this.Base_layers, 'auto_increment', max_id_order + 1),
|
||||
new app.Actions.Update_config_action({
|
||||
WIDTH: parseInt(json.info.width),
|
||||
HEIGHT: parseInt(json.info.height),
|
||||
}),
|
||||
new app.Actions.Prepare_canvas_action('do')
|
||||
);
|
||||
await app.State.do_action(
|
||||
new app.Actions.Bundle_action('open_json_file', 'Open JSON File', actions)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an action that saves the exif data of the provided object to the current layer
|
||||
*/
|
||||
extract_exif(object) {
|
||||
var exif_data = {
|
||||
general: [],
|
||||
exif: [],
|
||||
};
|
||||
|
||||
//exif data
|
||||
EXIF.getData(object, function () {
|
||||
exif_data.exif = this.exifdata;
|
||||
delete this.exifdata.thumbnail;
|
||||
});
|
||||
|
||||
//general
|
||||
if (object.name != undefined)
|
||||
exif_data.general.Name = object.name;
|
||||
if (object.size != undefined)
|
||||
exif_data.general.Size = this.Helper.number_format(object.size / 1000, 2) + ' KB';
|
||||
if (object.type != undefined)
|
||||
exif_data.general.Type = object.type;
|
||||
if (object.lastModified != undefined)
|
||||
exif_data.general['Last modified'] = this.Helper.format_time(object.lastModified);
|
||||
|
||||
return exif_data;
|
||||
}
|
||||
|
||||
search(){
|
||||
this.GUI_tools.activate_tool('media');
|
||||
}
|
||||
}
|
||||
|
||||
export default File_open_class;
|
||||
|
||||
Reference in New Issue
Block a user