2020-01-18 09:38:21 +01:00
|
|
|
/*
|
2024-10-04 13:19:50 +02:00
|
|
|
* Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
|
2022-09-30 12:26:13 -05:00
|
|
|
* Copyright (c) 2022, Timothy Slater <tslater2006@gmail.com>
|
2024-11-01 12:14:53 +01:00
|
|
|
* Copyright (c) 2024, Jelle Raaijmakers <jelle@ladybird.org>
|
2020-01-18 09:38:21 +01:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 09:38:21 +01:00
|
|
|
*/
|
|
|
|
|
2022-09-30 12:26:13 -05:00
|
|
|
#include <AK/Bitmap.h>
|
2020-04-15 16:55:07 +02:00
|
|
|
#include <AK/Checked.h>
|
2020-06-22 21:35:22 +02:00
|
|
|
#include <LibGfx/Bitmap.h>
|
2020-03-29 19:04:05 +02:00
|
|
|
#include <LibGfx/ShareableBitmap.h>
|
2021-07-24 22:49:48 +02:00
|
|
|
#include <errno.h>
|
2019-02-07 23:13:47 +01:00
|
|
|
|
2020-02-06 11:56:38 +01:00
|
|
|
namespace Gfx {
|
|
|
|
|
2020-09-12 17:17:50 +01:00
|
|
|
struct BackingStore {
|
|
|
|
void* data { nullptr };
|
|
|
|
size_t pitch { 0 };
|
|
|
|
size_t size_in_bytes { 0 };
|
|
|
|
};
|
|
|
|
|
2024-06-05 08:17:28 +02:00
|
|
|
size_t Bitmap::minimum_pitch(size_t width, BitmapFormat format)
|
2020-09-06 23:59:20 +02:00
|
|
|
{
|
|
|
|
size_t element_size;
|
|
|
|
switch (determine_storage_format(format)) {
|
2021-03-16 12:00:43 +01:00
|
|
|
case StorageFormat::BGRx8888:
|
|
|
|
case StorageFormat::BGRA8888:
|
2024-11-03 03:12:14 +04:00
|
|
|
case StorageFormat::RGBx8888:
|
2021-03-16 12:09:15 +01:00
|
|
|
case StorageFormat::RGBA8888:
|
2020-09-06 23:59:20 +02:00
|
|
|
element_size = 4;
|
|
|
|
break;
|
|
|
|
default:
|
2021-02-23 20:42:32 +01:00
|
|
|
VERIFY_NOT_REACHED();
|
2020-09-06 23:59:20 +02:00
|
|
|
}
|
|
|
|
|
2024-06-05 08:17:28 +02:00
|
|
|
return width * element_size;
|
2020-09-06 23:59:20 +02:00
|
|
|
}
|
|
|
|
|
2024-06-05 08:17:28 +02:00
|
|
|
static bool size_would_overflow(BitmapFormat format, IntSize size)
|
2019-02-11 09:47:10 +01:00
|
|
|
{
|
2020-04-15 11:57:24 +02:00
|
|
|
if (size.width() < 0 || size.height() < 0)
|
|
|
|
return true;
|
2020-08-30 14:18:54 +02:00
|
|
|
// This check is a bit arbitrary, but should protect us from most shenanigans:
|
2024-06-05 08:17:28 +02:00
|
|
|
if (size.width() >= INT16_MAX || size.height() >= INT16_MAX)
|
2020-08-30 14:18:54 +02:00
|
|
|
return true;
|
2020-09-06 23:59:20 +02:00
|
|
|
// In contrast, this check is absolutely necessary:
|
2024-06-05 08:17:28 +02:00
|
|
|
size_t pitch = Bitmap::minimum_pitch(size.width(), format);
|
|
|
|
return Checked<size_t>::multiplication_would_overflow(pitch, size.height());
|
2020-04-15 11:57:24 +02:00
|
|
|
}
|
|
|
|
|
2024-06-05 08:17:28 +02:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create(BitmapFormat format, IntSize size)
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
{
|
|
|
|
// For backwards compatibility, premultiplied alpha is assumed
|
|
|
|
return create(format, AlphaType::Premultiplied, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create(BitmapFormat format, AlphaType alpha_type, IntSize size)
|
2020-04-15 11:57:24 +02:00
|
|
|
{
|
2024-06-05 08:17:28 +02:00
|
|
|
auto backing_store = TRY(Bitmap::allocate_backing_store(format, size));
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
return AK::adopt_nonnull_ref_or_enomem(new (nothrow) Bitmap(format, alpha_type, size, backing_store));
|
2021-01-02 16:23:04 +01:00
|
|
|
}
|
|
|
|
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create_shareable(BitmapFormat format, AlphaType alpha_type, IntSize size)
|
2021-01-02 16:23:04 +01:00
|
|
|
{
|
2024-06-05 08:17:28 +02:00
|
|
|
if (size_would_overflow(format, size))
|
2023-01-20 20:06:05 +01:00
|
|
|
return Error::from_string_literal("Gfx::Bitmap::create_shareable size overflow");
|
2021-01-02 16:23:04 +01:00
|
|
|
|
2024-06-05 08:17:28 +02:00
|
|
|
auto const pitch = minimum_pitch(size.width(), format);
|
|
|
|
auto const data_size = size_in_bytes(pitch, size.height());
|
2021-01-16 23:14:24 +01:00
|
|
|
|
2021-11-06 11:44:05 +01:00
|
|
|
auto buffer = TRY(Core::AnonymousBuffer::create_with_size(round_up_to_power_of_two(data_size, PAGE_SIZE)));
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
auto bitmap = TRY(Bitmap::create_with_anonymous_buffer(format, alpha_type, buffer, size));
|
2021-11-06 11:44:05 +01:00
|
|
|
return bitmap;
|
2019-12-18 20:50:05 +01:00
|
|
|
}
|
|
|
|
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
Bitmap::Bitmap(BitmapFormat format, AlphaType alpha_type, IntSize size, BackingStore const& backing_store)
|
2019-02-11 09:47:10 +01:00
|
|
|
: m_size(size)
|
2020-09-12 17:17:50 +01:00
|
|
|
, m_data(backing_store.data)
|
|
|
|
, m_pitch(backing_store.pitch)
|
2019-02-19 01:42:53 +01:00
|
|
|
, m_format(format)
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
, m_alpha_type(alpha_type)
|
2019-02-11 09:47:10 +01:00
|
|
|
{
|
2021-02-23 20:42:32 +01:00
|
|
|
VERIFY(!m_size.is_empty());
|
2024-06-05 08:17:28 +02:00
|
|
|
VERIFY(!size_would_overflow(format, size));
|
2021-02-23 20:42:32 +01:00
|
|
|
VERIFY(m_data);
|
|
|
|
VERIFY(backing_store.size_in_bytes == size_in_bytes());
|
2024-06-18 02:11:35 +03:00
|
|
|
m_destruction_callback = [data = m_data, size_in_bytes = this->size_in_bytes()] {
|
|
|
|
kfree_sized(data, size_in_bytes);
|
|
|
|
};
|
2019-02-16 12:22:00 +01:00
|
|
|
}
|
2019-01-14 20:00:42 +01:00
|
|
|
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create_wrapper(BitmapFormat format, AlphaType alpha_type, IntSize size, size_t pitch, void* data, Function<void()>&& destruction_callback)
|
2019-01-14 20:00:42 +01:00
|
|
|
{
|
2024-06-05 08:17:28 +02:00
|
|
|
if (size_would_overflow(format, size))
|
2023-01-20 20:06:05 +01:00
|
|
|
return Error::from_string_literal("Gfx::Bitmap::create_wrapper size overflow");
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
return adopt_ref(*new Bitmap(format, alpha_type, size, pitch, data, move(destruction_callback)));
|
2019-01-14 20:00:42 +01:00
|
|
|
}
|
2019-01-09 03:51:34 +01:00
|
|
|
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
Bitmap::Bitmap(BitmapFormat format, AlphaType alpha_type, IntSize size, size_t pitch, void* data, Function<void()>&& destruction_callback)
|
2019-01-09 03:51:34 +01:00
|
|
|
: m_size(size)
|
2019-01-10 05:36:32 +01:00
|
|
|
, m_data(data)
|
2019-08-19 13:29:19 +02:00
|
|
|
, m_pitch(pitch)
|
2019-02-19 01:42:53 +01:00
|
|
|
, m_format(format)
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
, m_alpha_type(alpha_type)
|
2024-06-18 02:11:35 +03:00
|
|
|
, m_destruction_callback(move(destruction_callback))
|
2019-01-09 03:51:34 +01:00
|
|
|
{
|
2024-06-05 08:17:28 +02:00
|
|
|
VERIFY(pitch >= minimum_pitch(size.width(), format));
|
|
|
|
VERIFY(!size_would_overflow(format, size));
|
2020-09-06 23:59:20 +02:00
|
|
|
// FIXME: assert that `data` is actually long enough!
|
2019-01-09 02:06:04 +01:00
|
|
|
}
|
|
|
|
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create_with_anonymous_buffer(BitmapFormat format, AlphaType alpha_type, Core::AnonymousBuffer buffer, IntSize size)
|
2021-01-15 12:09:37 +01:00
|
|
|
{
|
2024-06-05 08:17:28 +02:00
|
|
|
if (size_would_overflow(format, size))
|
2023-01-20 20:06:05 +01:00
|
|
|
return Error::from_string_literal("Gfx::Bitmap::create_with_anonymous_buffer size overflow");
|
2021-01-15 12:09:37 +01:00
|
|
|
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
return adopt_nonnull_ref_or_enomem(new (nothrow) Bitmap(format, alpha_type, move(buffer), size));
|
2022-11-25 10:56:48 +08:00
|
|
|
}
|
|
|
|
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
Bitmap::Bitmap(BitmapFormat format, AlphaType alpha_type, Core::AnonymousBuffer buffer, IntSize size)
|
2021-01-15 12:09:37 +01:00
|
|
|
: m_size(size)
|
2021-05-24 12:24:38 +02:00
|
|
|
, m_data(buffer.data<void>())
|
2024-06-05 08:17:28 +02:00
|
|
|
, m_pitch(minimum_pitch(size.width(), format))
|
2021-01-15 12:09:37 +01:00
|
|
|
, m_format(format)
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
, m_alpha_type(alpha_type)
|
2021-07-07 17:33:35 +02:00
|
|
|
, m_buffer(move(buffer))
|
2021-01-15 12:09:37 +01:00
|
|
|
{
|
2024-06-05 08:17:28 +02:00
|
|
|
VERIFY(!size_would_overflow(format, size));
|
2021-01-15 12:09:37 +01:00
|
|
|
}
|
|
|
|
|
2021-11-06 11:52:35 +01:00
|
|
|
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Bitmap::clone() const
|
2020-09-12 12:20:34 +01:00
|
|
|
{
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
auto new_bitmap = TRY(Bitmap::create(format(), alpha_type(), size()));
|
2020-09-12 12:20:34 +01:00
|
|
|
|
2021-02-23 20:42:32 +01:00
|
|
|
VERIFY(size_in_bytes() == new_bitmap->size_in_bytes());
|
2020-09-12 12:20:34 +01:00
|
|
|
memcpy(new_bitmap->scanline(0), scanline(0), size_in_bytes());
|
|
|
|
|
2021-11-06 19:30:59 +01:00
|
|
|
return new_bitmap;
|
2020-09-12 12:20:34 +01:00
|
|
|
}
|
|
|
|
|
2023-09-03 19:24:00 +01:00
|
|
|
void Bitmap::apply_mask(Gfx::Bitmap const& mask, MaskKind mask_kind)
|
|
|
|
{
|
|
|
|
VERIFY(size() == mask.size());
|
|
|
|
|
|
|
|
for (int y = 0; y < height(); y++) {
|
|
|
|
for (int x = 0; x < width(); x++) {
|
|
|
|
auto color = get_pixel(x, y);
|
|
|
|
auto mask_color = mask.get_pixel(x, y);
|
|
|
|
if (mask_kind == MaskKind::Luminance) {
|
|
|
|
color = color.with_alpha(color.alpha() * mask_color.alpha() * mask_color.luminosity() / (255 * 255));
|
|
|
|
} else {
|
|
|
|
VERIFY(mask_kind == MaskKind::Alpha);
|
|
|
|
color = color.with_alpha(color.alpha() * mask_color.alpha() / 255);
|
|
|
|
}
|
|
|
|
set_pixel(x, y, color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-15 08:31:29 +01:00
|
|
|
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Bitmap::cropped(Gfx::IntRect crop, Optional<BitmapFormat> new_bitmap_format) const
|
2021-05-09 22:19:04 +03:00
|
|
|
{
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
auto new_bitmap = TRY(Gfx::Bitmap::create(new_bitmap_format.value_or(format()), alpha_type(), { crop.width(), crop.height() }));
|
2024-06-05 08:17:28 +02:00
|
|
|
|
|
|
|
for (int y = 0; y < crop.height(); ++y) {
|
|
|
|
for (int x = 0; x < crop.width(); ++x) {
|
|
|
|
int global_x = x + crop.left();
|
|
|
|
int global_y = y + crop.top();
|
|
|
|
if (global_x >= width() || global_y >= height() || global_x < 0 || global_y < 0) {
|
2021-05-09 22:19:04 +03:00
|
|
|
new_bitmap->set_pixel(x, y, Gfx::Color::Black);
|
|
|
|
} else {
|
|
|
|
new_bitmap->set_pixel(x, y, get_pixel(global_x, global_y));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-06 19:30:59 +01:00
|
|
|
return new_bitmap;
|
2021-05-09 22:19:04 +03:00
|
|
|
}
|
|
|
|
|
2021-11-06 13:15:43 +01:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::to_bitmap_backed_by_anonymous_buffer() const
|
2021-01-15 22:36:36 +01:00
|
|
|
{
|
2023-02-19 23:02:17 +01:00
|
|
|
if (m_buffer.is_valid()) {
|
|
|
|
// FIXME: The const_cast here is awkward.
|
|
|
|
return NonnullRefPtr { const_cast<Bitmap&>(*this) };
|
|
|
|
}
|
2021-11-06 13:15:43 +01:00
|
|
|
auto buffer = TRY(Core::AnonymousBuffer::create_with_size(round_up_to_power_of_two(size_in_bytes(), PAGE_SIZE)));
|
LibGfx: Store alpha type information in `Gfx::Bitmap`
We use instances of `Gfx::Bitmap` to move pixel data all the way from
raw image bytes up to the Skia renderer. A vital piece of information
for correct blending of bitmaps is the alpha type, i.e. are we dealing
with premultiplied or unpremultiplied color values?
Premultiplied means that the RGB colors have been multiplied with the
associated alpha value, i.e. RGB(255, 255, 255) with an alpha of 2% is
stored as RGBA(5, 5, 5, 2%).
Unpremultiplied means that the original RGB colors are stored,
regardless of the alpha value. I.e. RGB(255, 255, 255) with an alpha of
2% is stored as RGBA(255, 255, 255, 2%).
It is important to know how the color data is stored in a
`Gfx::Bitmap`, because correct blending depends on knowing the alpha
type: premultiplied blending uses `S + (1 - A) * D`, while
unpremultiplied blending uses `A * S + (1 - A) * D`.
This adds the alpha type information to `Gfx::Bitmap` across the board.
It isn't used anywhere yet.
2024-08-02 12:52:14 +02:00
|
|
|
auto bitmap = TRY(Bitmap::create_with_anonymous_buffer(format(), alpha_type(), move(buffer), size()));
|
2021-01-15 22:36:36 +01:00
|
|
|
memcpy(bitmap->scanline(0), scanline(0), size_in_bytes());
|
|
|
|
return bitmap;
|
|
|
|
}
|
|
|
|
|
2020-02-06 11:56:38 +01:00
|
|
|
Bitmap::~Bitmap()
|
2019-01-09 02:06:04 +01:00
|
|
|
{
|
2024-06-18 02:11:35 +03:00
|
|
|
if (m_destruction_callback)
|
|
|
|
m_destruction_callback();
|
2019-01-09 03:51:34 +01:00
|
|
|
m_data = nullptr;
|
2019-01-09 02:06:04 +01:00
|
|
|
}
|
|
|
|
|
2023-06-13 19:23:38 -04:00
|
|
|
void Bitmap::strip_alpha_channel()
|
|
|
|
{
|
|
|
|
VERIFY(m_format == BitmapFormat::BGRA8888 || m_format == BitmapFormat::BGRx8888);
|
|
|
|
for (ARGB32& pixel : *this)
|
|
|
|
pixel = 0xff000000 | (pixel & 0xffffff);
|
|
|
|
m_format = BitmapFormat::BGRx8888;
|
|
|
|
}
|
|
|
|
|
2021-11-06 13:15:43 +01:00
|
|
|
Gfx::ShareableBitmap Bitmap::to_shareable_bitmap() const
|
2020-03-29 19:04:05 +02:00
|
|
|
{
|
2021-11-06 13:15:43 +01:00
|
|
|
auto bitmap_or_error = to_bitmap_backed_by_anonymous_buffer();
|
|
|
|
if (bitmap_or_error.is_error())
|
2020-04-15 11:57:24 +02:00
|
|
|
return {};
|
2021-11-06 13:15:43 +01:00
|
|
|
return Gfx::ShareableBitmap { bitmap_or_error.release_value_but_fixme_should_propagate_errors(), Gfx::ShareableBitmap::ConstructWithKnownGoodBitmap };
|
2020-03-29 19:04:05 +02:00
|
|
|
}
|
|
|
|
|
2024-06-05 08:17:28 +02:00
|
|
|
ErrorOr<BackingStore> Bitmap::allocate_backing_store(BitmapFormat format, IntSize size)
|
2020-09-12 17:17:50 +01:00
|
|
|
{
|
2024-04-28 12:40:55 +02:00
|
|
|
if (size.is_empty())
|
|
|
|
return Error::from_string_literal("Gfx::Bitmap backing store size is empty");
|
|
|
|
|
2024-06-05 08:17:28 +02:00
|
|
|
if (size_would_overflow(format, size))
|
2022-07-11 17:57:32 +00:00
|
|
|
return Error::from_string_literal("Gfx::Bitmap backing store size overflow");
|
2020-09-12 17:17:50 +01:00
|
|
|
|
2024-06-05 08:17:28 +02:00
|
|
|
auto const pitch = minimum_pitch(size.width(), format);
|
|
|
|
auto const data_size_in_bytes = size_in_bytes(pitch, size.height());
|
2020-09-12 17:17:50 +01:00
|
|
|
|
2024-04-28 12:40:55 +02:00
|
|
|
void* data = kcalloc(1, data_size_in_bytes);
|
|
|
|
if (data == nullptr)
|
2021-11-06 10:34:14 +01:00
|
|
|
return Error::from_errno(errno);
|
2021-11-06 10:15:13 +01:00
|
|
|
return BackingStore { data, pitch, data_size_in_bytes };
|
2020-09-12 17:17:50 +01:00
|
|
|
}
|
|
|
|
|
2025-07-16 09:04:19 +02:00
|
|
|
Bitmap::DiffResult Bitmap::diff(Bitmap const& other) const
|
2022-04-15 01:07:15 +02:00
|
|
|
{
|
|
|
|
auto own_width = width();
|
|
|
|
auto own_height = height();
|
2025-07-16 09:04:19 +02:00
|
|
|
VERIFY(own_width == other.width() && own_height == other.height());
|
2022-04-15 01:07:15 +02:00
|
|
|
|
2025-07-16 09:04:19 +02:00
|
|
|
DiffResult result;
|
2022-04-15 01:07:15 +02:00
|
|
|
for (auto y = 0; y < own_height; ++y) {
|
|
|
|
for (auto x = 0; x < own_width; ++x) {
|
2025-07-16 09:04:19 +02:00
|
|
|
auto own_pixel = get_pixel(x, y);
|
|
|
|
auto other_pixel = other.get_pixel(x, y);
|
|
|
|
if (own_pixel == other_pixel)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
++result.pixel_error_count;
|
|
|
|
|
|
|
|
u8 red_error = abs(static_cast<int>(own_pixel.red()) - other_pixel.red());
|
|
|
|
u8 green_error = abs(static_cast<int>(own_pixel.green()) - other_pixel.green());
|
|
|
|
u8 blue_error = abs(static_cast<int>(own_pixel.blue()) - other_pixel.blue());
|
|
|
|
u8 alpha_error = abs(static_cast<int>(own_pixel.alpha()) - other_pixel.alpha());
|
|
|
|
|
|
|
|
result.total_red_error += red_error;
|
|
|
|
result.total_green_error += green_error;
|
|
|
|
result.total_blue_error += blue_error;
|
|
|
|
result.total_alpha_error += alpha_error;
|
|
|
|
|
|
|
|
result.maximum_red_error = max(result.maximum_red_error, red_error);
|
|
|
|
result.maximum_green_error = max(result.maximum_green_error, green_error);
|
|
|
|
result.maximum_blue_error = max(result.maximum_blue_error, blue_error);
|
|
|
|
result.maximum_alpha_error = max(result.maximum_alpha_error, alpha_error);
|
2022-04-15 01:07:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-07-16 09:04:19 +02:00
|
|
|
result.identical = result.pixel_error_count == 0;
|
|
|
|
result.total_error = result.total_red_error + result.total_green_error + result.total_blue_error + result.total_alpha_error;
|
|
|
|
|
|
|
|
u8 maximum_red_green_error = max(result.maximum_red_error, result.maximum_green_error);
|
|
|
|
u8 maximum_blue_alpha_error = max(result.maximum_blue_error, result.maximum_alpha_error);
|
|
|
|
result.maximum_error = max(maximum_red_green_error, maximum_blue_alpha_error);
|
|
|
|
|
|
|
|
return result;
|
2022-04-15 01:07:15 +02:00
|
|
|
}
|
|
|
|
|
2025-02-26 16:53:54 +01:00
|
|
|
void Bitmap::set_alpha_type_destructive(AlphaType alpha_type)
|
|
|
|
{
|
|
|
|
if (alpha_type == m_alpha_type)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_alpha_type == AlphaType::Unpremultiplied) {
|
|
|
|
for (auto y = 0; y < height(); ++y) {
|
|
|
|
for (auto x = 0; x < width(); ++x)
|
|
|
|
set_pixel(x, y, get_pixel(x, y).to_premultiplied());
|
|
|
|
}
|
|
|
|
} else if (m_alpha_type == AlphaType::Premultiplied) {
|
|
|
|
for (auto y = 0; y < height(); ++y) {
|
|
|
|
for (auto x = 0; x < width(); ++x)
|
|
|
|
set_pixel(x, y, get_pixel(x, y).to_unpremultiplied());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_alpha_type = alpha_type;
|
|
|
|
}
|
|
|
|
|
2020-02-06 11:56:38 +01:00
|
|
|
}
|