mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 20:15:17 +00:00
pdf: Add function to render a page of a PDF to a bitmap
Use like so: Build/lagom/bin/pdf --render foo.png --page=50 path/to.pdf
This commit is contained in:
parent
8c13b83a84
commit
c3f78d9561
Notes:
sideshowbarker
2024-07-17 23:02:37 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/c3f78d9561 Pull-request: https://github.com/SerenityOS/serenity/pull/19952
3 changed files with 58 additions and 2 deletions
|
@ -561,7 +561,7 @@ if (BUILD_LAGOM)
|
|||
endif()
|
||||
|
||||
add_executable(pdf ../../Userland/Utilities/pdf.cpp)
|
||||
target_link_libraries(pdf LibCore LibPDF LibMain)
|
||||
target_link_libraries(pdf LibCore LibGfx LibPDF LibMain)
|
||||
|
||||
add_executable(sql ../../Userland/Utilities/sql.cpp)
|
||||
target_link_libraries(sql LibCore LibFileSystem LibIPC LibLine LibMain LibSQL)
|
||||
|
|
|
@ -123,7 +123,7 @@ target_link_libraries(notify PRIVATE LibGfx LibGUI)
|
|||
target_link_libraries(open PRIVATE LibDesktop LibFileSystem)
|
||||
target_link_libraries(passwd PRIVATE LibCrypt)
|
||||
target_link_libraries(paste PRIVATE LibGUI)
|
||||
target_link_libraries(pdf PRIVATE LibPDF)
|
||||
target_link_libraries(pdf PRIVATE LibGfx LibPDF)
|
||||
target_link_libraries(pgrep PRIVATE LibRegex)
|
||||
target_link_libraries(pixelflut PRIVATE LibImageDecoderClient LibIPC LibGfx)
|
||||
target_link_libraries(pkill PRIVATE LibRegex)
|
||||
|
|
|
@ -4,11 +4,14 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/MappedFile.h>
|
||||
#include <LibGfx/ImageFormats/PNGWriter.h>
|
||||
#include <LibPDF/CommonNames.h>
|
||||
#include <LibPDF/Document.h>
|
||||
#include <LibPDF/Renderer.h>
|
||||
|
||||
static PDF::PDFErrorOr<void> print_document_info_dict(PDF::Document& document)
|
||||
{
|
||||
|
@ -41,6 +44,37 @@ static PDF::PDFErrorOr<void> print_document_info(PDF::Document& document)
|
|||
return {};
|
||||
}
|
||||
|
||||
static PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> render_page(PDF::Document& document, int page_index)
|
||||
{
|
||||
auto page = TRY(document.get_page(page_index));
|
||||
|
||||
auto page_size = Gfx::IntSize { 800, round_to<int>(800 * page.media_box.height() / page.media_box.width()) };
|
||||
|
||||
auto bitmap = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, page_size));
|
||||
|
||||
auto errors = PDF::Renderer::render(document, page, bitmap, PDF::RenderingPreferences {});
|
||||
if (errors.is_error()) {
|
||||
for (auto const& error : errors.error().errors())
|
||||
warnln("warning: {}", error.message());
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
static PDF::PDFErrorOr<void> save_rendered_page(PDF::Document& document, int page_index, StringView out_path)
|
||||
{
|
||||
auto bitmap = TRY(render_page(document, page_index));
|
||||
|
||||
if (!out_path.ends_with(".png"sv, CaseSensitivity::CaseInsensitive))
|
||||
return Error::from_string_view("can only save to .png files"sv);
|
||||
|
||||
auto output_stream = TRY(Core::File::open(out_path, Core::File::OpenMode::Write));
|
||||
auto buffered_stream = TRY(Core::OutputBufferedFile::create(move(output_stream)));
|
||||
ByteBuffer bytes = TRY(Gfx::PNGWriter::encode(*bitmap));
|
||||
TRY(buffered_stream->write_until_depleted(bytes));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static PDF::PDFErrorOr<int> pdf_main(Main::Arguments arguments)
|
||||
{
|
||||
Core::ArgsParser args_parser;
|
||||
|
@ -51,6 +85,12 @@ static PDF::PDFErrorOr<int> pdf_main(Main::Arguments arguments)
|
|||
StringView in_path;
|
||||
args_parser.add_positional_argument(in_path, "Path to input image file", "FILE");
|
||||
|
||||
StringView render_path;
|
||||
args_parser.add_option(render_path, "Path to render a PDF page to", "render", {}, "PNG FILE");
|
||||
|
||||
u32 page_number = 1;
|
||||
args_parser.add_option(page_number, "Page number (1-based)", "page", {}, "PAGE");
|
||||
|
||||
args_parser.parse(arguments);
|
||||
|
||||
auto file = TRY(Core::MappedFile::map(in_path));
|
||||
|
@ -70,6 +110,22 @@ static PDF::PDFErrorOr<int> pdf_main(Main::Arguments arguments)
|
|||
|
||||
TRY(document->initialize());
|
||||
|
||||
if (page_number < 1 || page_number > document->get_page_count()) {
|
||||
warnln("--page {} out of bounds, must be between 1 and {}", page_number, document->get_page_count());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!render_path.is_empty()) {
|
||||
#if !defined(AK_OS_SERENITY)
|
||||
// Get from Build/lagom/bin/pdf to Base/res/fonts.
|
||||
auto source_root = LexicalPath(arguments.argv[0]).parent().parent().parent().parent().string();
|
||||
Gfx::FontDatabase::set_default_fonts_lookup_path(DeprecatedString::formatted("{}/Base/res/fonts", source_root));
|
||||
#endif
|
||||
|
||||
TRY(save_rendered_page(document, page_number - 1, render_path));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRY(print_document_info(*document));
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue