Repository: SerenityOS/serenity
File: Userland/Utilities/pdf.cpp (C++)

Code before:
#include <LibCore/ResourceImplementationFile.h>
#include <LibCore/System.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(PDF::Document& document, bool json)
{
    JsonObject json_output;

    if (!json) {
        outln("PDF Version: {}.{}", document.version().major, document.version().minor);
        outln("Number of pages: {}", document.get_page_count());
    } else {
        JsonObject version;
        version.set("major", document.version().major);
        version.set("minor", document.version().minor);
        json_output.set("version", version);
        json_output.set("page_count", document.get_page_count());
    }

    if (auto info_dict = TRY(document.info_dict()); info_dict.has_value()) {
        if (!json) {
            if (auto title = TRY(info_dict->title()); title.has_value())
                outln("Title: {}", title);
            if (auto author = TRY(info_dict->author()); author.has_value())
                outln("Author: {}", author);
            if (auto subject = TRY(info_dict->subject()); subject.has_value())
                outln("Subject: {}", subject);
            if (auto keywords = TRY(info_dict->keywords()); keywords.has_value())
                outln("Keywords: {}", keywords);
            if (auto creator = TRY(info_dict->creator()); creator.has_value())
                outln("Creator: {}", creator);
            if (auto producer = TRY(info_dict->producer()); producer.has_value())
                outln("Producer: {}", producer);
            if (auto creation_date = TRY(info_dict->creation_date()); creation_date.has_value())
                outln("Creation date: {}", creation_date);
            if (auto modification_date = TRY(info_dict->modification_date()); modification_date.has_value())
                outln("Modification date: {}", modification_date);
        } else {
            if (auto title = TRY(info_dict->title()); title.has_value())
                json_output.set("title", title.value().to_byte_string());
            if (auto author = TRY(info_dict->author()); author.has_value())
                json_output.set("author", author.value().to_byte_string());
            if (auto subject = TRY(info_dict->subject()); subject.has_value())
                json_output.set("subject", subject.value().to_byte_string());
            if (auto keywords = TRY(info_dict->keywords()); keywords.has_value())
                json_output.set("keywords", keywords.value().to_byte_string());
            if (auto creator = TRY(info_dict->creator()); creator.has_value())
                json_output.set("creator", creator.value().to_byte_string());

Review comment (refactor):
Can you come up with a way of writing this that doesn't duplicate the function? Maybe add a local `emit(long_text, json_key, T value)` lambda that either outln()s or set()s based on `json` and call `emit()` instead of `outln()` or something.

Code after:
#include <LibCore/ResourceImplementationFile.h>
#include <LibCore/System.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(PDF::Document& document, bool json)
{
    JsonObject json_output;
    auto emit = [&](StringView long_text, StringView json_key, StringView value) {
        if (!json) {
            outln("{}: {}", long_text, value);
        } else {
            json_output.set(json_key, value);
        }
    };

    emit("PDF Version"sv, "version"sv, TRY(String::formatted("{}.{}", document.version().major, document.version().minor)));
    emit("Number of pages"sv, "page_count"sv, String::number(document.get_page_count()));

    if (auto info_dict = TRY(document.info_dict()); info_dict.has_value()) {
        if (auto title = TRY(info_dict->title()); title.has_value())
            emit("Title"sv, "title"sv, title.value());
        if (auto author = TRY(info_dict->author()); author.has_value())
            emit("Author"sv, "author"sv, author.value());
        if (auto subject = TRY(info_dict->subject()); subject.has_value())
            emit("Subject"sv, "subject"sv, subject.value());
        if (auto keywords = TRY(info_dict->keywords()); keywords.has_value())
            emit("Keywords"sv, "keywords"sv, keywords.value());
        if (auto creator = TRY(info_dict->creator()); creator.has_value())
            emit("Creator"sv, "creator"sv, creator.value());
        if (auto producer = TRY(info_dict->producer()); producer.has_value())
            emit("Producer"sv, "producer"sv, producer.value());
        if (auto creation_date = TRY(info_dict->creation_date()); creation_date.has_value())
            emit("Creation date"sv, "creation_date"sv, creation_date.value());
        if (auto modification_date = TRY(info_dict->modification_date()); modification_date.has_value())
            emit("Modification date"sv, "modification_date"sv, modification_date.value());
    }

    if (json)
        outln("{}", json_output.to_byte_string());

    return {};
}

static PDF::PDFErrorOr<NonnullRefPtr<Gfx::Bitmap>> render_page(PDF::Document& document, PDF::Page const& page)
{
    auto page_size = Gfx::IntSize { 800, round_to<int>(800 * page.media_box.height() / page.media_box.width()) };
    if (int rotation_count = (page.rotate / 90) % 4; rotation_count % 2 == 1)
        page_size = Gfx::IntSize { round_to<int>(800 * page.media_box.width() / page.media_box.height()), 800 };