Newer
Older
minerva / Userland / Libraries / LibGfx / ImageFormats / JPEGXLChannel.h
@minerva minerva on 13 Jul 3 KB Initial commit
/*
 * Copyright (c) 2025, Lucas Chollet <lucas.chollet@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#pragma once

#include <AK/Error.h>
#include <AK/Vector.h>

namespace Gfx {

struct ChannelInfo {
    static ChannelInfo from_size(IntSize size)
    {
        return {
            .width = static_cast<u32>(size.width()),
            .height = static_cast<u32>(size.height()),
        };
    }
    u32 width {};
    u32 height {};
    i8 hshift {};
    i8 vshift {};
};

class Channel {
public:
    static ErrorOr<Channel> create(ChannelInfo const& info)
    {
        Channel channel;

        channel.m_width = info.width;
        channel.m_height = info.height;
        channel.m_hshift = info.hshift;
        channel.m_vshift = info.vshift;

        TRY(channel.m_pixels.try_resize(channel.m_width * channel.m_height));

        return channel;
    }

    ErrorOr<Channel> copy(Optional<IntSize> destination_size = {}) const
    {
        Channel other;

        if (destination_size.has_value()) {
            VERIFY(static_cast<u32>(destination_size->width()) >= m_width);
            VERIFY(static_cast<u32>(destination_size->height()) >= m_height);
            other.m_width = destination_size->width();
            other.m_height = destination_size->height();
        } else {
            other.m_width = m_width;
            other.m_height = m_height;
        }
        other.m_hshift = m_hshift;
        other.m_vshift = m_vshift;
        other.m_decoded = m_decoded;

        TRY(other.m_pixels.try_resize(other.m_width * other.m_height));
        for (u32 y {}; y < m_height; ++y) {
            for (u32 x {}; x < m_width; ++x)
                other.set(x, y, get(x, y));
        }

        return other;
    }

    i32 get(u32 x, u32 y) const
    {
        return m_pixels[y * m_width + x];
    }

    void set(u32 x, u32 y, i32 value)
    {
        m_pixels[y * m_width + x] = value;
    }

    u32 width() const
    {
        return m_width;
    }

    u32 height() const
    {
        return m_height;
    }

    i8 hshift() const
    {
        return m_hshift;
    }

    i8 vshift() const
    {
        return m_vshift;
    }

    bool decoded() const
    {
        return m_decoded;
    }

    void set_decoded(bool decoded)
    {
        m_decoded = decoded;
    }

    void copy_from(IntRect destination, Channel const& other)
    {
        VERIFY(destination.left() >= 0);
        VERIFY(destination.top() >= 0);
        VERIFY(static_cast<u32>(destination.right()) <= m_width);
        VERIFY(static_cast<u32>(destination.bottom()) <= m_height);

        VERIFY(static_cast<u32>(destination.width()) == other.width());
        VERIFY(static_cast<u32>(destination.height()) == other.height());

        for (i32 y = 0; y < destination.height(); ++y) {
            for (i32 x = 0; x < destination.width(); ++x) {
                set(x + destination.left(), y + destination.top(), other.get(x, y));
            }
        }
    }

private:
    u32 m_width {};
    u32 m_height {};

    i8 m_hshift {};
    i8 m_vshift {};

    bool m_decoded { false };

    Vector<i32> m_pixels {};
};

}