2020-01-18 05:38:21 -03:00
|
|
|
/*
|
2025-08-20 17:01:30 -03:00
|
|
|
* Copyright (c) 2018-2025, Andreas Kling <andreas@ladybird.org>
|
2022-09-30 14:26:13 -03:00
|
|
|
* Copyright (c) 2022, Timothy Slater <tslater2006@gmail.com>
|
2024-11-01 08:14:53 -03:00
|
|
|
* Copyright (c) 2024, Jelle Raaijmakers <jelle@ladybird.org>
|
2020-01-18 05:38:21 -03:00
|
|
|
*
|
2021-04-22 05:24:48 -03:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 05:38:21 -03:00
|
|
|
*/
|
|
|
|
|
|
2022-09-30 14:26:13 -03:00
|
|
|
#include <AK/Bitmap.h>
|
2020-04-15 11:55:07 -03:00
|
|
|
#include <AK/Checked.h>
|
2020-06-22 16:35:22 -03:00
|
|
|
#include <LibGfx/Bitmap.h>
|
2020-03-29 14:04:05 -03:00
|
|
|
#include <LibGfx/ShareableBitmap.h>
|
2025-10-11 02:38:09 -03:00
|
|
|
#include <LibGfx/SkiaUtils.h>
|
|
|
|
|
|
|
|
|
|
#include <core/SkBitmap.h>
|
|
|
|
|
#include <core/SkColorSpace.h>
|
|
|
|
|
#include <core/SkImage.h>
|
2025-11-05 06:56:25 -03:00
|
|
|
#include <core/SkImageInfo.h>
|
|
|
|
|
#include <core/SkPixmap.h>
|
2021-07-24 17:49:48 -03:00
|
|
|
#include <errno.h>
|
2019-02-07 20:13:47 -02:00
|
|
|
|
2025-08-20 17:01:30 -03:00
|
|
|
#ifdef AK_OS_MACOS
|
|
|
|
|
# include <Accelerate/Accelerate.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-02-06 07:56:38 -03:00
|
|
|
namespace Gfx {
|
|
|
|
|
|
2020-09-12 13:17:50 -03:00
|
|
|
struct BackingStore {
|
|
|
|
|
void* data { nullptr };
|
|
|
|
|
size_t pitch { 0 };
|
|
|
|
|
size_t size_in_bytes { 0 };
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-23 09:07:43 -03:00
|
|
|
StringView bitmap_format_name(BitmapFormat format)
|
|
|
|
|
{
|
|
|
|
|
switch (format) {
|
|
|
|
|
#define ENUMERATE_BITMAP_FORMAT(format) \
|
|
|
|
|
case BitmapFormat::format: \
|
|
|
|
|
return #format##sv;
|
|
|
|
|
ENUMERATE_BITMAP_FORMATS(ENUMERATE_BITMAP_FORMAT)
|
|
|
|
|
#undef ENUMERATE_BITMAP_FORMAT
|
|
|
|
|
}
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 03:17:28 -03:00
|
|
|
size_t Bitmap::minimum_pitch(size_t width, BitmapFormat format)
|
2020-09-06 18:59:20 -03:00
|
|
|
{
|
|
|
|
|
size_t element_size;
|
2025-11-23 09:07:37 -03:00
|
|
|
switch (format) {
|
|
|
|
|
case BitmapFormat::BGRx8888:
|
|
|
|
|
case BitmapFormat::BGRA8888:
|
|
|
|
|
case BitmapFormat::RGBx8888:
|
|
|
|
|
case BitmapFormat::RGBA8888:
|
2020-09-06 18:59:20 -03:00
|
|
|
element_size = 4;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2021-02-23 16:42:32 -03:00
|
|
|
VERIFY_NOT_REACHED();
|
2020-09-06 18:59:20 -03:00
|
|
|
}
|
|
|
|
|
|
2024-06-05 03:17:28 -03:00
|
|
|
return width * element_size;
|
2020-09-06 18:59:20 -03:00
|
|
|
}
|
|
|
|
|
|
2024-06-05 03:17:28 -03:00
|
|
|
static bool size_would_overflow(BitmapFormat format, IntSize size)
|
2019-02-11 06:47:10 -02:00
|
|
|
{
|
2020-04-15 06:57:24 -03:00
|
|
|
if (size.width() < 0 || size.height() < 0)
|
|
|
|
|
return true;
|
2026-01-11 12:58:12 -03:00
|
|
|
|
|
|
|
|
if (size.width() > UINT16_MAX || size.height() > UINT16_MAX)
|
2020-08-30 09:18:54 -03:00
|
|
|
return true;
|
2026-01-11 12:58:12 -03:00
|
|
|
|
2024-06-05 03:17:28 -03:00
|
|
|
size_t pitch = Bitmap::minimum_pitch(size.width(), format);
|
2026-01-11 12:58:12 -03:00
|
|
|
return Checked<int32_t>::multiplication_would_overflow(pitch, size.height());
|
2020-04-15 06:57:24 -03:00
|
|
|
}
|
|
|
|
|
|
2024-06-05 03:17:28 -03: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 07:52:14 -03: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 06:57:24 -03:00
|
|
|
{
|
2024-06-05 03:17:28 -03: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 07:52:14 -03:00
|
|
|
return AK::adopt_nonnull_ref_or_enomem(new (nothrow) Bitmap(format, alpha_type, size, backing_store));
|
2021-01-02 12:23: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 07:52:14 -03:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create_shareable(BitmapFormat format, AlphaType alpha_type, IntSize size)
|
2021-01-02 12:23:04 -03:00
|
|
|
{
|
2024-06-05 03:17:28 -03:00
|
|
|
if (size_would_overflow(format, size))
|
2023-01-20 16:06:05 -03:00
|
|
|
return Error::from_string_literal("Gfx::Bitmap::create_shareable size overflow");
|
2021-01-02 12:23:04 -03:00
|
|
|
|
2024-06-05 03:17:28 -03:00
|
|
|
auto const pitch = minimum_pitch(size.width(), format);
|
|
|
|
|
auto const data_size = size_in_bytes(pitch, size.height());
|
2021-01-16 19:14:24 -03:00
|
|
|
|
2021-11-06 07:44:05 -03: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 07:52:14 -03:00
|
|
|
auto bitmap = TRY(Bitmap::create_with_anonymous_buffer(format, alpha_type, buffer, size));
|
2021-11-06 07:44:05 -03:00
|
|
|
return bitmap;
|
2019-12-18 16:50:05 -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 07:52:14 -03:00
|
|
|
Bitmap::Bitmap(BitmapFormat format, AlphaType alpha_type, IntSize size, BackingStore const& backing_store)
|
2019-02-11 06:47:10 -02:00
|
|
|
: m_size(size)
|
2020-09-12 13:17:50 -03:00
|
|
|
, m_data(backing_store.data)
|
|
|
|
|
, m_pitch(backing_store.pitch)
|
2019-02-18 21:42:53 -03: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 07:52:14 -03:00
|
|
|
, m_alpha_type(alpha_type)
|
2019-02-11 06:47:10 -02:00
|
|
|
{
|
2021-02-23 16:42:32 -03:00
|
|
|
VERIFY(!m_size.is_empty());
|
2024-06-05 03:17:28 -03:00
|
|
|
VERIFY(!size_would_overflow(format, size));
|
2021-02-23 16:42:32 -03:00
|
|
|
VERIFY(m_data);
|
|
|
|
|
VERIFY(backing_store.size_in_bytes == size_in_bytes());
|
AK: Adopt mimalloc v2 as main allocator
Use mimalloc for Ladybird-owned allocations without overriding malloc().
Route kmalloc(), kcalloc(), krealloc(), and kfree() through mimalloc,
and put the embedded Rust crates on the same allocator via a shared
shim in AK/kmalloc.cpp.
This also lets us drop kfree_sized(), since it no longer used its size
argument. StringData, Utf16StringData, JS object storage, Rust error
strings, and the CoreAudio playback helpers can all free their AK-backed
storage with plain kfree().
Sanitizer builds still use the system allocator. LeakSanitizer does not
reliably trace references stored in mimalloc-managed AK containers, so
static caches and other long-lived roots can look leaked. Pass the old
size into the Rust realloc shim so aligned fallback reallocations can
move posix_memalign-backed blocks safely.
Static builds still need a little linker help. macOS app binaries need
the Rust allocator entry points forced in from liblagom-ak.a, while
static ELF links can pull in identical allocator shim definitions from
multiple Rust staticlibs. Keep the Apple -u flags and allow those
duplicate shim symbols for LibJS and LibRegex links on Linux and BSD.
2026-04-03 12:06:58 -03:00
|
|
|
m_destruction_callback = [data = m_data] {
|
|
|
|
|
kfree(data);
|
2024-06-17 20:11:35 -03:00
|
|
|
};
|
2019-02-16 09:22:00 -02:00
|
|
|
}
|
2019-01-14 17:00:42 -02: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 07:52:14 -03: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 17:00:42 -02:00
|
|
|
{
|
2024-06-05 03:17:28 -03:00
|
|
|
if (size_would_overflow(format, size))
|
2023-01-20 16:06:05 -03: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 07:52:14 -03:00
|
|
|
return adopt_ref(*new Bitmap(format, alpha_type, size, pitch, data, move(destruction_callback)));
|
2019-01-14 17:00:42 -02:00
|
|
|
}
|
2019-01-09 00:51:34 -02: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 07:52:14 -03:00
|
|
|
Bitmap::Bitmap(BitmapFormat format, AlphaType alpha_type, IntSize size, size_t pitch, void* data, Function<void()>&& destruction_callback)
|
2019-01-09 00:51:34 -02:00
|
|
|
: m_size(size)
|
2019-01-10 02:36:32 -02:00
|
|
|
, m_data(data)
|
2019-08-19 08:29:19 -03:00
|
|
|
, m_pitch(pitch)
|
2019-02-18 21:42:53 -03: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 07:52:14 -03:00
|
|
|
, m_alpha_type(alpha_type)
|
2024-06-17 20:11:35 -03:00
|
|
|
, m_destruction_callback(move(destruction_callback))
|
2019-01-09 00:51:34 -02:00
|
|
|
{
|
2024-06-05 03:17:28 -03:00
|
|
|
VERIFY(pitch >= minimum_pitch(size.width(), format));
|
|
|
|
|
VERIFY(!size_would_overflow(format, size));
|
2020-09-06 18:59:20 -03:00
|
|
|
// FIXME: assert that `data` is actually long enough!
|
2019-01-08 23:06:04 -02: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 07:52:14 -03:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create_with_anonymous_buffer(BitmapFormat format, AlphaType alpha_type, Core::AnonymousBuffer buffer, IntSize size)
|
2021-01-15 08:09:37 -03:00
|
|
|
{
|
2024-06-05 03:17:28 -03:00
|
|
|
if (size_would_overflow(format, size))
|
2023-01-20 16:06:05 -03:00
|
|
|
return Error::from_string_literal("Gfx::Bitmap::create_with_anonymous_buffer size overflow");
|
2021-01-15 08:09:37 -03:00
|
|
|
|
2026-06-19 01:52:11 -03:00
|
|
|
if (buffer.size() < size_in_bytes(minimum_pitch(size.width(), format), size.height()))
|
|
|
|
|
return Error::from_string_literal("Gfx::Bitmap::create_with_anonymous_buffer buffer too small for 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 07:52:14 -03:00
|
|
|
return adopt_nonnull_ref_or_enomem(new (nothrow) Bitmap(format, alpha_type, move(buffer), size));
|
2022-11-24 23:56:48 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-23 16:47:16 -03:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::create_with_raw_data(BitmapFormat format, AlphaType alpha_type, ReadonlyBytes raw_data, IntSize size)
|
|
|
|
|
{
|
|
|
|
|
if (size_would_overflow(format, size))
|
|
|
|
|
return Error::from_string_literal("Gfx::Bitmap::create_with_raw_data size overflow");
|
|
|
|
|
|
2026-06-19 01:52:11 -03:00
|
|
|
if (raw_data.size() < size_in_bytes(minimum_pitch(size.width(), format), size.height()))
|
|
|
|
|
return Error::from_string_literal("Gfx::Bitmap::create_with_raw_data data too small for size");
|
|
|
|
|
|
2025-10-23 16:47:16 -03:00
|
|
|
auto backing_store = TRY(Bitmap::allocate_backing_store(format, size, InitializeBackingStore::No));
|
|
|
|
|
raw_data.copy_to(Bytes { backing_store.data, backing_store.size_in_bytes });
|
|
|
|
|
return AK::adopt_nonnull_ref_or_enomem(new (nothrow) Bitmap(format, alpha_type, size, backing_store));
|
|
|
|
|
}
|
|
|
|
|
|
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 07:52:14 -03:00
|
|
|
Bitmap::Bitmap(BitmapFormat format, AlphaType alpha_type, Core::AnonymousBuffer buffer, IntSize size)
|
2021-01-15 08:09:37 -03:00
|
|
|
: m_size(size)
|
2021-05-24 07:24:38 -03:00
|
|
|
, m_data(buffer.data<void>())
|
2024-06-05 03:17:28 -03:00
|
|
|
, m_pitch(minimum_pitch(size.width(), format))
|
2021-01-15 08:09:37 -03: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 07:52:14 -03:00
|
|
|
, m_alpha_type(alpha_type)
|
2021-07-07 12:33:35 -03:00
|
|
|
, m_buffer(move(buffer))
|
2021-01-15 08:09:37 -03:00
|
|
|
{
|
2024-06-05 03:17:28 -03:00
|
|
|
VERIFY(!size_would_overflow(format, size));
|
2021-01-15 08:09:37 -03:00
|
|
|
}
|
|
|
|
|
|
2021-11-06 07:52:35 -03:00
|
|
|
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Bitmap::clone() const
|
2020-09-12 08:20:34 -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 07:52:14 -03:00
|
|
|
auto new_bitmap = TRY(Bitmap::create(format(), alpha_type(), size()));
|
2020-09-12 08:20:34 -03:00
|
|
|
|
2021-02-23 16:42:32 -03:00
|
|
|
VERIFY(size_in_bytes() == new_bitmap->size_in_bytes());
|
2020-09-12 08:20:34 -03:00
|
|
|
memcpy(new_bitmap->scanline(0), scanline(0), size_in_bytes());
|
|
|
|
|
|
2021-11-06 15:30:59 -03:00
|
|
|
return new_bitmap;
|
2020-09-12 08:20:34 -03:00
|
|
|
}
|
|
|
|
|
|
2025-08-04 08:33:30 -03:00
|
|
|
ErrorOr<NonnullRefPtr<Gfx::Bitmap>> Bitmap::cropped(Gfx::IntRect crop, Gfx::Color outside_color) const
|
2021-05-09 16:19:04 -03:00
|
|
|
{
|
2025-08-04 08:34:00 -03:00
|
|
|
// OPTIMIZATION: Skip slow manual copying for NO-OP crops
|
|
|
|
|
if (crop == rect())
|
|
|
|
|
return clone();
|
|
|
|
|
|
2025-08-04 08:31:37 -03:00
|
|
|
auto new_bitmap = TRY(Gfx::Bitmap::create(format(), alpha_type(), { crop.width(), crop.height() }));
|
2024-06-05 03:17:28 -03: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) {
|
2025-08-04 08:33:30 -03:00
|
|
|
new_bitmap->set_pixel(x, y, outside_color);
|
2021-05-09 16:19:04 -03:00
|
|
|
} else {
|
|
|
|
|
new_bitmap->set_pixel(x, y, get_pixel(global_x, global_y));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-11-06 15:30:59 -03:00
|
|
|
return new_bitmap;
|
2021-05-09 16:19:04 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-11 02:38:09 -03:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::scaled(int const width, int const height, ScalingMode const scaling_mode) const
|
|
|
|
|
{
|
|
|
|
|
auto const source_info = SkImageInfo::Make(this->width(), this->height(), to_skia_color_type(format()), to_skia_alpha_type(format(), alpha_type()), nullptr);
|
|
|
|
|
SkPixmap const source_sk_pixmap(source_info, begin(), pitch());
|
|
|
|
|
SkBitmap source_sk_bitmap;
|
|
|
|
|
source_sk_bitmap.installPixels(source_sk_pixmap);
|
|
|
|
|
source_sk_bitmap.setImmutable();
|
|
|
|
|
|
|
|
|
|
auto scaled_bitmap = TRY(Gfx::Bitmap::create(format(), alpha_type(), { width, height }));
|
|
|
|
|
auto const scaled_info = SkImageInfo::Make(scaled_bitmap->width(), scaled_bitmap->height(), to_skia_color_type(scaled_bitmap->format()), to_skia_alpha_type(scaled_bitmap->format(), scaled_bitmap->alpha_type()), nullptr);
|
|
|
|
|
SkPixmap const scaled_sk_pixmap(scaled_info, scaled_bitmap->begin(), scaled_bitmap->pitch());
|
|
|
|
|
|
|
|
|
|
sk_sp<SkImage> source_sk_image = source_sk_bitmap.asImage();
|
|
|
|
|
if (!source_sk_image->scalePixels(scaled_sk_pixmap, to_skia_sampling_options(scaling_mode)))
|
|
|
|
|
return Error::from_string_literal("Unable to scale pixels for bitmap");
|
|
|
|
|
return scaled_bitmap;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-06 09:15:43 -03:00
|
|
|
ErrorOr<NonnullRefPtr<Bitmap>> Bitmap::to_bitmap_backed_by_anonymous_buffer() const
|
2021-01-15 18:36:36 -03:00
|
|
|
{
|
2023-02-19 19:02:17 -03:00
|
|
|
if (m_buffer.is_valid()) {
|
|
|
|
|
// FIXME: The const_cast here is awkward.
|
|
|
|
|
return NonnullRefPtr { const_cast<Bitmap&>(*this) };
|
|
|
|
|
}
|
2021-11-06 09:15:43 -03: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 07:52:14 -03:00
|
|
|
auto bitmap = TRY(Bitmap::create_with_anonymous_buffer(format(), alpha_type(), move(buffer), size()));
|
2021-01-15 18:36:36 -03:00
|
|
|
memcpy(bitmap->scanline(0), scanline(0), size_in_bytes());
|
|
|
|
|
return bitmap;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-06 07:56:38 -03:00
|
|
|
Bitmap::~Bitmap()
|
2019-01-08 23:06:04 -02:00
|
|
|
{
|
2024-06-17 20:11:35 -03:00
|
|
|
if (m_destruction_callback)
|
|
|
|
|
m_destruction_callback();
|
2019-01-09 00:51:34 -02:00
|
|
|
m_data = nullptr;
|
2019-01-08 23:06:04 -02:00
|
|
|
}
|
|
|
|
|
|
2023-06-13 20:23:38 -03:00
|
|
|
void Bitmap::strip_alpha_channel()
|
|
|
|
|
{
|
|
|
|
|
VERIFY(m_format == BitmapFormat::BGRA8888 || m_format == BitmapFormat::BGRx8888);
|
2025-11-23 09:07:38 -03:00
|
|
|
for (BGRA8888& pixel : *this)
|
2023-06-13 20:23:38 -03:00
|
|
|
pixel = 0xff000000 | (pixel & 0xffffff);
|
|
|
|
|
m_format = BitmapFormat::BGRx8888;
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-06 09:15:43 -03:00
|
|
|
Gfx::ShareableBitmap Bitmap::to_shareable_bitmap() const
|
2020-03-29 14:04:05 -03:00
|
|
|
{
|
2021-11-06 09:15:43 -03:00
|
|
|
auto bitmap_or_error = to_bitmap_backed_by_anonymous_buffer();
|
|
|
|
|
if (bitmap_or_error.is_error())
|
2020-04-15 06:57:24 -03:00
|
|
|
return {};
|
2021-11-06 09:15:43 -03:00
|
|
|
return Gfx::ShareableBitmap { bitmap_or_error.release_value_but_fixme_should_propagate_errors(), Gfx::ShareableBitmap::ConstructWithKnownGoodBitmap };
|
2020-03-29 14:04:05 -03:00
|
|
|
}
|
|
|
|
|
|
2025-10-23 16:47:16 -03:00
|
|
|
ErrorOr<BackingStore> Bitmap::allocate_backing_store(BitmapFormat format, IntSize size, InitializeBackingStore initialize_backing_store)
|
2020-09-12 13:17:50 -03:00
|
|
|
{
|
2024-04-28 07:40:55 -03:00
|
|
|
if (size.is_empty())
|
|
|
|
|
return Error::from_string_literal("Gfx::Bitmap backing store size is empty");
|
|
|
|
|
|
2024-06-05 03:17:28 -03:00
|
|
|
if (size_would_overflow(format, size))
|
2022-07-11 14:57:32 -03:00
|
|
|
return Error::from_string_literal("Gfx::Bitmap backing store size overflow");
|
2020-09-12 13:17:50 -03:00
|
|
|
|
2024-06-05 03:17:28 -03:00
|
|
|
auto const pitch = minimum_pitch(size.width(), format);
|
|
|
|
|
auto const data_size_in_bytes = size_in_bytes(pitch, size.height());
|
2020-09-12 13:17:50 -03:00
|
|
|
|
2025-10-23 16:47:16 -03:00
|
|
|
void* data;
|
|
|
|
|
if (initialize_backing_store == InitializeBackingStore::Yes)
|
|
|
|
|
data = kcalloc(1, data_size_in_bytes);
|
|
|
|
|
else
|
|
|
|
|
data = kmalloc(data_size_in_bytes);
|
2024-04-28 07:40:55 -03:00
|
|
|
if (data == nullptr)
|
2021-11-06 06:34:14 -03:00
|
|
|
return Error::from_errno(errno);
|
2021-11-06 06:15:13 -03:00
|
|
|
return BackingStore { data, pitch, data_size_in_bytes };
|
2020-09-12 13:17:50 -03:00
|
|
|
}
|
|
|
|
|
|
2025-07-16 04:04:19 -03:00
|
|
|
Bitmap::DiffResult Bitmap::diff(Bitmap const& other) const
|
2022-04-14 20:07:15 -03:00
|
|
|
{
|
|
|
|
|
auto own_width = width();
|
|
|
|
|
auto own_height = height();
|
2025-07-16 04:04:19 -03:00
|
|
|
VERIFY(own_width == other.width() && own_height == other.height());
|
2022-04-14 20:07:15 -03:00
|
|
|
|
2025-07-16 04:04:19 -03:00
|
|
|
DiffResult result;
|
2022-04-14 20:07:15 -03:00
|
|
|
for (auto y = 0; y < own_height; ++y) {
|
|
|
|
|
for (auto x = 0; x < own_width; ++x) {
|
2025-07-16 04:04:19 -03: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-14 20:07:15 -03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-16 04:04:19 -03: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-14 20:07:15 -03:00
|
|
|
}
|
|
|
|
|
|
2025-02-26 12:53:54 -03:00
|
|
|
void Bitmap::set_alpha_type_destructive(AlphaType alpha_type)
|
|
|
|
|
{
|
|
|
|
|
if (alpha_type == m_alpha_type)
|
|
|
|
|
return;
|
|
|
|
|
|
2025-11-05 09:08:59 -03:00
|
|
|
if (m_format == BitmapFormat::BGRx8888 || m_format == BitmapFormat::RGBx8888) {
|
|
|
|
|
m_alpha_type = alpha_type;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-20 17:01:30 -03:00
|
|
|
#ifdef AK_OS_MACOS
|
|
|
|
|
vImage_Buffer buf { .data = m_data, .height = vImagePixelCount(height()), .width = vImagePixelCount(width()), .rowBytes = pitch() };
|
|
|
|
|
vImage_Error err;
|
|
|
|
|
if (m_alpha_type == AlphaType::Unpremultiplied) {
|
|
|
|
|
switch (m_format) {
|
|
|
|
|
case BitmapFormat::BGRA8888:
|
|
|
|
|
err = vImagePremultiplyData_BGRA8888(&buf, &buf, kvImageNoFlags);
|
|
|
|
|
break;
|
|
|
|
|
case BitmapFormat::RGBA8888:
|
|
|
|
|
err = vImagePremultiplyData_RGBA8888(&buf, &buf, kvImageNoFlags);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
switch (m_format) {
|
|
|
|
|
case BitmapFormat::BGRA8888:
|
|
|
|
|
err = vImageUnpremultiplyData_BGRA8888(&buf, &buf, kvImageNoFlags);
|
|
|
|
|
break;
|
|
|
|
|
case BitmapFormat::RGBA8888:
|
|
|
|
|
err = vImageUnpremultiplyData_RGBA8888(&buf, &buf, kvImageNoFlags);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
VERIFY(err == kvImageNoError);
|
|
|
|
|
#else
|
2025-11-05 06:56:25 -03:00
|
|
|
auto color_type = to_skia_color_type(m_format);
|
|
|
|
|
auto source_alpha = to_skia_alpha_type(m_format, m_alpha_type);
|
|
|
|
|
auto destination_alpha = to_skia_alpha_type(m_format, alpha_type);
|
|
|
|
|
|
|
|
|
|
auto color_space = SkColorSpace::MakeSRGB();
|
|
|
|
|
|
|
|
|
|
auto source_info = SkImageInfo::Make(width(), height(), color_type, source_alpha, color_space);
|
|
|
|
|
auto destination_info = SkImageInfo::Make(width(), height(), color_type, destination_alpha, color_space);
|
|
|
|
|
|
|
|
|
|
SkPixmap src_pixmap(source_info, m_data, pitch());
|
|
|
|
|
SkPixmap dst_pixmap(destination_info, m_data, pitch());
|
|
|
|
|
|
|
|
|
|
bool ok = src_pixmap.readPixels(dst_pixmap);
|
|
|
|
|
VERIFY(ok);
|
2025-08-20 17:01:30 -03:00
|
|
|
#endif
|
2025-02-26 12:53:54 -03:00
|
|
|
m_alpha_type = alpha_type;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-06 07:56:38 -03:00
|
|
|
}
|