summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNico Weber <thakis@chromium.org>2023-03-11 19:33:17 -0500
committerLinus Groh <mail@linusgroh.de>2023-03-12 12:17:26 +0000
commitb10ec6743f817d35450601e65fe89bc490ce0702 (patch)
tree801859a563cb625d4008bb6cf092c03d3a9e5343
parent3cff36b7ab427e040c9cac80a41cde9cfa0ac75d (diff)
downloadserenity-b10ec6743f817d35450601e65fe89bc490ce0702.zip
Userland: Add an `image` utility
At the moment, all it can do is read all image formats that LibGfx can read and save to any image format that LibGfx can write (currently bmp, png, qoi). Currently, it drops all image metadata (including color profiles). Over time, this could learn tricks like keeping color profiles, converting an image to a different color profile, cropping out a part of an image, and so on.
-rw-r--r--Meta/Lagom/CMakeLists.txt3
-rw-r--r--Userland/Utilities/CMakeLists.txt1
-rw-r--r--Userland/Utilities/image.cpp55
3 files changed, 59 insertions, 0 deletions
diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt
index 3cc6a424ef..f683d435c5 100644
--- a/Meta/Lagom/CMakeLists.txt
+++ b/Meta/Lagom/CMakeLists.txt
@@ -510,6 +510,9 @@ if (BUILD_LAGOM)
add_executable(icc ../../Userland/Utilities/icc.cpp)
target_link_libraries(icc LibCore LibGfx LibMain)
+ add_executable(image ../../Userland/Utilities/image.cpp)
+ target_link_libraries(image LibCore LibGfx LibMain)
+
add_executable(ttfdisasm ../../Userland/Utilities/ttfdisasm.cpp)
target_link_libraries(ttfdisasm LibGfx LibMain)
diff --git a/Userland/Utilities/CMakeLists.txt b/Userland/Utilities/CMakeLists.txt
index ec1928cf68..530a5811ac 100644
--- a/Userland/Utilities/CMakeLists.txt
+++ b/Userland/Utilities/CMakeLists.txt
@@ -95,6 +95,7 @@ target_link_libraries(gunzip PRIVATE LibCompress)
target_link_libraries(gzip PRIVATE LibCompress)
target_link_libraries(headless-browser PRIVATE LibCrypto LibGemini LibGfx LibHTTP LibTLS LibWeb LibWebSocket LibIPC LibJS)
target_link_libraries(icc PRIVATE LibGfx LibVideo)
+target_link_libraries(image PRIVATE LibGfx)
target_link_libraries(image2bin PRIVATE LibGfx)
target_link_libraries(jail-attach PRIVATE LibCore LibMain)
target_link_libraries(jail-create PRIVATE LibCore LibMain)
diff --git a/Userland/Utilities/image.cpp b/Userland/Utilities/image.cpp
new file mode 100644
index 0000000000..fa105303b9
--- /dev/null
+++ b/Userland/Utilities/image.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023, Nico Weber <thakis@chromium.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibCore/ArgsParser.h>
+#include <LibCore/File.h>
+#include <LibCore/MappedFile.h>
+#include <LibGfx/BMPWriter.h>
+#include <LibGfx/ImageDecoder.h>
+#include <LibGfx/PNGWriter.h>
+#include <LibGfx/QOIWriter.h>
+
+ErrorOr<int> serenity_main(Main::Arguments arguments)
+{
+ Core::ArgsParser args_parser;
+
+ StringView in_path;
+ args_parser.add_positional_argument(in_path, "Path to input image file", "FILE");
+
+ StringView out_path;
+ args_parser.add_option(out_path, "Path to output image file", "output", 'o', "FILE");
+
+ args_parser.parse(arguments);
+
+ if (out_path.is_empty()) {
+ warnln("-o is required");
+ return 1;
+ }
+
+ auto file = TRY(Core::MappedFile::map(in_path));
+ auto decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(file->bytes());
+
+ // This uses ImageDecoder instead of Bitmap::load_from_file() to have more control
+ // over selecting a frame, access color profile data, and so on in the future.
+ auto frame = TRY(decoder->frame(0)).image;
+
+ ByteBuffer bytes;
+ if (out_path.ends_with(".bmp"sv, CaseSensitivity::CaseInsensitive)) {
+ bytes = Gfx::BMPWriter().dump(frame);
+ } else if (out_path.ends_with(".png"sv, CaseSensitivity::CaseInsensitive)) {
+ bytes = TRY(Gfx::PNGWriter::encode(*frame));
+ } else if (out_path.ends_with(".qoi"sv, CaseSensitivity::CaseInsensitive)) {
+ bytes = Gfx::QOIWriter::encode(*frame);
+ } else {
+ warnln("can only write .bmp, .png, and .qoi");
+ return 1;
+ }
+
+ auto output_stream = TRY(Core::File::open(out_path, Core::File::OpenMode::Write));
+ TRY(output_stream->write_entire_buffer(bytes));
+
+ return 0;
+}