Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ImageManager #334

Merged
merged 24 commits into from
Apr 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
ad202ca
Initial implementation of an ImageManager
Alecaddd Apr 20, 2020
eeae799
Fix linting issues
Alecaddd Apr 20, 2020
c73ccad
Fix linting issues
Alecaddd Apr 20, 2020
c3b2389
Attach image manager to the Window
Alecaddd Apr 22, 2020
d71c085
Validate accepted image types
Alecaddd Apr 22, 2020
3610781
Create static utils methods, remove ImageProvider
Alecaddd Apr 22, 2020
36bf285
Store base64 string of image file
Alecaddd Apr 22, 2020
eeed713
Send canvas notification if unable to get the pixbuf
Alecaddd Apr 22, 2020
bc290db
IJnitial work to save images inside the akira file
Alecaddd Apr 22, 2020
22a9a79
Save the image unique name for later. Do not go the base64 route
Alecaddd Apr 23, 2020
c1e1458
Save image inside the Pictures folder
Alecaddd Apr 24, 2020
c2be3a8
Merge branch 'master' into image-handler
Alecaddd Apr 24, 2020
edd5356
Delete picutre from saved file if not references anymore
Alecaddd Apr 24, 2020
a2e5884
Clear leftover images if saving the first time, in case we are overri…
Alecaddd Apr 24, 2020
1b3a8c1
Clear leftover images only on overwrite
Alecaddd Apr 24, 2020
e3a1550
Load saved images
Alecaddd Apr 24, 2020
74d0888
Resample pixbuf quality on image resize
Alecaddd Apr 24, 2020
4166bc7
Keep track of edited attributes
Alecaddd Apr 24, 2020
6394720
Remove unused methods
Alecaddd Apr 24, 2020
fe3f22e
Improve error message
Alecaddd Apr 25, 2020
63208d5
Use unique IDs for image filename
Alecaddd Apr 25, 2020
1928e0e
Prevent resetting pixbuf width and height when loading images from sa…
Alecaddd Apr 25, 2020
95b8edc
Restore the correct order of the items
Alecaddd Apr 25, 2020
687b8b2
Remove debug messages
Alecaddd Apr 25, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/FileFormat/AkiraFile.vala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public class Akira.FileFormat.AkiraFile : Akira.FileFormat.ZipArchiveHandler {
public File pictures_folder { get; private set; }
public File thumbnails_folder { get; private set; }

public bool overwrite = false;

private File content_file { get; set; }
public string path {
owned get {
Expand All @@ -45,6 +47,7 @@ public class Akira.FileFormat.AkiraFile : Akira.FileFormat.ZipArchiveHandler {
new FileFormat.JsonLoader (window, content_json);

update_recent_list.begin ();

debug ("Version from file: %s", content_json.get_string_member ("version"));
} catch (Error e) {
error ("Could not load file: %s", e.message);
Expand All @@ -53,6 +56,7 @@ public class Akira.FileFormat.AkiraFile : Akira.FileFormat.ZipArchiveHandler {

public void save_file () {
try {
save_images.begin ();
var content = new FileFormat.JsonContent (window);

content.save_content ();
Expand Down Expand Up @@ -126,4 +130,50 @@ public class Akira.FileFormat.AkiraFile : Akira.FileFormat.ZipArchiveHandler {

window.app.update_recent_files_list ();
}

/**
* Save all the images used in the Canvas and make a copy in the Pictures folder.
*/
public async void save_images () {
// Clear potential leftover images if we're overwriting an existing file.
if (overwrite) {
try {
Dir dir = Dir.open (pictures_folder.get_path (), 0);
string? name = null;
while ((name = dir.read_name ()) != null) {
var file = File.new_for_path (Path.build_filename (pictures_folder.get_path (), name));
file_collector.mark_for_deletion (file);
}
} catch (FileError err) {
stderr.printf (err.message);
}
overwrite = false;
}

foreach (var image in window.items_manager.images) {
var image_file = File.new_for_path (
Path.build_filename (pictures_folder.get_path (), image.manager.filename)
);

// Copy the file if it doesn't exist, or increase the reference count.
if (!image_file.query_exists ()) {
copy_image (image.manager.file, image_file);
continue;
}
}
}

/**
* Decrease the reference count to an existing image, which will cause its
* deletion if the count reaches 0.
*/
public async void remove_image (string filename) {
var image_file = File.new_for_path (
Path.build_filename (pictures_folder.get_path (), filename)
);

if (image_file.query_exists ()) {
file_collector.unref_file (image_file);
}
}
}
5 changes: 4 additions & 1 deletion src/FileFormat/FileManager.vala
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,20 @@ public class Akira.FileFormat.FileManager : Object {
}

private void save_file_as_response (Gtk.FileChooserNative dialog, int response_id) {
bool overwrite = false;

switch (response_id) {
case Gtk.ResponseType.ACCEPT:
File file;
var save_file = dialog.get_file ();
var path = save_file.get_path ();
if (path.has_suffix (".akira")) {
file = save_file;
overwrite = true;
} else {
file = File.new_for_path (path + ".akira");
}
window.save_new_file (file);
window.save_new_file (file, overwrite);
window.event_bus.file_saved (dialog.get_current_name ());
break;
}
Expand Down
7 changes: 6 additions & 1 deletion src/FileFormat/JsonObject.vala
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class Akira.FileFormat.JsonObject : GLib.Object {
}

transform = new Json.Object ();

write_transform ();
}

Expand Down Expand Up @@ -91,8 +92,12 @@ public class Akira.FileFormat.JsonObject : GLib.Object {
} else if (type == typeof (Goo.CanvasItemVisibility)) {
item.get_property (spec.get_name (), ref val);
obj.set_int_member (spec.get_name (), val.get_enum ());
} else if (type == typeof (Akira.Lib.Managers.ImageManager)) {
var canvas_image = item as Akira.Lib.Models.CanvasImage;
obj.set_string_member ("image_id", canvas_image.manager.filename);
} else {
// warning ("Property type %s not yet supported: %s\n", type.name (), spec.get_name ());
// Leave this comment for debug purpose.
// warning ("Property type %s not yet supported: %s\n", type.name (), spec.get_name ());
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/FileFormat/ZipArchiveHandler.vala
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,19 @@ public class Akira.FileFormat.ZipArchiveHandler : GLib.Object {
}
}

public virtual void copy_image (GLib.File old_file, GLib.File new_file) {
try {
old_file.copy (new_file, 0, null, (current_num_bytes, total_num_bytes) => {
// Report copy-status:
print ("%" + int64.FORMAT + " bytes of %" + int64.FORMAT + " bytes copied.\n",
current_num_bytes, total_num_bytes);
});
file_collector.ref_file (new_file);
} catch (Error e) {
print ("Error: %s\n", e.message);
}
}


/**
* Takes care of the reference counting for files inside the archive.
Expand Down
2 changes: 2 additions & 0 deletions src/Layouts/Partials/TransformPanel.vala
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ public class Akira.Layouts.Partials.TransformPanel : Gtk.Grid {
y.value = position["y"];
y.notify["value"].connect (y_notify_value);
}

window.event_bus.file_edited ();
}

public void x_notify_value () {
Expand Down
95 changes: 95 additions & 0 deletions src/Lib/Managers/ImageManager.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2020 Alecaddd (https://alecaddd.com)
*
* This file is part of Akira.
*
* Akira is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.

* Akira is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.

* You should have received a copy of the GNU General Public License
* along with Akira. If not, see <https://www.gnu.org/licenses/>.
*
* Authored by: Adam Bieńkowski <[email protected]>
* Authored by: Alessandro "Alecaddd" Castellani <[email protected]>
*/

public class Akira.Lib.Managers.ImageManager : Object {
public GLib.File file { get; set; }

// Save the generated Pixbuf for later reference.
public Gdk.Pixbuf pixbuf;
// The unique name of the loaded image, including the current timestamp.
public string filename;

private const string[] ACCEPTED_TYPES = {
"image/jpeg",
"image/png",
"image/tiff",
"image/svg+xml",
"image/gif"
};

public ImageManager (GLib.File _file, int id) {
file = _file;

var timestamp = new GLib.DateTime.now_utc ();
filename = ("akira-img-%i-%s.%s").printf (
id,
timestamp.to_unix ().to_string (),
Utils.Image.get_extension (file)
);
}

/**
* Initialize a new ImageManager from a previously saved file.
* We use this to avoid changing the filename which should be unique.
*
* @param {GLib.File} _file - The file loaded from the saved archive.
* @param {string} _filename - The original filename of the saved file.
*/
public ImageManager.from_archive (GLib.File _file, string _filename) {
file = _file;
filename = _filename;
}

/**
* Generate the Pixbuf from the given file. This method is also called to
* resample the quality of the pixbuf when the image is resized.
*
* @param {int} width - The requested width for the resample.
* @param {int} height - The requested height for the resample.
* @return Gdk.Pixbuf
*/
public async Gdk.Pixbuf get_pixbuf (int width = -1, int height = -1) throws Error {
FileInputStream stream;

try {
stream = yield file.read_async ();
} catch (Error e) {
throw e;
}

if (width != -1 && height != -1) {
try {
pixbuf = yield new Gdk.Pixbuf.from_stream_at_scale_async (stream, width, height, false);
return pixbuf;
} catch (Error e) {
throw e;
}
} else {
try {
pixbuf = yield new Gdk.Pixbuf.from_stream_async (stream);
return pixbuf;
} catch (Error e) {
throw e;
}
}
}
}
Loading