Files
serenity/Userland/Libraries/LibGfx/ImageFormats/JPEG2000ProgressionIterators.cpp
T
Dan Klishch d3a6d82574 AK+LibGfx/JPEG2000: Make SyncGenerator request next value eagerly
It seems that `bool has_next() / Y next()` interface is somewhat more
natural compared to `bool is_done() / Optional<Y> next()`.
2025-04-06 13:43:20 -04:00

335 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2025, Nico Weber <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibGfx/ImageFormats/JPEG2000ProgressionIterators.h>
namespace Gfx::JPEG2000 {
LayerResolutionLevelComponentPositionProgressionIterator::LayerResolutionLevelComponentPositionProgressionIterator(int layer_count, int max_number_of_decomposition_levels, int component_count, Function<int(int resolution_level, int component)> precinct_count)
: m_layer_count(layer_count)
, m_max_number_of_decomposition_levels(max_number_of_decomposition_levels)
, m_component_count(component_count)
, m_precinct_count(move(precinct_count))
, m_generator(generator())
{
}
bool LayerResolutionLevelComponentPositionProgressionIterator::has_next() const
{
return m_generator.has_next();
}
ProgressionData LayerResolutionLevelComponentPositionProgressionIterator::next()
{
return m_generator.next();
}
SyncGenerator<ProgressionData> LayerResolutionLevelComponentPositionProgressionIterator::generator()
{
// B.12.1.1 Layer-resolution level-component-position progression
// "for each l = 0,..., L – 1
// for each r = 0,..., Nmax
// for each i = 0,..., Csiz – 1
// for each k = 0,..., numprecincts – 1
// packet for component i, resolution level r, layer l, and precinct k.
// Here, L is the number of layers and Nmax is the maximum number of decomposition levels, N_L, used in any component of the tile."
// FIXME: This always iterates up to Nmax, instead of just N_l of each component. That means several of the iteration results will be invalid and skipped.
// (This is a performance issue, not a correctness issue.)
for (int l = 0; l < m_layer_count; ++l)
for (int r = 0; r <= m_max_number_of_decomposition_levels; ++r)
for (int i = 0; i < m_component_count; ++i)
for (int k = 0; k < m_precinct_count(r, i); ++k)
co_yield ProgressionData { l, r, i, k };
}
ResolutionLevelLayerComponentPositionProgressionIterator::ResolutionLevelLayerComponentPositionProgressionIterator(int layer_count, int max_number_of_decomposition_levels, int component_count, Function<int(int resolution_level, int component)> precinct_count)
: m_layer_count(layer_count)
, m_max_number_of_decomposition_levels(max_number_of_decomposition_levels)
, m_component_count(component_count)
, m_precinct_count(move(precinct_count))
, m_generator(generator())
{
}
bool ResolutionLevelLayerComponentPositionProgressionIterator::has_next() const
{
return m_generator.has_next();
}
ProgressionData ResolutionLevelLayerComponentPositionProgressionIterator::next()
{
return m_generator.next();
}
SyncGenerator<ProgressionData> ResolutionLevelLayerComponentPositionProgressionIterator::generator()
{
// B.12.1.2 Resolution level-layer-component-position progression
// "for each r = 0,..., Nmax
// for each l = 0,..., L – 1
// for each i = 0,..., Csiz – 1
// for each k = 0,..., numprecincts – 1
// packet for component i, resolution level r, layer l, and precinct k."
// FIXME: This always iterates up to Nmax, instead of just N_l of each component. That means several of the iteration results will be invalid and skipped.
// (This is a performance issue, not a correctness issue.)
for (int r = 0; r <= m_max_number_of_decomposition_levels; ++r)
for (int l = 0; l < m_layer_count; ++l)
for (int i = 0; i < m_component_count; ++i)
for (int k = 0; k < m_precinct_count(r, i); ++k)
co_yield ProgressionData { l, r, i, k };
}
ResolutionLevelPositionComponentLayerProgressionIterator::ResolutionLevelPositionComponentLayerProgressionIterator(
int layer_count, int max_number_of_decomposition_levels, int component_count, Function<int(int resolution_level, int component)> precinct_count,
Function<int(int component)> XRsiz, Function<int(int component)> YRsiz,
Function<int(int resolution_level, int component)> PPx, Function<int(int resolution_level, int component)> PPy,
Function<int(int component)> N_L,
Function<int(int resolution_level, int component)> num_precincts_wide,
Gfx::IntRect tile_rect,
Function<IntRect(int resolution_level, int component)> ll_rect)
: m_layer_count(layer_count)
, m_max_number_of_decomposition_levels(max_number_of_decomposition_levels)
, m_component_count(component_count)
, m_precinct_count(move(precinct_count))
, m_XRsiz(move(XRsiz))
, m_YRsiz(move(YRsiz))
, m_PPx(move(PPx))
, m_PPy(move(PPy))
, m_N_L(move(N_L))
, m_num_precincts_wide(move(num_precincts_wide))
, m_tile_rect(tile_rect)
, m_ll_rect(move(ll_rect))
, m_generator(generator())
{
}
bool ResolutionLevelPositionComponentLayerProgressionIterator::has_next() const
{
return m_generator.has_next();
}
ProgressionData ResolutionLevelPositionComponentLayerProgressionIterator::next()
{
return m_generator.next();
}
SyncGenerator<ProgressionData> ResolutionLevelPositionComponentLayerProgressionIterator::generator()
{
auto compute_precinct = [&](int x, int y, int r, int i) {
// (B-20)
auto const trx0 = m_ll_rect(r, i).left();
auto const try0 = m_ll_rect(r, i).top();
auto const x_offset = floor_div(ceil_div(x, m_XRsiz(i) * (1 << (m_N_L(i) - r))), 1 << m_PPx(r, i)) - floor_div(trx0, 1 << m_PPx(r, i));
auto const y_offset = floor_div(ceil_div(y, m_YRsiz(i) * (1 << (m_N_L(i) - r))), 1 << m_PPy(r, i)) - floor_div(try0, 1 << m_PPy(r, i));
return x_offset + m_num_precincts_wide(r, i) * y_offset;
};
// B.12.1.3 Resolution level-position-component-layer progression
// "for each r = 0,..., Nmax
// for each y = ty0,..., ty1 – 1,
// for each x = tx0,..., tx1 – 1,
// for each i = 0,..., Csiz – 1
// if ((y divisible by YRsiz(i) * 2 ** (PPy(r, i) + N_L(i) - r) OR
// ((y == ty0) AND (try0 * 2 ** (N_L(i) - r) NOT divisible by 2 ** (PPy(r, i) + N_L(i) - r))))
// if ((x divisible by XRsiz(i) * 2 ** (PPx(r, i) + N_L(i) - r) OR
// ((x == tx0) AND (trx0 * 2 ** (N_L(i) - r) NOT divisible by 2 ** (PPx(r, i) + N_L(i) - r))))
// for the next precinct, k, if one exists,
// for each l = 0,..., L – 1
// packet for component i, resolution level r, layer l, and precinct k."
// The motivation for this loop is to walk corresponding precincts in different components at the same time,
// even if the components have different precinct counts.
for (int r = 0; r <= m_max_number_of_decomposition_levels; ++r) {
auto const tx0 = m_tile_rect.left();
auto const ty0 = m_tile_rect.top();
for (int y = ty0; y < m_tile_rect.bottom(); ++y) {
for (int x = tx0; x < m_tile_rect.right(); ++x) {
for (int i = 0; i < m_component_count; ++i) {
auto const trx0 = m_ll_rect(r, i).left();
auto const try0 = m_ll_rect(r, i).top();
if ((y % (m_YRsiz(i) * (1 << (m_PPy(r, i) + m_N_L(i) - r))) == 0)
|| ((y == ty0) && (try0 * (1 << (m_N_L(i) - r)) % (1 << (m_PPy(r, i) + m_N_L(i) - r)) != 0))) {
if ((x % (m_XRsiz(i) * (1 << (m_PPx(r, i) + m_N_L(i) - r))) == 0)
|| ((x == tx0) && (trx0 * (1 << (m_N_L(i) - r)) % (1 << (m_PPx(r, i) + m_N_L(i) - r)) != 0))) {
if (int k = compute_precinct(x, y, r, i); k < m_precinct_count(r, i)) {
for (int l = 0; l < m_layer_count; ++l) {
co_yield ProgressionData { l, r, i, k };
}
}
}
}
}
}
}
}
}
PositionComponentResolutionLevelLayerProgressionIterator::PositionComponentResolutionLevelLayerProgressionIterator(
int layer_count, int component_count, Function<int(int resolution_level, int component)> precinct_count,
Function<int(int component)> XRsiz, Function<int(int component)> YRsiz,
Function<int(int resolution_level, int component)> PPx, Function<int(int resolution_level, int component)> PPy,
Function<int(int component)> N_L,
Function<int(int resolution_level, int component)> num_precincts_wide,
Gfx::IntRect tile_rect,
Function<IntRect(int resolution_level, int component)> ll_rect)
: m_layer_count(layer_count)
, m_component_count(component_count)
, m_precinct_count(move(precinct_count))
, m_XRsiz(move(XRsiz))
, m_YRsiz(move(YRsiz))
, m_PPx(move(PPx))
, m_PPy(move(PPy))
, m_N_L(move(N_L))
, m_num_precincts_wide(move(num_precincts_wide))
, m_tile_rect(tile_rect)
, m_ll_rect(move(ll_rect))
, m_generator(generator())
{
}
bool PositionComponentResolutionLevelLayerProgressionIterator::has_next() const
{
return m_generator.has_next();
}
ProgressionData PositionComponentResolutionLevelLayerProgressionIterator::next()
{
return m_generator.next();
}
SyncGenerator<ProgressionData> PositionComponentResolutionLevelLayerProgressionIterator::generator()
{
auto compute_precinct = [&](int x, int y, int r, int i) {
// (B-20)
auto const trx0 = m_ll_rect(r, i).left();
auto const try0 = m_ll_rect(r, i).top();
auto const x_offset = floor_div(ceil_div(x, m_XRsiz(i) * (1 << (m_N_L(i) - r))), 1 << m_PPx(r, i)) - floor_div(trx0, 1 << m_PPx(r, i));
auto const y_offset = floor_div(ceil_div(y, m_YRsiz(i) * (1 << (m_N_L(i) - r))), 1 << m_PPy(r, i)) - floor_div(try0, 1 << m_PPy(r, i));
return x_offset + m_num_precincts_wide(r, i) * y_offset;
};
// B.12.1.4 Position-component-resolution level-layer progression
// "for each y = ty0,..., ty1 – 1,
// for each x = tx0,..., tx1 – 1,
// for each i = 0,..., Csiz – 1
// for each r = 0,..., NL where NL is the number of decomposition levels for component i,
// if ((y divisible by YRsiz(i) * 2 ** (PPy(r, i) + N_L(i) - r) OR
// ((y == ty0) AND (try0 * 2 ** (N_L(i) - r) NOT divisible by 2 ** (PPy(r, i) + N_L(i) - r))))
// if ((x divisible by XRsiz(i) * 2 ** (PPx(r, i) + N_L(i) - r) OR
// ((x == tx0) AND (trx0 * 2 ** (N_L(i) - r) NOT divisible by 2 ** (PPx(r, i) + N_L(i) - r))))
// for the next precinct, k, if one exists, in the sequence shown in Figure B.8
// for each l = 0,..., L – 1
// packet for component i, resolution level r, layer l, and precinct k."
// The motivation for this loop is to walk corresponding precincts in different components and resolution levels at the same time,
// even if the components or resolution levels have different precinct counts.
auto const tx0 = m_tile_rect.left();
auto const ty0 = m_tile_rect.top();
for (int y = ty0; y < m_tile_rect.bottom(); ++y) {
for (int x = tx0; x < m_tile_rect.right(); ++x) {
for (int i = 0; i < m_component_count; ++i) {
for (int r = 0; r <= m_N_L(i); ++r) {
auto const trx0 = m_ll_rect(r, i).left();
auto const try0 = m_ll_rect(r, i).top();
if ((y % (m_YRsiz(i) * (1 << (m_PPy(r, i) + m_N_L(i) - r))) == 0)
|| ((y == ty0) && (try0 * (1 << (m_N_L(i) - r)) % (1 << (m_PPy(r, i) + m_N_L(i) - r)) != 0))) {
if ((x % (m_XRsiz(i) * (1 << (m_PPx(r, i) + m_N_L(i) - r))) == 0)
|| ((x == tx0) && (trx0 * (1 << (m_N_L(i) - r)) % (1 << (m_PPx(r, i) + m_N_L(i) - r)) != 0))) {
if (int k = compute_precinct(x, y, r, i); k < m_precinct_count(r, i)) {
for (int l = 0; l < m_layer_count; ++l) {
co_yield ProgressionData { l, r, i, k };
}
}
}
}
}
}
}
}
}
ComponentPositionResolutionLevelLayerProgressionIterator::ComponentPositionResolutionLevelLayerProgressionIterator(
int layer_count, int component_count, Function<int(int resolution_level, int component)> precinct_count,
Function<int(int component)> XRsiz, Function<int(int component)> YRsiz,
Function<int(int resolution_level, int component)> PPx, Function<int(int resolution_level, int component)> PPy,
Function<int(int component)> N_L,
Function<int(int resolution_level, int component)> num_precincts_wide,
Gfx::IntRect tile_rect,
Function<IntRect(int resolution_level, int component)> ll_rect)
: m_layer_count(layer_count)
, m_component_count(component_count)
, m_precinct_count(move(precinct_count))
, m_XRsiz(move(XRsiz))
, m_YRsiz(move(YRsiz))
, m_PPx(move(PPx))
, m_PPy(move(PPy))
, m_N_L(move(N_L))
, m_num_precincts_wide(move(num_precincts_wide))
, m_tile_rect(tile_rect)
, m_ll_rect(move(ll_rect))
, m_generator(generator())
{
}
bool ComponentPositionResolutionLevelLayerProgressionIterator::has_next() const
{
return m_generator.has_next();
}
ProgressionData ComponentPositionResolutionLevelLayerProgressionIterator::next()
{
return m_generator.next();
}
SyncGenerator<ProgressionData> ComponentPositionResolutionLevelLayerProgressionIterator::generator()
{
auto compute_precinct = [&](int x, int y, int r, int i) {
// (B-20)
auto const trx0 = m_ll_rect(r, i).left();
auto const try0 = m_ll_rect(r, i).top();
auto const x_offset = floor_div(ceil_div(x, m_XRsiz(i) * (1 << (m_N_L(i) - r))), 1 << m_PPx(r, i)) - floor_div(trx0, 1 << m_PPx(r, i));
auto const y_offset = floor_div(ceil_div(y, m_YRsiz(i) * (1 << (m_N_L(i) - r))), 1 << m_PPy(r, i)) - floor_div(try0, 1 << m_PPy(r, i));
return x_offset + m_num_precincts_wide(r, i) * y_offset;
};
// B.12.1.5 Component-position-resolution level-layer progression
// "for each i = 0,..., Csiz – 1
// for each y = ty0,..., ty1 – 1,
// for each x = tx0,..., tx1 – 1,
// for each r = 0,..., NL where NL is the number of decomposition levels for component i,
// if ((y divisible by YRsiz(i) * 2 ** (PPy(r, i) + N_L(i) - r) OR
// ((y == ty0) AND (try0 * 2 ** (N_L(i) - r) NOT divisible by 2 ** (PPy(r, i) + N_L(i) - r))))
// if ((x divisible by XRsiz(i) * 2 ** (PPx(r, i) + N_L(i) - r) OR
// ((x == tx0) AND (trx0 * 2 ** (N_L(i) - r) NOT divisible by 2 ** (PPx(r, i) + N_L(i) - r))))
// for the next precinct, k, if one exists, in the sequence shown in Figure B.8
// for each l = 0,..., L – 1
// packet for component i, resolution level r, layer l, and precinct k."
// The motivation for this loop is to walk corresponding precincts in different resolution levels at the same time,
// even if the resolution levels have different precinct counts.
auto const tx0 = m_tile_rect.left();
auto const ty0 = m_tile_rect.top();
for (int i = 0; i < m_component_count; ++i) {
for (int y = ty0; y < m_tile_rect.bottom(); ++y) {
for (int x = tx0; x < m_tile_rect.right(); ++x) {
for (int r = 0; r <= m_N_L(i); ++r) {
auto const trx0 = m_ll_rect(r, i).left();
auto const try0 = m_ll_rect(r, i).top();
if ((y % (m_YRsiz(i) * (1 << (m_PPy(r, i) + m_N_L(i) - r))) == 0)
|| ((y == ty0) && (try0 * (1 << (m_N_L(i) - r)) % (1 << (m_PPy(r, i) + m_N_L(i) - r)) != 0))) {
if ((x % (m_XRsiz(i) * (1 << (m_PPx(r, i) + m_N_L(i) - r))) == 0)
|| ((x == tx0) && (trx0 * (1 << (m_N_L(i) - r)) % (1 << (m_PPx(r, i) + m_N_L(i) - r)) != 0))) {
if (int k = compute_precinct(x, y, r, i); k < m_precinct_count(r, i)) {
for (int l = 0; l < m_layer_count; ++l) {
co_yield ProgressionData { l, r, i, k };
}
}
}
}
}
}
}
}
}
}