diff --git a/examples/open-edit-save.html b/examples/open-edit-save.html
index 8ec8d55..9645309 100644
--- a/examples/open-edit-save.html
+++ b/examples/open-edit-save.html
@@ -72,13 +72,11 @@ function save_image(){
//update image using blob (faster)
tempCanvas.toBlob(function (blob) {
alert('Data length: ' + blob.size);
- console.log(blob);
}, 'image/png');
}
else{
//slow way for IE, Edge
var data = tempCanvas.toDataURL();
- console.log(data);
alert('Data length: ' + data.length);
}
}
diff --git a/src/js/actions/add-layer-filter.js b/src/js/actions/add-layer-filter.js
new file mode 100644
index 0000000..cbdc134
--- /dev/null
+++ b/src/js/actions/add-layer-filter.js
@@ -0,0 +1,55 @@
+import app from './../app.js';
+import config from './../config.js';
+import { Base_action } from './base.js';
+
+export class Add_layer_filter_action extends Base_action {
+ /**
+ * register new live filter
+ *
+ * @param {int} layer_id
+ * @param {string} name
+ * @param {object} params
+ */
+ constructor(layer_id, name, params) {
+ super('add_layer_filter', 'Add Layer Filter');
+ if (layer_id == null)
+ layer_id = config.layer.id;
+ this.layer_id = parseInt(layer_id);
+ this.filter_id = Math.floor(Math.random() * 999999999) + 1; // A good UUID library would
+ this.name = name;
+ this.params = params;
+ this.reference_layer = null;
+ }
+
+ async do() {
+ super.do();
+ this.reference_layer = app.Layers.get_layer(this.layer_id);
+ if (!this.reference_layer) {
+ throw new Error('Aborted - layer with specified id doesn\'t exist');
+ }
+ var filter = {
+ id: this.filter_id,
+ name: this.name,
+ params: this.params,
+ };
+ this.reference_layer.filters.push(filter);
+
+ config.need_render = true;
+ app.GUI.GUI_layers.render_layers();
+ }
+
+ async undo() {
+ super.undo();
+ if (this.reference_layer) {
+ this.reference_layer.filters.pop();
+ this.reference_layer = null;
+ }
+ config.need_render = true;
+ app.GUI.GUI_layers.render_layers();
+ }
+
+ free() {
+ this.reference_layer = null;
+ this.params = null;
+ }
+}
\ No newline at end of file
diff --git a/src/js/actions/base.js b/src/js/actions/base.js
index c025caa..11da929 100644
--- a/src/js/actions/base.js
+++ b/src/js/actions/base.js
@@ -4,12 +4,14 @@ export class Base_action {
this.action_id = action_id;
this.action_description = action_description;
this.is_done = false;
+ this.memory_estimate = 0; // Estimate of how much memory will be freed when the free() method is called (in bytes)
}
do() {
this.is_done = true;
}
undo() {
this.is_done = false;
+ this.memory_estimate = 0;
}
free() {
// Override if need to run tasks to free memory when action is discarded from history
diff --git a/src/js/actions/bundle.js b/src/js/actions/bundle.js
index 9bf57e3..b2635d0 100644
--- a/src/js/actions/bundle.js
+++ b/src/js/actions/bundle.js
@@ -41,6 +41,11 @@ export class Bundle_action extends Base_action {
}
free() {
- this.actions_to_do = null;
+ if (this.actions_to_do) {
+ for (let action of this.actions_to_do) {
+ action.free();
+ }
+ this.actions_to_do = null;
+ }
}
}
\ No newline at end of file
diff --git a/src/js/actions/clear-layer.js b/src/js/actions/clear-layer.js
new file mode 100644
index 0000000..a9f8d5a
--- /dev/null
+++ b/src/js/actions/clear-layer.js
@@ -0,0 +1,82 @@
+import app from './../app.js';
+import config from './../config.js';
+import { Base_action } from './base.js';
+
+export class Clear_layer_action extends Base_action {
+ /**
+ * clear layer data
+ *
+ * @param {int} layer_id
+ */
+ constructor(layer_id) {
+ super('clear_layer', 'Clear Layer');
+ this.layer_id = parseInt(layer_id);
+ this.update_layer_action = null;
+ this.delete_layer_settings_action = null;
+ }
+
+ async do() {
+ super.do();
+ let layer = app.Layers.get_layer(this.layer_id);
+ if (!layer) {
+ throw new Error('Aborted - layer with specified id doesn\'t exist');
+ }
+ let new_settings = {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+ visible: true,
+ opacity: 100,
+ composition: null,
+ rotate: 0,
+ data: null,
+ params: {},
+ status: null,
+ render_function: null,
+ type: null
+ };
+ if (layer.type == 'image') {
+ //clean image
+ new_settings.link = null;
+ }
+ this.update_layer_action = new app.Actions.Update_layer_action(this.layer_id, new_settings);
+ await this.update_layer_action.do();
+ let delete_setting_names = [];
+ for (let prop_name in layer) {
+ //remove private attributes
+ if (prop_name[0] == '_') {
+ delete_setting_names.push(prop_name);
+ }
+ }
+ if (delete_setting_names.length > 0) {
+ this.delete_layer_settings_action = new app.Actions.Delete_layer_settings_action(this.layer_id, delete_setting_names);
+ await this.delete_layer_settings_action.do();
+ }
+ }
+
+ async undo() {
+ super.undo();
+ if (this.delete_layer_settings_action) {
+ await this.delete_layer_settings_action.undo();
+ this.delete_layer_settings_action.free();
+ this.delete_layer_settings_action = null;
+ }
+ if (this.update_layer_action) {
+ await this.update_layer_action.undo();
+ this.update_layer_action.free();
+ this.update_layer_action = null;
+ }
+ }
+
+ free() {
+ if (this.update_layer_action) {
+ this.update_layer_action.free();
+ this.update_layer_action = null;
+ }
+ if (this.delete_layer_settings_action) {
+ this.delete_layer_settings_action.free();
+ this.delete_layer_settings_action = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/js/actions/delete-layer-filter.js b/src/js/actions/delete-layer-filter.js
new file mode 100644
index 0000000..821f233
--- /dev/null
+++ b/src/js/actions/delete-layer-filter.js
@@ -0,0 +1,60 @@
+import app from './../app.js';
+import config from './../config.js';
+import { Base_action } from './base.js';
+
+export class Delete_layer_filter_action extends Base_action {
+ /**
+ * delete live filter
+ *
+ * @param {int} layer_id
+ * @param {string} filter_id
+ */
+ constructor(layer_id, filter_id) {
+ super('delete_layer_filter', 'Delete Layer Filter');
+ if (layer_id == null)
+ layer_id = config.layer.id;
+ this.layer_id = parseInt(layer_id);
+ this.filter_id = filter_id;
+ this.reference_layer = null;
+ this.filter_remove_index = null;
+ this.old_filter = null;
+ }
+
+ async do() {
+ super.do();
+ this.reference_layer = app.Layers.get_layer(this.layer_id);
+ if (!this.reference_layer) {
+ throw new Error('Aborted - layer with specified id doesn\'t exist');
+ }
+ this.old_filter = null;
+ for (let i in this.reference_layer.filters) {
+ if (this.reference_layer.filters[i].id == this.filter_id) {
+ this.filter_remove_index = i;
+ this.old_filter = this.reference_layer.filters.splice(i, 1)[0];
+ break;
+ }
+ }
+ if (!this.old_filter) {
+ throw new Error('Aborted - filter with specified id doesn\'t exist in layer');
+ }
+ config.need_render = true;
+ app.GUI.GUI_layers.render_layers();
+ }
+
+ async undo() {
+ super.undo();
+ if (this.reference_layer && this.old_filter) {
+ this.reference_layer.filters.splice(this.filter_remove_index, 0, this.old_filter);
+ }
+ this.reference_layer = null;
+ this.old_filter = null;
+ this.filter_remove_index = null;
+ config.need_render = true;
+ app.GUI.GUI_layers.render_layers();
+ }
+
+ free() {
+ this.reference_layer = null;
+ this.old_filter = null;
+ }
+}
\ No newline at end of file
diff --git a/src/js/actions/delete-layer-settings.js b/src/js/actions/delete-layer-settings.js
new file mode 100644
index 0000000..8587fb0
--- /dev/null
+++ b/src/js/actions/delete-layer-settings.js
@@ -0,0 +1,50 @@
+import app from './../app.js';
+import config from './../config.js';
+import { Base_action } from './base.js';
+
+export class Delete_layer_settings_action extends Base_action {
+ /**
+ * Deletes the specified settings in a layer
+ *
+ * @param {int} layer_id
+ * @param {array} setting_names
+ */
+ constructor(layer_id, setting_names) {
+ super('delete_layer_settings', 'Delete Layer Settings');
+ this.layer_id = parseInt(layer_id);
+ this.setting_names = setting_names;
+ this.reference_layer = null;
+ this.old_settings = {};
+ }
+
+ async do() {
+ super.do();
+ this.reference_layer = app.Layers.get_layer(this.layer_id);
+ if (!this.reference_layer) {
+ throw new Error('Aborted - layer with specified id doesn\'t exist');
+ }
+ for (let name in this.setting_names) {
+ this.old_settings[name] = this.reference_layer[name];
+ delete this.reference_layer[name];
+ }
+ config.need_render = true;
+ }
+
+ async undo() {
+ super.undo();
+ if (this.reference_layer) {
+ for (let i in this.old_settings) {
+ this.reference_layer[i] = this.old_settings[i];
+ }
+ this.old_settings = {};
+ }
+ this.reference_layer = null;
+ config.need_render = true;
+ }
+
+ free() {
+ this.setting_names = null;
+ this.reference_layer = null;
+ this.old_settings = null;
+ }
+}
\ No newline at end of file
diff --git a/src/js/actions/delete-layer.js b/src/js/actions/delete-layer.js
index 889d4a9..5d6a6af 100644
--- a/src/js/actions/delete-layer.js
+++ b/src/js/actions/delete-layer.js
@@ -76,10 +76,12 @@ export class Delete_layer_action extends Base_action {
}
if (this.select_layer_action) {
await this.select_layer_action.undo();
+ this.select_layer_action.free();
this.select_layer_action = null;
}
if (this.insert_layer_action) {
await this.insert_layer_action.undo();
+ this.insert_layer_action.free();
this.insert_layer_action = null;
}
@@ -91,8 +93,14 @@ export class Delete_layer_action extends Base_action {
if (this.deleted_layer) {
delete this.deleted_layer.link;
}
- this.insert_layer_action = null;
- this.select_layer_action = null;
+ if (this.insert_layer_action) {
+ this.insert_layer_action.free();
+ this.insert_layer_action = null;
+ }
+ if (this.select_layer_action) {
+ this.select_layer_action.free();
+ this.select_layer_action = null;
+ }
this.deleted_layer = null;
}
}
\ No newline at end of file
diff --git a/src/js/actions/index.js b/src/js/actions/index.js
index 30d2bc3..284504a 100644
--- a/src/js/actions/index.js
+++ b/src/js/actions/index.js
@@ -1,14 +1,21 @@
+export { Add_layer_filter_action } from './add-layer-filter.js';
export { Autoresize_canvas_action } from './autoresize-canvas.js';
export { Bundle_action } from './bundle.js';
+export { Clear_layer_action } from './clear-layer.js';
export { Delete_layer_action } from './delete-layer.js';
+export { Delete_layer_filter_action } from './delete-layer-filter.js';
+export { Delete_layer_settings_action } from './delete-layer-settings.js';
export { Init_canvas_zoom_action } from './init-canvas-zoom.js';
export { Insert_layer_action } from './insert-layer.js';
export { Prepare_canvas_action } from './prepare-canvas.js';
+export { Reorder_layer_action } from './reorder-layer.js';
export { Reset_layers_action } from './reset-layers.js';
export { Reset_selection_action } from './reset-selection.js';
export { Select_layer_action } from './select-layer.js';
export { Select_next_layer_action } from './select-next-layer.js';
export { Select_previous_layer_action } from './select-previous-layer.js';
+export { Set_selection_action } from './set-selection.js';
export { Toggle_layer_visibility_action } from './toggle-layer-visibility.js';
export { Update_config_action } from './update-config.js';
+export { Update_layer_image_action } from './update-layer-image.js';
export { Update_layer_action } from './update-layer.js';
\ No newline at end of file
diff --git a/src/js/actions/insert-layer.js b/src/js/actions/insert-layer.js
index b1d6f96..dc305e7 100644
--- a/src/js/actions/insert-layer.js
+++ b/src/js/actions/insert-layer.js
@@ -1,6 +1,7 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
+import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
export class Insert_layer_action extends Base_action {
/**
@@ -23,6 +24,7 @@ export class Insert_layer_action extends Base_action {
async do() {
super.do();
+
this.previous_auto_increment = app.Layers.auto_increment;
this.previous_selected_layer = config.layer;
let autoresize_as = null;
@@ -78,7 +80,7 @@ export class Insert_layer_action extends Base_action {
// Remove first empty layer
this.delete_layer_action = new app.Actions.Delete_layer_action(config.layer.id, true);
- this.delete_layer_action.do();
+ await this.delete_layer_action.do();
}
if (layer.link == null) {
@@ -179,15 +181,17 @@ export class Insert_layer_action extends Base_action {
this.autoresize_canvas_action = null;
}
if (this.inserted_layer_id) {
- await new app.Actions.Delete_layer_action(this.inserted_layer_id, true).do();
+ config.layers.pop();
this.inserted_layer_id = null;
}
if (this.update_layer_action) {
await this.update_layer_action.undo();
+ this.update_layer_action.free();
this.update_layer_action = null;
}
if (this.delete_layer_action) {
await this.delete_layer_action.undo();
+ this.delete_layer_action.free();
this.delete_layer_action = null;
}
config.layer = this.previous_selected_layer;
@@ -198,8 +202,14 @@ export class Insert_layer_action extends Base_action {
}
free() {
- this.delete_layer_action = null;
- this.update_layer_action = null;
+ if (this.delete_layer_action) {
+ this.delete_layer_action.free();
+ this.delete_layer_action = null;
+ }
+ if (this.update_layer_action) {
+ this.update_layer_action.free();
+ this.update_layer_action = null;
+ }
this.previous_selected_layer = null;
}
}
\ No newline at end of file
diff --git a/src/js/actions/reorder-layer.js b/src/js/actions/reorder-layer.js
new file mode 100644
index 0000000..8225a99
--- /dev/null
+++ b/src/js/actions/reorder-layer.js
@@ -0,0 +1,64 @@
+import app from '../app.js';
+import config from '../config.js';
+import { Base_action } from './base.js';
+
+export class Reorder_layer_action extends Base_action {
+ /**
+ * Reorder layer up or down in the layer stack
+ *
+ * @param {int} layer_id
+ * @param {int} direction
+ */
+ constructor(layer_id, direction) {
+ super('reorder_layer', 'Reorder Layer');
+ this.layer_id = parseInt(layer_id);
+ this.direction = direction;
+ this.reference_layer = null;
+ this.reference_target = null;
+ this.old_layer_order = null;
+ this.old_target_order = null;
+ }
+
+ async do() {
+ super.do();
+ this.reference_layer = app.Layers.get_layer(this.layer_id);
+ if (!this.reference_layer) {
+ throw new Error('Aborted - layer with specified id doesn\'t exist');
+ }
+ if (this.direction < 0) {
+ this.reference_target = app.Layers.find_previous(this.layer_id);
+ }
+ else {
+ this.reference_target = app.Layers.find_next(this.layer_id);
+ }
+ if (!this.reference_target) {
+ throw new Error('Aborted - layer has nowhere to move');
+ }
+ this.old_layer_order = this.reference_layer.order;
+ this.old_target_order = this.reference_target.order;
+ this.reference_layer.order = this.old_target_order;
+ this.reference_target.order = this.old_layer_order;
+
+ app.Layers.render();
+ app.GUI.GUI_layers.render_layers();
+ }
+
+ async undo() {
+ super.undo();
+ if (this.reference_layer) {
+ this.reference_layer.order = this.old_layer_order;
+ this.reference_layer = null;
+ }
+ if (this.reference_target) {
+ this.reference_target.order = this.old_target_order;
+ this.reference_target = null;
+ }
+ app.Layers.render();
+ app.GUI.GUI_layers.render_layers();
+ }
+
+ free() {
+ this.reference_layer = null;
+ this.reference_target = null;
+ }
+}
\ No newline at end of file
diff --git a/src/js/actions/reset-layers.js b/src/js/actions/reset-layers.js
index b89a425..ea289fc 100644
--- a/src/js/actions/reset-layers.js
+++ b/src/js/actions/reset-layers.js
@@ -39,15 +39,28 @@ export class Reset_layers_action extends Base_action {
super.undo();
if (this.insert_action) {
await this.insert_action.undo();
+ this.insert_action.free();
this.insert_action = null;
}
for (let i = this.delete_actions.length - 1; i >= 0; i--) {
await this.delete_actions[i].undo();
+ this.delete_actions[i].free();
}
app.Layers.auto_increment = this.previous_auto_increment;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
-
+ free() {
+ if (this.insert_action) {
+ this.insert_action.free();
+ this.insert_action = null;
+ }
+ if (this.delete_actions) {
+ for (let action of this.delete_actions) {
+ action.free();
+ }
+ this.delete_actions = null;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/js/actions/reset-selection.js b/src/js/actions/reset-selection.js
index a614185..7f775ce 100644
--- a/src/js/actions/reset-selection.js
+++ b/src/js/actions/reset-selection.js
@@ -15,19 +15,23 @@ export class Reset_selection_action extends Base_action {
async do() {
super.do();
this.settings_reference = app.Layers.Base_selection.find_settings();
- this.old_settings_data = this.settings_reference.data;
- this.settings_reference.data = {
- x: null,
- y: null,
- width: null,
- height: null
- };
+ this.old_settings_data = JSON.parse(JSON.stringify(this.settings_reference.data));
+ this.settings_reference.data = {
+ x: null,
+ y: null,
+ width: null,
+ height: null
+ }
config.need_render = true;
}
async undo() {
super.undo();
- this.settings_reference.data = this.old_settings_data;
+ if (this.old_settings_data) {
+ for (let prop in this.old_settings_data) {
+ this.settings_reference.data[prop] = this.old_settings_data[prop];
+ }
+ }
this.settings_reference = null;
this.old_settings_data = null;
config.need_render = true;
diff --git a/src/js/actions/select-layer.js b/src/js/actions/select-layer.js
index 93e1f5b..b27c97d 100644
--- a/src/js/actions/select-layer.js
+++ b/src/js/actions/select-layer.js
@@ -41,6 +41,7 @@ export class Select_layer_action extends Base_action {
if (this.reset_selection_action) {
await this.reset_selection_action.undo();
+ this.reset_selection_action.free();
this.reset_selection_action = null;
}
@@ -53,5 +54,9 @@ export class Select_layer_action extends Base_action {
free() {
this.old_layer = null;
+ if (this.reset_selection_action) {
+ this.reset_selection_action.free();
+ this.reset_selection_action = null;
+ }
}
}
\ No newline at end of file
diff --git a/src/js/actions/set-selection.js b/src/js/actions/set-selection.js
new file mode 100644
index 0000000..c6255dc
--- /dev/null
+++ b/src/js/actions/set-selection.js
@@ -0,0 +1,57 @@
+import app from '../app.js';
+import config from '../config.js';
+import { Base_action } from './base.js';
+
+export class Set_selection_action extends Base_action {
+ /**
+ * Sets the selection to the specified position and dimensions
+ */
+ constructor(x, y, width, height, old_settings_override) {
+ super('set_selection', 'Set Selection');
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.settings_reference = null;
+ this.old_settings_data = null;
+ this.old_settings_override = old_settings_override || null;
+ }
+
+ async do() {
+ super.do();
+ this.settings_reference = app.Layers.Base_selection.find_settings();
+ this.old_settings_data = JSON.parse(JSON.stringify(this.settings_reference.data));
+ if (this.x != null)
+ this.settings_reference.data.x = this.x;
+ if (this.y != null)
+ this.settings_reference.data.y = this.y;
+ if (this.width != null)
+ this.settings_reference.data.width = this.width;
+ if (this.height != null)
+ this.settings_reference.data.height = this.height;
+
+ config.need_render = true;
+ }
+
+ async undo() {
+ super.undo();
+ if (this.old_settings_override) {
+ for (let prop in this.old_settings_override) {
+ this.settings_reference.data[prop] = this.old_settings_override[prop];
+ }
+ } else {
+ for (let prop in this.old_settings_data) {
+ this.settings_reference.data[prop] = this.old_settings_data[prop];
+ }
+ }
+ this.settings_reference = null;
+ this.old_settings_data = null;
+ config.need_render = true;
+ }
+
+ free() {
+ this.settings_reference = null;
+ this.old_settings_override = null;
+ this.old_settings_data = null;
+ }
+}
\ No newline at end of file
diff --git a/src/js/actions/store/image-store.js b/src/js/actions/store/image-store.js
new file mode 100644
index 0000000..0d8f133
--- /dev/null
+++ b/src/js/actions/store/image-store.js
@@ -0,0 +1,143 @@
+import { get } from "jquery";
+
+let idCounter = 0;
+let database = null;
+let databaseInitPromise = null;
+
+export default {
+ /**
+ * Initializes the database
+ */
+ async init() {
+ if (!databaseInitPromise) {
+ databaseInitPromise = new Promise(async (resolveInit) => {
+ try {
+ if (window.indexedDB) {
+ // Delete database from a previous page load
+ await new Promise((resolve, reject) => {
+ let deleteRequest = window.indexedDB.deleteDatabase('undoHistoryImageStore');
+ deleteRequest.onerror = () => {
+ reject(deleteRequest.error);
+ };
+ deleteRequest.onsuccess = () => {
+ resolve();
+ };
+ });
+ // Initialize database
+ await new Promise((resolve, reject) => {
+ let openRequest = window.indexedDB.open('undoHistoryImageStore', 1);
+ openRequest.onupgradeneeded = function(event) {
+ database = openRequest.result;
+ switch (event.oldVersion) {
+ case 0:
+ database.createObjectStore('images', { keyPath: 'id' });
+ break;
+ }
+ };
+ openRequest.onerror = () => {
+ reject(openRequest.error);
+ }
+ openRequest.onsuccess = () => {
+ resolve();
+ database = openRequest.result;
+ }
+ });
+ if (!database) {
+ throw new Error('indexedDB not initialized');
+ }
+ }
+ } catch (error) {
+ database = {
+ isMemory: true,
+ images: {}
+ };
+ }
+ resolveInit();
+ });
+ await databaseInitPromise;
+ } else if (!database) {
+ await databaseInitPromise;
+ }
+ },
+
+ /**
+ * Adds the specified image to the database. Returns a promise that is resolved with an id that can be used to retrieve it again.
+ *
+ * @param {string | canvas | ImageData} imageData the image data to store
+ * @returns {Promise} resolves with retrieval id
+ */
+ async add(imageData) {
+ await this.init();
+ let imageId = (idCounter++) + '';
+ if (database.isMemory) {
+ database.images[imageId] = imageData;
+ } else {
+ await new Promise((resolve, reject) => {
+ const transaction = database.transaction('images', 'readwrite');
+ const images = transaction.objectStore('images');
+ const image = {
+ id: imageId,
+ data: imageData
+ }
+ const request = images.add(image);
+ request.onsuccess = function() {
+ resolve();
+ };
+ request.onerror = function() {
+ reject(request.error);
+ };
+ });
+ }
+ return imageId;
+ },
+
+ /**
+ * Gets the specified image from the database, by imageId retrieved from "add()" method.
+ *
+ * @param {string} imageId the id of the image to get
+ * @returns {Promise} resolves with the image
+ */
+ async get(imageId) {
+ await this.init();
+ if (database.isMemory) {
+ return database.images[imageId];
+ } else {
+ return new Promise((resolve, reject) => {
+ const transaction = database.transaction('images', 'readonly');
+ const images = transaction.objectStore('images');
+ const request = images.get(imageId);
+ request.onsuccess = function() {
+ resolve(request.result.data);
+ };
+ request.onerror = function() {
+ reject(request.error);
+ };
+ });
+ }
+ },
+
+ /**
+ * Deletes the specified image from the database, by imageId retrieved from "add()" method.
+ *
+ * @param {string} imageId the id of the image to delete
+ * @returns {Promise} resolves with the image
+ */
+ async delete(imageId) {
+ await this.init();
+ if (database.isMemory) {
+ delete database.images[imageId];
+ } else {
+ return new Promise((resolve, reject) => {
+ const transaction = database.transaction('images', 'readwrite');
+ const images = transaction.objectStore('images');
+ const request = images.delete(imageId);
+ request.onsuccess = function() {
+ resolve();
+ };
+ request.onerror = function() {
+ reject(request.error);
+ };
+ });
+ }
+ }
+};
\ No newline at end of file
diff --git a/src/js/actions/update-layer-image.js b/src/js/actions/update-layer-image.js
new file mode 100644
index 0000000..64fc46e
--- /dev/null
+++ b/src/js/actions/update-layer-image.js
@@ -0,0 +1,98 @@
+import app from './../app.js';
+import config from './../config.js';
+import Helper_class from './../libs/helpers.js';
+import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
+import image_store from './store/image-store.js';
+import { Base_action } from './base.js';
+
+const Helper = new Helper_class();
+
+export class Update_layer_image_action extends Base_action {
+ /**
+ * updates layer image data
+ *
+ * @param {canvas} canvas
+ * @param {int} layer_id (optional)
+ */
+ constructor(canvas, layer_id) {
+ super('update_layer_image', 'Update Layer Image');
+ this.canvas = canvas;
+ this.canvas_data_url = null;
+ if (layer_id == null)
+ layer_id = config.layer.id;
+ this.layer_id = parseInt(layer_id);
+ this.reference_layer = null;
+ this.old_image_id = null;
+ }
+
+ async do() {
+ super.do();
+ this.reference_layer = app.Layers.get_layer(this.layer_id);
+ if (!this.reference_layer) {
+ throw new Error('Aborted - layer with specified id doesn\'t exist');
+ }
+ if (this.reference_layer.type != 'image'){
+ alertify.error('Error: layer must be image.');
+ throw new Error('Aborted - layer is not an image');
+ }
+
+ if (!this.canvas_data_url) {
+ if (Helper.is_edge_or_ie() == false) {
+ // Update image using blob (faster)
+ await new Promise((resolve) => {
+ this.canvas.toBlob((blob) => {
+ this.canvas_data_url = window.URL.createObjectURL(blob);
+ resolve();
+ }, 'image/png');
+ });
+ }
+ else {
+ // Slow way for IE, Edge
+ this.canvas_data_url = this.canvas.toDataURL();
+ }
+ this.canvas = null;
+ }
+
+ try {
+ this.old_image_id = await image_store.add(this.reference_layer.link.src);
+ } catch (error) {
+ console.log(error);
+ // TODO - need to delete undo history, how to handle this?
+ }
+ this.reference_layer.link.src = this.canvas_data_url;
+
+ config.need_render = true;
+ }
+
+ async undo() {
+ super.undo();
+ if (this.old_image_id != null) {
+ try {
+ this.reference_layer.link.src = await image_store.get(this.old_image_id);
+ } catch (error) {
+ throw new Error('Failed to retrieve image from store');
+ }
+ try {
+ await image_store.delete(this.old_image_id);
+ } catch (error) {
+ // TODO - Reduce assumed total memory storage by image size
+ }
+ this.old_image_id = null;
+ }
+ this.reference_layer = null;
+ config.need_render = true;
+ }
+
+ async free() {
+ if (this.old_image_id != null) {
+ try {
+ await image_store.delete(this.old_image_id);
+ } catch (error) {
+ // TODO - Reduce assumed total memory storage by image size
+ }
+ this.old_image_id = null;
+ }
+ this.reference_layer = null;
+ this.canvas_data_url = null;
+ }
+}
\ No newline at end of file
diff --git a/src/js/actions/update-layer.js b/src/js/actions/update-layer.js
index 0a729e0..894133d 100644
--- a/src/js/actions/update-layer.js
+++ b/src/js/actions/update-layer.js
@@ -5,6 +5,7 @@ import { Base_action } from './base.js';
export class Update_layer_action extends Base_action {
/**
* Updates an existing layer with the provided settings
+ * WARNING: If passing objects or arrays into settings, make sure these are new objects, and not a modified existing object!
*
* @param {string} layer_id
* @param {object} settings
@@ -20,11 +21,9 @@ export class Update_layer_action extends Base_action {
async do() {
super.do();
this.reference_layer = app.Layers.get_layer(this.layer_id);
-
if (!this.reference_layer) {
throw new Error('Aborted - layer with specified id doesn\'t exist');
}
-
for (let i in this.settings) {
if (i == 'id')
continue;
@@ -33,6 +32,10 @@ export class Update_layer_action extends Base_action {
this.old_settings[i] = this.reference_layer[i];
this.reference_layer[i] = this.settings[i];
}
+ if (this.settings.data && this.reference_layer.type === 'text') {
+ this.reference_layer._needs_update_data = true;
+ }
+ config.need_render = true;
}
async undo() {
@@ -41,9 +44,13 @@ export class Update_layer_action extends Base_action {
for (let i in this.old_settings) {
this.reference_layer[i] = this.old_settings[i];
}
+ if (this.old_settings.data && this.reference_layer[i] === 'text') {
+ this.reference_layer._needs_update_data = true;
+ }
this.old_settings = {};
}
this.reference_layer = null;
+ config.need_render = true;
}
free() {
diff --git a/src/js/core/base-layers.js b/src/js/core/base-layers.js
index 65154e6..4fc3813 100644
--- a/src/js/core/base-layers.js
+++ b/src/js/core/base-layers.js
@@ -411,16 +411,15 @@ class Base_layers_class {
* @param {int} id
* @param {int} value 0-100
*/
- set_opacity(id, value) {
- id = parseInt(id);
+ async set_opacity(id, value) {
value = parseInt(value);
if (value < 0 || value > 100) {
//reset
value = 100;
}
- var link = this.get_layer(id);
-
- link.opacity = value;
+ return app.State.do_action(
+ new app.Actions.Update_layer_action(id, { opacity: value })
+ );
}
/**
@@ -428,36 +427,10 @@ class Base_layers_class {
*
* @param {int} id
*/
- layer_clear(id) {
- id = parseInt(id);
- var link = this.get_layer(id);
-
- if (link.type == 'image') {
- //clean image
- link.link = null;
- }
-
- for (var i in link) {
- //remove private attributes
- if (i[0] == '_')
- delete link[i];
- }
-
- link.x = 0;
- link.y = 0;
- link.width = 0;
- link.height = 0;
- link.visible = true;
- link.opacity = 100;
- link.composition = null;
- link.rotate = 0;
- link.data = null;
- link.params = {};
- link.status = null;
- link.render_function = null;
- link.type = null;
-
- config.need_render = true;
+ async layer_clear(id) {
+ return app.State.do_action(
+ new app.Actions.Clear_layer_action(id)
+ );
}
/**
@@ -466,24 +439,10 @@ class Base_layers_class {
* @param {int} id
* @param {int} direction
*/
- move(id, direction) {
- id = parseInt(id);
- var link = this.get_layer(id);
-
- if (direction < 0) {
- var target = this.find_previous(id);
- }
- else {
- var target = this.find_next(id);
- }
- if (target != null) {
- var current_order = link.order;
- link.order = target.order;
- target.order = current_order;
- }
-
- this.render();
- this.Base_gui.GUI_layers.render_layers();
+ async move(id, direction) {
+ return app.State.do_action(
+ new app.Actions.Reorder_layer_action(id, direction)
+ );
}
/**
@@ -579,18 +538,9 @@ class Base_layers_class {
* @param {object} params
*/
add_filter(layer_id, name, params) {
- if (layer_id == null)
- layer_id = config.layer.id;
- var link = this.get_layer(layer_id);
- var filter = {
- id: this.Helper.getRandomInt(1, 999999999),
- name: name,
- params: params,
- };
- link.filters.push(filter);
-
- config.need_render = true;
- this.Base_gui.GUI_layers.render_layers();
+ return app.State.do_action(
+ new app.Actions.Add_layer_filter_action(layer_id, name, params)
+ );
}
/**
@@ -600,18 +550,9 @@ class Base_layers_class {
* @param {string} filter_id
*/
delete_filter(layer_id, filter_id) {
- if (layer_id == null)
- layer_id = config.layer.id;
- var link = this.get_layer(layer_id);
-
- for (var i in link.filters) {
- if (link.filters[i].id == filter_id) {
- link.filters.splice(i, 1);
- }
- }
-
- config.need_render = true;
- this.Base_gui.GUI_layers.render_layers();
+ return app.State.do_action(
+ new app.Actions.Delete_layer_filter_action(layer_id, filter_id)
+ );
}
/**
@@ -704,28 +645,9 @@ class Base_layers_class {
* @param {int} layer_id (optional)
*/
update_layer_image(canvas, layer_id) {
- if (layer_id == null)
- layer_id = config.layer.id;
- var link = this.get_layer(layer_id);
-
- if (link.type != 'image'){
- alertify.error('Error: layer must be image.');
- return null;
- }
-
- if(this.Helper.is_edge_or_ie() == false){
- //update image using blob (faster)
- canvas.toBlob(function (blob) {
- link.link.src = window.URL.createObjectURL(blob);
- config.need_render = true;
- }, 'image/png');
- }
- else{
- //slow way for IE, Edge
- link.link.src = canvas.toDataURL();
- }
-
- config.need_render = true;
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas, layer_id)
+ );
}
/**
diff --git a/src/js/core/base-selection.js b/src/js/core/base-selection.js
index e16bffc..5b4aa9e 100644
--- a/src/js/core/base-selection.js
+++ b/src/js/core/base-selection.js
@@ -45,39 +45,47 @@ class Base_selection_class {
this.selected_object_drag_type = null;
this.click_details = {};
this.is_touch = false;
+ // True if dragging from inside canvas area
+ this.is_drag = false;
this.events();
}
events() {
- var _this = this;
-
- document.addEventListener('mousedown', function (e) {
- if(_this.is_touch == true)
+ document.addEventListener('mousedown', (e) => {
+ this.is_drag = false;
+ if(this.is_touch == true)
return;
- _this.selected_object_actions(e);
+ if (!e.target.closest('#main_wrapper'))
+ return;
+ this.is_drag = true;
+ this.selected_object_actions(e);
});
- document.addEventListener('mousemove', function (e) {
- if(_this.is_touch == true)
+ document.addEventListener('mousemove', (e) => {
+ if(this.is_touch == true)
return;
- _this.selected_object_actions(e);
+ this.selected_object_actions(e);
});
- document.addEventListener('mouseup', function (e) {
- if(_this.is_touch == true)
+ document.addEventListener('mouseup', (e) => {
+ if(this.is_touch == true)
return;
- _this.selected_object_actions(e);
+ this.selected_object_actions(e);
});
// touch
- document.addEventListener('touchstart', function (event) {
- _this.is_touch = true;
- _this.selected_object_actions(event);
+ document.addEventListener('touchstart', (event) => {
+ this.is_drag = false;
+ this.is_touch = true;
+ if (!e.target.closest('#main_wrapper'))
+ return;
+ this.is_drag = true;
+ this.selected_object_actions(event);
});
- document.addEventListener('touchmove', function (event) {
- _this.selected_object_actions(event);
+ document.addEventListener('touchmove', (event) => {
+ this.selected_object_actions(event);
}, {passive: false});
- document.addEventListener('touchend', function (event) {
- _this.selected_object_actions(event);
+ document.addEventListener('touchend', (event) => {
+ this.selected_object_actions(event);
});
}
@@ -264,6 +272,9 @@ class Base_selection_class {
if(event_type == 'touchmove') event_type = 'mousemove';
if(event_type == 'touchend') event_type = 'mouseup';
+ if (!this.is_drag && ['mousedown', 'mouseup'].includes(event_type))
+ return;
+
const mainWrapper = document.getElementById('main_wrapper');
const defaultCursor = config.TOOL && config.TOOL.name === 'text' ? 'text' : 'default';
if (mainWrapper.style.cursor != defaultCursor) {
@@ -288,7 +299,7 @@ class Base_selection_class {
height: settings.data.height,
};
}
- if (event_type == 'mousemove' && this.mouse_lock == 'selected_object_actions') {
+ if (event_type == 'mousemove' && this.mouse_lock == 'selected_object_actions' && this.is_drag) {
const allowNegativeDimensions = settings.data.render_function
&& ['line', 'gradient'].includes(settings.data.render_function[0]);
diff --git a/src/js/core/base-state.js b/src/js/core/base-state.js
index 692dbac..404e08d 100644
--- a/src/js/core/base-state.js
+++ b/src/js/core/base-state.js
@@ -61,6 +61,7 @@ class Base_state_class {
await action.do();
} catch (error) {
// Action aborted. This could be expected behavior if detected that the action shouldn't run.
+ console.info(error);
return { status: 'aborted', reason: error };
}
// Remove all redo actions from history
@@ -106,6 +107,7 @@ class Base_state_class {
save() {
+ /*
this.optimize();
if (this.enabled == false) {
@@ -155,6 +157,7 @@ class Base_state_class {
}
);
}
+ */
}
/**
diff --git a/src/js/core/gui/gui-colors.js b/src/js/core/gui/gui-colors.js
index f5adf60..6bf5338 100644
--- a/src/js/core/gui/gui-colors.js
+++ b/src/js/core/gui/gui-colors.js
@@ -341,7 +341,6 @@ class GUI_colors_class {
// Initialize hex entry
this.inputs.hex
.on('input', (event) => {
- console.log(event);
const value = this.inputs.hex.val();
const trimmedValue = value.trim();
if (value !== trimmedValue) {
diff --git a/src/js/core/gui/gui-layers.js b/src/js/core/gui/gui-layers.js
index 68312ec..8f510ae 100644
--- a/src/js/core/gui/gui-layers.js
+++ b/src/js/core/gui/gui-layers.js
@@ -50,13 +50,15 @@ class GUI_layers_class {
}
else if (target.id == 'layer_up') {
//move layer up
- window.State.save();
- _this.Base_layers.move(config.layer.id, 1);
+ app.State.do_action(
+ new app.Actions.Reorder_layer_action(config.layer.id, 1)
+ );
}
else if (target.id == 'layer_down') {
//move layer down
- window.State.save();
- _this.Base_layers.move(config.layer.id, -1);
+ app.State.do_action(
+ new app.Actions.Reorder_layer_action(config.layer.id, -1)
+ );
}
else if (target.id == 'visibility') {
//change visibility
@@ -80,8 +82,9 @@ class GUI_layers_class {
}
else if (target.id == 'delete_filter') {
//delete filter
- window.State.save();
- _this.Base_layers.delete_filter(target.dataset.pid, target.dataset.id);
+ app.State.do_action(
+ new app.Actions.Delete_layer_filter_action(target.dataset.pid, target.dataset.id)
+ );
}
});
@@ -107,38 +110,40 @@ class GUI_layers_class {
document.getElementById(target_id).innerHTML = '';
var html = '';
+
+ if (config.layer) {
+ for (var i in layers) {
+ var value = layers[i];
- for (var i in layers) {
- var value = layers[i];
+ if (value.id == config.layer.id)
+ html += '
';
+ else
+ html += '
';
+ if (value.visible == true)
+ html += ' ';
+ else
+ html += ' ';
+ html += ' ';
+ html += ' ' + value.name + '';
+ html += ' ';
+ html += '
';
- if (value.id == config.layer.id)
- html += '
';
- else
- html += '
';
- if (value.visible == true)
- html += ' ';
- else
- html += ' ';
- html += ' ';
- html += ' ' + value.name + '';
- html += ' ';
- html += '
';
+ //show filters
+ if (layers[i].filters.length > 0) {
+ html += '
';
+ for (var j in layers[i].filters) {
+ var filter = layers[i].filters[j];
+ var title = this.Helper.ucfirst(filter.name);
+ title = title.replace(/-/g, ' ');
- //show filters
- if (layers[i].filters.length > 0) {
- html += '
';
- for (var j in layers[i].filters) {
- var filter = layers[i].filters[j];
- var title = this.Helper.ucfirst(filter.name);
- title = title.replace(/-/g, ' ');
-
- html += '
';
- html += ' ';
- html += ' ' + title + '';
- html += ' ';
+ html += '
';
+ html += ' ';
+ html += ' ' + title + '';
+ html += ' ';
+ html += '
';
+ }
html += '
';
}
- html += '
';
}
}
diff --git a/src/js/modules/effects/abstract/css.js b/src/js/modules/effects/abstract/css.js
index 28cb655..84f149b 100644
--- a/src/js/modules/effects/abstract/css.js
+++ b/src/js/modules/effects/abstract/css.js
@@ -1,3 +1,4 @@
+import app from './../../../app.js';
import config from './../../../config.js';
import Dialog_class from './../../../libs/popup.js';
import Base_layers_class from './../../../core/base-layers.js';
@@ -38,7 +39,9 @@ class Effects_common_class {
}
save(params, type) {
- this.Base_layers.add_filter(null, type, params);
+ return app.State.do_action(
+ new app.Actions.Add_layer_filter_action(null, type, params)
+ );
}
preview(params, type) {
diff --git a/src/js/modules/effects/black_and_white.js b/src/js/modules/effects/black_and_white.js
index 54cb4b1..1211967 100644
--- a/src/js/modules/effects/black_and_white.js
+++ b/src/js/modules/effects/black_and_white.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -66,7 +67,9 @@ class Effects_backAndWhite_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data, params) {
diff --git a/src/js/modules/effects/blueprint.js b/src/js/modules/effects/blueprint.js
index f548dbd..1fb9406 100644
--- a/src/js/modules/effects/blueprint.js
+++ b/src/js/modules/effects/blueprint.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -32,7 +33,9 @@ class Effects_blueprint_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/box_blur.js b/src/js/modules/effects/box_blur.js
index 8407f1a..736c331 100644
--- a/src/js/modules/effects/box_blur.js
+++ b/src/js/modules/effects/box_blur.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -52,7 +53,9 @@ class Effects_boxBlur_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data, params) {
diff --git a/src/js/modules/effects/denoise.js b/src/js/modules/effects/denoise.js
index cdc7481..a6be6f2 100644
--- a/src/js/modules/effects/denoise.js
+++ b/src/js/modules/effects/denoise.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -51,7 +52,9 @@ class Effects_denoise_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, params) {
diff --git a/src/js/modules/effects/dither.js b/src/js/modules/effects/dither.js
index a10646a..3ba4626 100644
--- a/src/js/modules/effects/dither.js
+++ b/src/js/modules/effects/dither.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -50,7 +51,9 @@ class Effects_dither_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data, params) {
diff --git a/src/js/modules/effects/dot_screen.js b/src/js/modules/effects/dot_screen.js
index e229dc0..f846e1f 100644
--- a/src/js/modules/effects/dot_screen.js
+++ b/src/js/modules/effects/dot_screen.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -51,7 +52,9 @@ class Effects_dotScreen_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, params) {
diff --git a/src/js/modules/effects/edge.js b/src/js/modules/effects/edge.js
index da99eb9..c8044f9 100644
--- a/src/js/modules/effects/edge.js
+++ b/src/js/modules/effects/edge.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -29,7 +30,9 @@ class Effects_edge_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data) {
diff --git a/src/js/modules/effects/emboss.js b/src/js/modules/effects/emboss.js
index 5536ec4..79079b7 100644
--- a/src/js/modules/effects/emboss.js
+++ b/src/js/modules/effects/emboss.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -29,7 +30,9 @@ class Effects_emboss_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data) {
diff --git a/src/js/modules/effects/enrich.js b/src/js/modules/effects/enrich.js
index 4d413d6..f72e623 100644
--- a/src/js/modules/effects/enrich.js
+++ b/src/js/modules/effects/enrich.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -48,7 +49,9 @@ class Effects_enrich_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data, params) {
diff --git a/src/js/modules/effects/grains.js b/src/js/modules/effects/grains.js
index 02fab7c..3db95c7 100644
--- a/src/js/modules/effects/grains.js
+++ b/src/js/modules/effects/grains.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -51,7 +52,9 @@ class Effects_grains_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data, params) {
diff --git a/src/js/modules/effects/heatmap.js b/src/js/modules/effects/heatmap.js
index ff37082..e08f451 100644
--- a/src/js/modules/effects/heatmap.js
+++ b/src/js/modules/effects/heatmap.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -28,7 +29,9 @@ class Effects_heatmap_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data) {
diff --git a/src/js/modules/effects/instagram/1977.js b/src/js/modules/effects/instagram/1977.js
index cf00ad5..8a3045f 100644
--- a/src/js/modules/effects/instagram/1977.js
+++ b/src/js/modules/effects/instagram/1977.js
@@ -1,3 +1,4 @@
+import app from '../../../app.js';
import config from '../../../config.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
@@ -29,7 +30,9 @@ class Effects_1977_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/instagram/aden.js b/src/js/modules/effects/instagram/aden.js
index 8240831..fb2dff7 100644
--- a/src/js/modules/effects/instagram/aden.js
+++ b/src/js/modules/effects/instagram/aden.js
@@ -1,4 +1,4 @@
-import config from '../../../config.js';
+import app from '../../../app.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
import alertify from 'alertifyjs/build/alertify.min.js';
@@ -16,8 +16,6 @@ class Effects_aden_class {
return;
}
- window.State.save();
-
//get canvas from layer
var canvas = this.Base_layers.convert_layer_to_canvas(null, true);
var ctx = canvas.getContext("2d");
@@ -28,7 +26,9 @@ class Effects_aden_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/instagram/clarendon.js b/src/js/modules/effects/instagram/clarendon.js
index 432eb1d..7c39bc7 100644
--- a/src/js/modules/effects/instagram/clarendon.js
+++ b/src/js/modules/effects/instagram/clarendon.js
@@ -1,3 +1,4 @@
+import app from '../../../app.js';
import config from '../../../config.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
@@ -29,7 +30,9 @@ class Effects_clarendon_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/instagram/gingham.js b/src/js/modules/effects/instagram/gingham.js
index 1e4ea79..219c8a1 100644
--- a/src/js/modules/effects/instagram/gingham.js
+++ b/src/js/modules/effects/instagram/gingham.js
@@ -1,3 +1,4 @@
+import app from '../../../app.js';
import config from '../../../config.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
@@ -28,7 +29,9 @@ class Effects_gingham_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/instagram/inkwell.js b/src/js/modules/effects/instagram/inkwell.js
index ae8f983..1f7d6cf 100644
--- a/src/js/modules/effects/instagram/inkwell.js
+++ b/src/js/modules/effects/instagram/inkwell.js
@@ -1,3 +1,4 @@
+import app from '../../../app.js';
import config from '../../../config.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
@@ -33,7 +34,9 @@ class Effects_inkwell_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/instagram/lofi.js b/src/js/modules/effects/instagram/lofi.js
index 681e388..816a4c5 100644
--- a/src/js/modules/effects/instagram/lofi.js
+++ b/src/js/modules/effects/instagram/lofi.js
@@ -1,3 +1,4 @@
+import app from '../../../app.js';
import config from '../../../config.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
@@ -27,7 +28,9 @@ class Effects_lofi_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/instagram/toaster.js b/src/js/modules/effects/instagram/toaster.js
index cfd3d1f..1a5bcd4 100644
--- a/src/js/modules/effects/instagram/toaster.js
+++ b/src/js/modules/effects/instagram/toaster.js
@@ -1,3 +1,4 @@
+import app from '../../../app.js';
import config from '../../../config.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
@@ -32,7 +33,9 @@ class Effects_toaster_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/instagram/valencia.js b/src/js/modules/effects/instagram/valencia.js
index 4252ec0..1adda0b 100644
--- a/src/js/modules/effects/instagram/valencia.js
+++ b/src/js/modules/effects/instagram/valencia.js
@@ -1,3 +1,4 @@
+import app from '../../../app.js';
import config from '../../../config.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
@@ -28,7 +29,9 @@ class Effects_valencia_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/instagram/xpro2.js b/src/js/modules/effects/instagram/xpro2.js
index 86465a9..9f0b20e 100644
--- a/src/js/modules/effects/instagram/xpro2.js
+++ b/src/js/modules/effects/instagram/xpro2.js
@@ -1,3 +1,4 @@
+import app from '../../../app.js';
import config from '../../../config.js';
import Dialog_class from '../../../libs/popup.js';
import Base_layers_class from '../../../core/base-layers.js';
@@ -28,7 +29,9 @@ class Effects_xpro2_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/mosaic.js b/src/js/modules/effects/mosaic.js
index 542238e..491f28b 100644
--- a/src/js/modules/effects/mosaic.js
+++ b/src/js/modules/effects/mosaic.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -50,7 +51,9 @@ class Effects_mosaic_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data, params) {
diff --git a/src/js/modules/effects/night_vision.js b/src/js/modules/effects/night_vision.js
index 1b46416..67e4d93 100644
--- a/src/js/modules/effects/night_vision.js
+++ b/src/js/modules/effects/night_vision.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -32,7 +33,9 @@ class Effects_nightVision_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/oil.js b/src/js/modules/effects/oil.js
index ea1a1fe..a08ec30 100644
--- a/src/js/modules/effects/oil.js
+++ b/src/js/modules/effects/oil.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -51,7 +52,9 @@ class Effects_oil_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data, params) {
diff --git a/src/js/modules/effects/pencil.js b/src/js/modules/effects/pencil.js
index b01e6dc..a04c4e1 100644
--- a/src/js/modules/effects/pencil.js
+++ b/src/js/modules/effects/pencil.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -28,7 +29,9 @@ class Effects_pencil_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, width, height) {
diff --git a/src/js/modules/effects/sharpen.js b/src/js/modules/effects/sharpen.js
index 928ed12..8d009c6 100644
--- a/src/js/modules/effects/sharpen.js
+++ b/src/js/modules/effects/sharpen.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -50,7 +51,9 @@ class Effects_sharpen_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data, params) {
diff --git a/src/js/modules/effects/solarize.js b/src/js/modules/effects/solarize.js
index acf77ca..d36233d 100644
--- a/src/js/modules/effects/solarize.js
+++ b/src/js/modules/effects/solarize.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -29,7 +30,9 @@ class Effects_solarize_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(data) {
diff --git a/src/js/modules/effects/tilt_shift.js b/src/js/modules/effects/tilt_shift.js
index b0dacaa..edab6d7 100644
--- a/src/js/modules/effects/tilt_shift.js
+++ b/src/js/modules/effects/tilt_shift.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -73,7 +74,9 @@ class Effects_tiltShift_class {
this.change(canvas, params);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, params) {
diff --git a/src/js/modules/effects/vibrance.js b/src/js/modules/effects/vibrance.js
index 3f5fc35..f2d2b1d 100644
--- a/src/js/modules/effects/vibrance.js
+++ b/src/js/modules/effects/vibrance.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -51,7 +52,9 @@ class Effects_vibrance_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, params) {
diff --git a/src/js/modules/effects/vignette.js b/src/js/modules/effects/vignette.js
index f2fbbc1..a12e0bb 100644
--- a/src/js/modules/effects/vignette.js
+++ b/src/js/modules/effects/vignette.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -52,7 +53,9 @@ class Effects_vignette_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, params) {
diff --git a/src/js/modules/effects/vintage.js b/src/js/modules/effects/vintage.js
index ae5d953..b11321f 100644
--- a/src/js/modules/effects/vintage.js
+++ b/src/js/modules/effects/vintage.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -49,7 +50,9 @@ class Effects_vintage_class {
this.change(canvas, params);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, params) {
diff --git a/src/js/modules/effects/zoom_blur.js b/src/js/modules/effects/zoom_blur.js
index 6b3a308..6248bf0 100644
--- a/src/js/modules/effects/zoom_blur.js
+++ b/src/js/modules/effects/zoom_blur.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Dialog_class from './../../libs/popup.js';
import Base_layers_class from './../../core/base-layers.js';
@@ -60,7 +61,9 @@ class Effects_zoomBlur_class {
ctx.drawImage(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
change(canvas, params) {
diff --git a/src/js/modules/image/auto_adjust.js b/src/js/modules/image/auto_adjust.js
index 17fedfc..84cf83b 100644
--- a/src/js/modules/image/auto_adjust.js
+++ b/src/js/modules/image/auto_adjust.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Base_layers_class from './../../core/base-layers.js';
import Dialog_class from './../../libs/popup.js';
@@ -54,7 +55,9 @@ class Image_autoAdjust_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
get_adjust_data(data) {
diff --git a/src/js/modules/image/color_corrections.js b/src/js/modules/image/color_corrections.js
index 3873b24..50de741 100644
--- a/src/js/modules/image/color_corrections.js
+++ b/src/js/modules/image/color_corrections.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Base_layers_class from './../../core/base-layers.js';
import Dialog_class from './../../libs/popup.js';
@@ -61,7 +62,9 @@ class Image_colorCorrections_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
do_corrections(data, params) {
diff --git a/src/js/modules/image/decrease_colors.js b/src/js/modules/image/decrease_colors.js
index ae7f90f..7707b7c 100644
--- a/src/js/modules/image/decrease_colors.js
+++ b/src/js/modules/image/decrease_colors.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Base_layers_class from './../../core/base-layers.js';
import Dialog_class from './../../libs/popup.js';
@@ -53,7 +54,9 @@ class Image_decreaseColors_class {
ctx.putImageData(data, 0, 0);
//save
- this.Base_layers.update_layer_image(canvas);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas)
+ );
}
get_decreased_data(data, colors, greyscale) {
diff --git a/src/js/modules/image/flip.js b/src/js/modules/image/flip.js
index 9708f87..fd6178f 100644
--- a/src/js/modules/image/flip.js
+++ b/src/js/modules/image/flip.js
@@ -1,3 +1,4 @@
+import app from './../../app.js';
import config from './../../config.js';
import Base_layers_class from './../../core/base-layers.js';
import alertify from './../../../../node_modules/alertifyjs/build/alertify.min.js';
@@ -47,7 +48,9 @@ class Image_flip_class {
}
//save
- this.Base_layers.update_layer_image(canvas2);
+ return app.State.do_action(
+ new app.Actions.Update_layer_image_action(canvas2)
+ );
}
}
diff --git a/src/js/modules/image/resize.js b/src/js/modules/image/resize.js
index eb3e8cb..0b37f6c 100644
--- a/src/js/modules/image/resize.js
+++ b/src/js/modules/image/resize.js
@@ -1,3 +1,4 @@
+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';
@@ -58,7 +59,7 @@ class Image_resize_class {
{name: "mode", title: "Mode:", values: ["Lanczos", "Hermite", "Basic"]},
{name: "sharpen", title: "Sharpen:", value: false},
- {name: "layers", title: "Layers:", values: ["Active", "All"], value: "Active"},
+ {name: "layers", title: "Layers:", values: ["All", "Active"], value: "All"},
],
on_finish: function (params) {
_this.do_resize(params);
@@ -67,50 +68,61 @@ class Image_resize_class {
this.POP.show(settings);
}
- do_resize(params) {
+ async do_resize(params) {
//validate
- if (isNaN(params.width) && isNaN(params.height) && isNaN(params.width_percent) && isNaN(params.height_percent)){
+ if (isNaN(params.width) && isNaN(params.height) && isNaN(params.width_percent) && isNaN(params.height_percent)) {
alertify.error('Missing at least 1 size parameter.');
return false;
}
- if (params.width == config.WIDTH && params.height == config.HEIGHT){
+ if (params.layers == 'All' && params.width == config.WIDTH && params.height == config.HEIGHT) {
return false;
}
window.State.save();
+
+ // Build a list of actions to execute for resize
+ let actions = [];
if (params.layers == 'All') {
//resize all layers
var skips = 0;
for (var i in config.layers) {
- var response = this.resize_layer(config.layers[i], params);
- if(response === false){
+ try {
+ actions = actions.concat(await this.resize_layer(config.layers[i], params));
+
+ } catch (error) {
skips++;
}
}
if (skips > 0) {
alertify.error(skips + ' layer(s) were skipped.');
}
+ actions = actions.concat(this.resize_gui(params));
}
else {
//only active
- this.resize_layer(config.layer, params);
+ actions = actions.concat(await this.resize_layer(config.layer, params));
}
+ return app.State.do_action(
+ new app.Actions.Bundle_action('resize_layers', 'Resize Layers', actions)
+ );
}
/**
- * it will try to resize layer (image, text, vector), returns false on failure.
+ * Generates actions that will resize layer (image, text, vector), returns a promise that rejects on failure.
*
* @param {object} layer
* @param {object} params
- * @returns {undefined|Boolean}
+ * @returns {Promise