mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 09:51:57 -05:00
PixelPaint: Use unveil to hide file system
This commit is contained in:
parent
62af82f494
commit
1927dbf025
6 changed files with 206 additions and 64 deletions
|
@ -2,7 +2,7 @@ serenity_component(
|
|||
PixelPaint
|
||||
RECOMMENDED
|
||||
TARGETS PixelPaint
|
||||
DEPENDS ImageDecoder
|
||||
DEPENDS ImageDecoder FileSystemAccessServer
|
||||
)
|
||||
|
||||
compile_gml(PixelPaintWindow.gml PixelPaintWindowGML.h pixel_paint_window_gml)
|
||||
|
@ -42,4 +42,4 @@ set(SOURCES
|
|||
)
|
||||
|
||||
serenity_app(PixelPaint ICON app-pixel-paint)
|
||||
target_link_libraries(PixelPaint LibImageDecoderClient LibGUI LibGfx)
|
||||
target_link_libraries(PixelPaint LibImageDecoderClient LibGUI LibGfx LibFileSystemAccessClient)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <AK/LexicalPath.h>
|
||||
#include <AK/MappedFile.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGfx/BMPWriter.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
|
@ -85,13 +84,27 @@ RefPtr<Image> Image::try_create_from_bitmap(NonnullRefPtr<Gfx::Bitmap> bitmap)
|
|||
return image;
|
||||
}
|
||||
|
||||
Result<NonnullRefPtr<Image>, String> Image::try_create_from_pixel_paint_file(String const& file_path)
|
||||
Result<NonnullRefPtr<Image>, String> Image::try_create_from_pixel_paint_fd(int fd, String const& file_path)
|
||||
{
|
||||
auto file = Core::File::construct();
|
||||
file->open(fd, Core::OpenMode::ReadOnly, Core::File::ShouldCloseFileDescriptor::No);
|
||||
if (file->has_error())
|
||||
return String { file->error_string() };
|
||||
|
||||
return try_create_from_pixel_paint_file(file, file_path);
|
||||
}
|
||||
|
||||
Result<NonnullRefPtr<Image>, String> Image::try_create_from_pixel_paint_path(String const& file_path)
|
||||
{
|
||||
auto file_or_error = Core::File::open(file_path, Core::OpenMode::ReadOnly);
|
||||
if (file_or_error.is_error())
|
||||
return file_or_error.error();
|
||||
|
||||
auto& file = *file_or_error.value();
|
||||
return try_create_from_pixel_paint_file(*file_or_error.value(), file_path);
|
||||
}
|
||||
|
||||
Result<NonnullRefPtr<Image>, String> Image::try_create_from_pixel_paint_file(Core::File& file, String const& file_path)
|
||||
{
|
||||
auto contents = file.read_all();
|
||||
|
||||
auto json_or_error = JsonValue::from_string(contents);
|
||||
|
@ -137,9 +150,33 @@ Result<NonnullRefPtr<Image>, String> Image::try_create_from_pixel_paint_file(Str
|
|||
return image.release_nonnull();
|
||||
}
|
||||
|
||||
Result<NonnullRefPtr<Image>, String> Image::try_create_from_file(String const& file_path)
|
||||
Result<NonnullRefPtr<Image>, String> Image::try_create_from_fd_and_close(int fd, String const& file_path)
|
||||
{
|
||||
auto image_or_error = try_create_from_pixel_paint_file(file_path);
|
||||
auto image_or_error = try_create_from_pixel_paint_fd(fd, file_path);
|
||||
if (!image_or_error.is_error()) {
|
||||
close(fd);
|
||||
return image_or_error.release_value();
|
||||
}
|
||||
|
||||
auto file_or_error = MappedFile::map_from_fd_and_close(fd, file_path);
|
||||
if (file_or_error.is_error())
|
||||
return String::formatted("Unable to mmap file {}", file_or_error.error().string());
|
||||
|
||||
auto& mapped_file = *file_or_error.value();
|
||||
// FIXME: Find a way to avoid the memory copy here.
|
||||
auto bitmap = try_decode_bitmap(ByteBuffer::copy(mapped_file.bytes()));
|
||||
if (!bitmap)
|
||||
return String { "Unable to decode image"sv };
|
||||
auto image = Image::try_create_from_bitmap(bitmap.release_nonnull());
|
||||
if (!image)
|
||||
return String { "Unable to allocate Image"sv };
|
||||
image->set_path(file_path);
|
||||
return image.release_nonnull();
|
||||
}
|
||||
|
||||
Result<NonnullRefPtr<Image>, String> Image::try_create_from_path(String const& file_path)
|
||||
{
|
||||
auto image_or_error = try_create_from_pixel_paint_path(file_path);
|
||||
if (!image_or_error.is_error())
|
||||
return image_or_error.release_value();
|
||||
|
||||
|
@ -159,6 +196,40 @@ Result<NonnullRefPtr<Image>, String> Image::try_create_from_file(String const& f
|
|||
return image.release_nonnull();
|
||||
}
|
||||
|
||||
Result<void, String> Image::write_to_fd_and_close(int fd) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
JsonObjectSerializer json(builder);
|
||||
json.add("width", m_size.width());
|
||||
json.add("height", m_size.height());
|
||||
{
|
||||
auto json_layers = json.add_array("layers");
|
||||
for (const auto& layer : m_layers) {
|
||||
Gfx::BMPWriter bmp_dumber;
|
||||
auto json_layer = json_layers.add_object();
|
||||
json_layer.add("width", layer.size().width());
|
||||
json_layer.add("height", layer.size().height());
|
||||
json_layer.add("name", layer.name());
|
||||
json_layer.add("locationx", layer.location().x());
|
||||
json_layer.add("locationy", layer.location().y());
|
||||
json_layer.add("opacity_percent", layer.opacity_percent());
|
||||
json_layer.add("visible", layer.is_visible());
|
||||
json_layer.add("selected", layer.is_selected());
|
||||
json_layer.add("bitmap", encode_base64(bmp_dumber.dump(layer.bitmap())));
|
||||
}
|
||||
}
|
||||
json.finish();
|
||||
|
||||
auto file = Core::File::construct();
|
||||
file->open(fd, Core::OpenMode::WriteOnly | Core::OpenMode::Truncate, Core::File::ShouldCloseFileDescriptor::Yes);
|
||||
if (file->has_error())
|
||||
return String { file->error_string() };
|
||||
|
||||
if (!file->write(builder.string_view()))
|
||||
return String { file->error_string() };
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, String> Image::write_to_file(const String& file_path) const
|
||||
{
|
||||
StringBuilder builder;
|
||||
|
@ -202,11 +273,12 @@ RefPtr<Gfx::Bitmap> Image::try_compose_bitmap(Gfx::BitmapFormat format) const
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
Result<void, String> Image::export_bmp_to_file(String const& file_path, bool preserve_alpha_channel)
|
||||
Result<void, String> Image::export_bmp_to_fd_and_close(int fd, bool preserve_alpha_channel)
|
||||
{
|
||||
auto file_or_error = Core::File::open(file_path, (Core::OpenMode)(Core::OpenMode::WriteOnly | Core::OpenMode::Truncate));
|
||||
if (file_or_error.is_error())
|
||||
return file_or_error.error();
|
||||
auto file = Core::File::construct();
|
||||
file->open(fd, Core::OpenMode::WriteOnly | Core::OpenMode::Truncate, Core::File::ShouldCloseFileDescriptor::Yes);
|
||||
if (file->has_error())
|
||||
return String { file->error_string() };
|
||||
|
||||
auto bitmap_format = preserve_alpha_channel ? Gfx::BitmapFormat::BGRA8888 : Gfx::BitmapFormat::BGRx8888;
|
||||
auto bitmap = try_compose_bitmap(bitmap_format);
|
||||
|
@ -216,18 +288,18 @@ Result<void, String> Image::export_bmp_to_file(String const& file_path, bool pre
|
|||
Gfx::BMPWriter dumper;
|
||||
auto encoded_data = dumper.dump(bitmap);
|
||||
|
||||
auto& file = *file_or_error.value();
|
||||
if (!file.write(encoded_data.data(), encoded_data.size()))
|
||||
if (!file->write(encoded_data.data(), encoded_data.size()))
|
||||
return String { "Failed to write encoded BMP data to file"sv };
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<void, String> Image::export_png_to_file(String const& file_path, bool preserve_alpha_channel)
|
||||
Result<void, String> Image::export_png_to_fd_and_close(int fd, bool preserve_alpha_channel)
|
||||
{
|
||||
auto file_or_error = Core::File::open(file_path, (Core::OpenMode)(Core::OpenMode::WriteOnly | Core::OpenMode::Truncate));
|
||||
if (file_or_error.is_error())
|
||||
return file_or_error.error();
|
||||
auto file = Core::File::construct();
|
||||
file->open(fd, Core::OpenMode::WriteOnly | Core::OpenMode::Truncate, Core::File::ShouldCloseFileDescriptor::Yes);
|
||||
if (file->has_error())
|
||||
return String { file->error_string() };
|
||||
|
||||
auto bitmap_format = preserve_alpha_channel ? Gfx::BitmapFormat::BGRA8888 : Gfx::BitmapFormat::BGRx8888;
|
||||
auto bitmap = try_compose_bitmap(bitmap_format);
|
||||
|
@ -235,8 +307,7 @@ Result<void, String> Image::export_png_to_file(String const& file_path, bool pre
|
|||
return String { "Failed to allocate bitmap for encoding"sv };
|
||||
|
||||
auto encoded_data = Gfx::PNGWriter::encode(*bitmap);
|
||||
auto& file = *file_or_error.value();
|
||||
if (!file.write(encoded_data.data(), encoded_data.size()))
|
||||
if (!file->write(encoded_data.data(), encoded_data.size()))
|
||||
return String { "Failed to write encoded PNG data to file"sv };
|
||||
|
||||
return {};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <AK/RefPtr.h>
|
||||
#include <AK/Result.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibGUI/Command.h>
|
||||
#include <LibGUI/Forward.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
|
@ -40,7 +41,8 @@ protected:
|
|||
class Image : public RefCounted<Image> {
|
||||
public:
|
||||
static RefPtr<Image> try_create_with_size(Gfx::IntSize const&);
|
||||
static Result<NonnullRefPtr<Image>, String> try_create_from_file(String const& file_path);
|
||||
static Result<NonnullRefPtr<Image>, String> try_create_from_fd_and_close(int fd, String const& file_path);
|
||||
static Result<NonnullRefPtr<Image>, String> try_create_from_path(String const& file_path);
|
||||
static RefPtr<Image> try_create_from_bitmap(NonnullRefPtr<Gfx::Bitmap>);
|
||||
|
||||
// This generates a new Bitmap with the final image (all layers composed according to their attributes.)
|
||||
|
@ -58,9 +60,10 @@ public:
|
|||
void restore_snapshot(Image const&);
|
||||
|
||||
void paint_into(GUI::Painter&, Gfx::IntRect const& dest_rect) const;
|
||||
Result<void, String> write_to_fd_and_close(int fd) const;
|
||||
Result<void, String> write_to_file(String const& file_path) const;
|
||||
Result<void, String> export_bmp_to_file(String const& file_path, bool preserve_alpha_channel);
|
||||
Result<void, String> export_png_to_file(String const& file_path, bool preserve_alpha_channel);
|
||||
Result<void, String> export_bmp_to_fd_and_close(int fd, bool preserve_alpha_channel);
|
||||
Result<void, String> export_png_to_fd_and_close(int fd, bool preserve_alpha_channel);
|
||||
|
||||
void move_layer_to_front(Layer&);
|
||||
void move_layer_to_back(Layer&);
|
||||
|
@ -89,7 +92,9 @@ public:
|
|||
private:
|
||||
explicit Image(Gfx::IntSize const&);
|
||||
|
||||
static Result<NonnullRefPtr<Image>, String> try_create_from_pixel_paint_file(String const& file_path);
|
||||
static Result<NonnullRefPtr<Image>, String> try_create_from_pixel_paint_fd(int fd, String const& file_path);
|
||||
static Result<NonnullRefPtr<Image>, String> try_create_from_pixel_paint_path(String const& file_path);
|
||||
static Result<NonnullRefPtr<Image>, String> try_create_from_pixel_paint_file(Core::File& file, String const& file_path);
|
||||
|
||||
void did_change(Gfx::IntRect const& modified_rect = {});
|
||||
void did_modify_layer_stack();
|
||||
|
|
|
@ -95,7 +95,7 @@ PaletteWidget::PaletteWidget()
|
|||
bottom_color_container.set_layout<GUI::HorizontalBoxLayout>();
|
||||
bottom_color_container.layout()->set_spacing(1);
|
||||
|
||||
auto result = load_palette_file("/res/color-palettes/default.palette");
|
||||
auto result = load_palette_path("/res/color-palettes/default.palette");
|
||||
if (result.is_error()) {
|
||||
GUI::MessageBox::show_error(window(), String::formatted("Loading default palette failed: {}", result.error()));
|
||||
display_color_list(fallback_colors());
|
||||
|
@ -192,14 +192,8 @@ Vector<Color> PaletteWidget::colors()
|
|||
return colors;
|
||||
}
|
||||
|
||||
Result<Vector<Color>, String> PaletteWidget::load_palette_file(String const& file_path)
|
||||
Result<Vector<Color>, String> PaletteWidget::load_palette_file(Core::File& file)
|
||||
{
|
||||
auto file_or_error = Core::File::open(file_path, Core::OpenMode::ReadOnly);
|
||||
if (file_or_error.is_error())
|
||||
return file_or_error.error();
|
||||
|
||||
auto& file = *file_or_error.value();
|
||||
|
||||
Vector<Color> palette;
|
||||
|
||||
while (file.can_read_line()) {
|
||||
|
@ -224,20 +218,39 @@ Result<Vector<Color>, String> PaletteWidget::load_palette_file(String const& fil
|
|||
return palette;
|
||||
}
|
||||
|
||||
Result<void, String> PaletteWidget::save_palette_file(Vector<Color> palette, String const& file_path)
|
||||
Result<Vector<Color>, String> PaletteWidget::load_palette_fd_and_close(int fd)
|
||||
{
|
||||
auto file_or_error = Core::File::open(file_path, Core::OpenMode::WriteOnly);
|
||||
auto file = Core::File::construct();
|
||||
file->open(fd, Core::OpenMode::ReadOnly, Core::File::ShouldCloseFileDescriptor::Yes);
|
||||
if (file->has_error())
|
||||
return String { file->error_string() };
|
||||
|
||||
return load_palette_file(file);
|
||||
}
|
||||
|
||||
Result<Vector<Color>, String> PaletteWidget::load_palette_path(String const& file_path)
|
||||
{
|
||||
auto file_or_error = Core::File::open(file_path, Core::OpenMode::ReadOnly);
|
||||
if (file_or_error.is_error())
|
||||
return file_or_error.error();
|
||||
|
||||
auto& file = *file_or_error.value();
|
||||
return load_palette_file(file);
|
||||
}
|
||||
|
||||
Result<void, String> PaletteWidget::save_palette_fd_and_close(Vector<Color> palette, int fd)
|
||||
{
|
||||
auto file = Core::File::construct();
|
||||
file->open(fd, Core::OpenMode::WriteOnly, Core::File::ShouldCloseFileDescriptor::Yes);
|
||||
if (file->has_error())
|
||||
return String { file->error_string() };
|
||||
|
||||
for (auto& color : palette) {
|
||||
file.write(color.to_string_without_alpha());
|
||||
file.write("\n");
|
||||
file->write(color.to_string_without_alpha());
|
||||
file->write("\n");
|
||||
}
|
||||
|
||||
file.close();
|
||||
file->close();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -28,13 +28,16 @@ public:
|
|||
|
||||
Vector<Color> colors();
|
||||
|
||||
static Result<Vector<Color>, String> load_palette_file(String const&);
|
||||
static Result<void, String> save_palette_file(Vector<Color>, String const&);
|
||||
static Result<Vector<Color>, String> load_palette_fd_and_close(int);
|
||||
static Result<Vector<Color>, String> load_palette_path(String const&);
|
||||
static Result<void, String> save_palette_fd_and_close(Vector<Color>, int);
|
||||
static Vector<Color> fallback_colors();
|
||||
|
||||
void set_image_editor(ImageEditor&);
|
||||
|
||||
private:
|
||||
static Result<Vector<Color>, String> load_palette_file(Core::File&);
|
||||
|
||||
explicit PaletteWidget();
|
||||
|
||||
ImageEditor* m_editor { nullptr };
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
#include <Applications/PixelPaint/PixelPaintWindowGML.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibFileSystemAccessClient/Client.h>
|
||||
#include <LibGUI/Action.h>
|
||||
#include <LibGUI/Application.h>
|
||||
#include <LibGUI/Clipboard.h>
|
||||
#include <LibGUI/FilePicker.h>
|
||||
#include <LibGUI/Icon.h>
|
||||
#include <LibGUI/Menubar.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
|
@ -50,6 +50,45 @@ int main(int argc, char** argv)
|
|||
args_parser.add_positional_argument(image_file, "Image file to open", "path", Core::ArgsParser::Required::No);
|
||||
args_parser.parse(argc, argv);
|
||||
|
||||
String file_to_edit_full_path;
|
||||
|
||||
if (image_file) {
|
||||
file_to_edit_full_path = Core::File::absolute_path(image_file);
|
||||
VERIFY(!file_to_edit_full_path.is_empty());
|
||||
if (Core::File::exists(file_to_edit_full_path)) {
|
||||
dbgln("unveil for: {}", file_to_edit_full_path);
|
||||
if (unveil(file_to_edit_full_path.characters(), "r") < 0) {
|
||||
perror("unveil");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unveil("/res", "r") < 0) {
|
||||
perror("unveil");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unveil("/tmp/portal/clipboard", "rw") < 0) {
|
||||
perror("unveil");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unveil("/tmp/portal/filesystemaccess", "rw") < 0) {
|
||||
perror("unveil");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unveil("/tmp/portal/image", "rw") < 0) {
|
||||
perror("unveil");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unveil(nullptr, nullptr) < 0) {
|
||||
perror("unveil");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto app_icon = GUI::Icon::default_icon("app-pixel-paint");
|
||||
|
||||
auto window = GUI::Window::construct();
|
||||
|
@ -111,7 +150,7 @@ int main(int argc, char** argv)
|
|||
window);
|
||||
|
||||
auto open_image_file = [&](auto& path) {
|
||||
auto image_or_error = PixelPaint::Image::try_create_from_file(path);
|
||||
auto image_or_error = PixelPaint::Image::try_create_from_path(path);
|
||||
if (image_or_error.is_error()) {
|
||||
GUI::MessageBox::show_error(window, String::formatted("Unable to open file: {}", path));
|
||||
return;
|
||||
|
@ -121,26 +160,38 @@ int main(int argc, char** argv)
|
|||
layer_list_widget.set_image(&image);
|
||||
};
|
||||
|
||||
auto open_image_action = GUI::CommonActions::make_open_action([&](auto&) {
|
||||
Optional<String> open_path = GUI::FilePicker::get_open_filepath(window);
|
||||
if (!open_path.has_value())
|
||||
auto open_image_fd = [&](int fd, auto& path) {
|
||||
auto image_or_error = PixelPaint::Image::try_create_from_fd_and_close(fd, path);
|
||||
if (image_or_error.is_error()) {
|
||||
GUI::MessageBox::show_error(window, String::formatted("Unable to open file: {}, {}", path, image_or_error.error()));
|
||||
return;
|
||||
open_image_file(open_path.value());
|
||||
}
|
||||
auto& image = *image_or_error.value();
|
||||
create_new_editor(image);
|
||||
layer_list_widget.set_image(&image);
|
||||
};
|
||||
|
||||
auto open_image_action = GUI::CommonActions::make_open_action([&](auto&) {
|
||||
auto result = FileSystemAccessClient::Client::the().open_file(window->window_id());
|
||||
if (result.error != 0)
|
||||
return;
|
||||
|
||||
open_image_fd(*result.fd, *result.chosen_file);
|
||||
});
|
||||
|
||||
auto save_image_as_action = GUI::CommonActions::make_save_as_action([&](auto&) {
|
||||
auto* editor = current_image_editor();
|
||||
if (!editor)
|
||||
return;
|
||||
auto save_path = GUI::FilePicker::get_save_filepath(window, "untitled", "pp");
|
||||
if (!save_path.has_value())
|
||||
auto save_result = FileSystemAccessClient::Client::the().save_file(window->window_id(), "untitled", "pp");
|
||||
if (save_result.error != 0)
|
||||
return;
|
||||
auto result = editor->image().write_to_file(save_path.value());
|
||||
auto result = editor->image().write_to_fd_and_close(*save_result.fd);
|
||||
if (result.is_error()) {
|
||||
GUI::MessageBox::show_error(window, String::formatted("Could not save {}: {}", save_path.value(), result.error()));
|
||||
GUI::MessageBox::show_error(window, String::formatted("Could not save {}: {}", *save_result.chosen_file, result.error()));
|
||||
return;
|
||||
}
|
||||
editor->image().set_path(save_path.value());
|
||||
editor->image().set_path(*save_result.chosen_file);
|
||||
});
|
||||
|
||||
auto& file_menu = window->add_menu("&File");
|
||||
|
@ -155,11 +206,11 @@ int main(int argc, char** argv)
|
|||
auto* editor = current_image_editor();
|
||||
if (!editor)
|
||||
return;
|
||||
auto save_path = GUI::FilePicker::get_save_filepath(window, "untitled", "bmp");
|
||||
if (!save_path.has_value())
|
||||
auto save_result = FileSystemAccessClient::Client::the().save_file(window->window_id(), "untitled", "bmp");
|
||||
if (save_result.error != 0)
|
||||
return;
|
||||
auto preserve_alpha_channel = GUI::MessageBox::show(window, "Do you wish to preserve transparency?", "Preserve transparency?", GUI::MessageBox::Type::Question, GUI::MessageBox::InputType::YesNo);
|
||||
auto result = editor->image().export_bmp_to_file(save_path.value(), preserve_alpha_channel == GUI::MessageBox::ExecYes);
|
||||
auto result = editor->image().export_bmp_to_fd_and_close(*save_result.fd, preserve_alpha_channel == GUI::MessageBox::ExecYes);
|
||||
if (result.is_error())
|
||||
GUI::MessageBox::show_error(window, String::formatted("Export to BMP failed: {}", result.error()));
|
||||
},
|
||||
|
@ -168,11 +219,11 @@ int main(int argc, char** argv)
|
|||
GUI::Action::create(
|
||||
"As &PNG", [&](auto&) {
|
||||
auto* editor = current_image_editor();
|
||||
auto save_path = GUI::FilePicker::get_save_filepath(window, "untitled", "png");
|
||||
if (!save_path.has_value())
|
||||
auto save_result = FileSystemAccessClient::Client::the().save_file(window->window_id(), "untitled", "png");
|
||||
if (save_result.error != 0)
|
||||
return;
|
||||
auto preserve_alpha_channel = GUI::MessageBox::show(window, "Do you wish to preserve transparency?", "Preserve transparency?", GUI::MessageBox::Type::Question, GUI::MessageBox::InputType::YesNo);
|
||||
auto result = editor->image().export_png_to_file(save_path.value(), preserve_alpha_channel == GUI::MessageBox::ExecYes);
|
||||
auto result = editor->image().export_png_to_fd_and_close(*save_result.fd, preserve_alpha_channel == GUI::MessageBox::ExecYes);
|
||||
if (result.is_error())
|
||||
GUI::MessageBox::show_error(window, String::formatted("Export to PNG failed: {}", result.error()));
|
||||
},
|
||||
|
@ -270,11 +321,11 @@ int main(int argc, char** argv)
|
|||
window));
|
||||
edit_menu.add_action(GUI::Action::create(
|
||||
"&Load Color Palette", [&](auto&) {
|
||||
auto open_path = GUI::FilePicker::get_open_filepath(window, "Load Color Palette");
|
||||
if (!open_path.has_value())
|
||||
auto open_result = FileSystemAccessClient::Client::the().open_file(window->window_id(), "Load Color Palette");
|
||||
if (open_result.error != 0)
|
||||
return;
|
||||
|
||||
auto result = PixelPaint::PaletteWidget::load_palette_file(open_path.value());
|
||||
auto result = PixelPaint::PaletteWidget::load_palette_fd_and_close(*open_result.fd);
|
||||
if (result.is_error()) {
|
||||
GUI::MessageBox::show_error(window, String::formatted("Loading color palette failed: {}", result.error()));
|
||||
return;
|
||||
|
@ -285,11 +336,11 @@ int main(int argc, char** argv)
|
|||
window));
|
||||
edit_menu.add_action(GUI::Action::create(
|
||||
"Sa&ve Color Palette", [&](auto&) {
|
||||
auto save_path = GUI::FilePicker::get_save_filepath(window, "untitled", "palette");
|
||||
if (!save_path.has_value())
|
||||
auto save_result = FileSystemAccessClient::Client::the().save_file(window->window_id(), "untitled", "palette");
|
||||
if (save_result.error != 0)
|
||||
return;
|
||||
|
||||
auto result = PixelPaint::PaletteWidget::save_palette_file(palette_widget.colors(), save_path.value());
|
||||
auto result = PixelPaint::PaletteWidget::save_palette_fd_and_close(palette_widget.colors(), *save_result.fd);
|
||||
if (result.is_error())
|
||||
GUI::MessageBox::show_error(window, String::formatted("Writing color palette failed: {}", result.error()));
|
||||
},
|
||||
|
@ -693,9 +744,8 @@ int main(int argc, char** argv)
|
|||
});
|
||||
};
|
||||
|
||||
auto image_file_real_path = Core::File::real_path_for(image_file);
|
||||
if (Core::File::exists(image_file_real_path)) {
|
||||
open_image_file(image_file_real_path);
|
||||
if (Core::File::exists(file_to_edit_full_path)) {
|
||||
open_image_file(file_to_edit_full_path);
|
||||
} else {
|
||||
auto image = PixelPaint::Image::try_create_with_size({ 480, 360 });
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue