Skip to content

Commit

Permalink
stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Gagis committed Sep 21, 2023
1 parent 1675a2f commit 3474055
Showing 1 changed file with 300 additions and 0 deletions.
300 changes: 300 additions & 0 deletions src/rasterimage/image.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,289 @@ class dimensioned
}
};

template <typename channel_type, size_t number_of_channels>
class image;

template <typename channel_type, size_t number_of_channels>
class image_span : public dimensioned
{
public:
static const size_t num_channels = number_of_channels;

using pixel_type = r4::vector<channel_type, num_channels>;
using value_type = typename pixel_type::value_type;

static_assert(sizeof(pixel_type) == sizeof(channel_type) * number_of_channels, "pixel_type has padding");

static_assert(
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
sizeof(std::array<pixel_type, 2>) == sizeof(pixel_type) * 2,
"pixel_type array has gaps"
);

private:
size_t stride;

utki::span<pixel_type> span;

template <bool is_const>
class iterator_internal
{
friend class image_span;

public:
using const_value_type = utki::span<const pixel_type>;

private:
using non_const_value_type = utki::span<pixel_type>;

std::conditional_t<is_const, const_value_type, non_const_value_type> line;

size_t stride;

iterator_internal(decltype(line) line, size_t stride) :
line(std::move(line)),
stride(stride)
{}

public:
// The iterator cannot have stronger tag than std::input_iterator_tag
// because it's reference type is value_type. Otherwise, the iterator is
// actually a random access iterator.
using iterator_category = std::input_iterator_tag;

using difference_type = std::ptrdiff_t;
using value_type = decltype(line);
using reference = value_type;
using pointer = void;

iterator_internal() = default;

bool operator!=(const iterator_internal& i) const noexcept
{
return this->line.data() != i.line.data();
}

bool operator==(const iterator_internal& i) const noexcept
{
return this->line.data() == i.line.data();
}

value_type operator*() noexcept
{
return this->line;
}

const_value_type operator*() const noexcept
{
return this->line;
}

const value_type* operator->() noexcept
{
return &this->line;
}

const const_value_type* operator->() const noexcept
{
return &this->line;
}

iterator_internal& operator++() noexcept
{
this->line = utki::make_span(this->line.data() + this->stride, this->line.size());
return *this;
}

iterator_internal& operator--() noexcept
{
this->line = utki::make_span(this->line.data() - this->stride, this->line.size());
return *this;
}

// postfix increment
iterator_internal operator++(int) noexcept
{
iterator_internal ret(*this);
this->operator++();
return ret;
}

// postfix decrement
iterator_internal operator--(int) noexcept
{
iterator_internal ret(*this);
this->operator--();
return ret;
}

iterator_internal& operator+=(difference_type d) noexcept
{
this->line = utki::make_span(this->line.data() + d * this->stride, this->line.size());

return *this;
}

iterator_internal& operator-=(difference_type d) noexcept
{
return this->operator+=(-d);
}

iterator_internal operator+(difference_type d) const noexcept
{
iterator_internal ret = *this;
ret += d;
return ret;
}

friend iterator_internal operator+(difference_type d, const iterator_internal& i) noexcept
{
return i + d;
}

iterator_internal operator-(difference_type d) const noexcept
{
iterator_internal ret = *this;
ret -= d;
return ret;
}

difference_type operator-(const iterator_internal& i) const noexcept
{
ASSERT(!this->line.empty())
if (this->line.data() >= i.line.data()) {
return (this->line.data() - i.line.data()) / this->stride;
} else {
return -((i.line.data() - this->line.data()) / this->stride);
}
}

value_type operator[](difference_type d) noexcept
{
return *(*this + d);
}

const_value_type operator[](difference_type d) const noexcept
{
return *(*this + d);
}

bool operator<(const iterator_internal& i) const noexcept
{
return this->line.data() < i.line.data();
}

bool operator>(const iterator_internal& i) const noexcept
{
return this->line.data() > i.line.data();
}

bool operator>=(const iterator_internal& i) const noexcept
{
return this->line.data() >= i.line.data();
}

bool operator<=(const iterator_internal& i) const noexcept
{
return this->line.data() <= i.line.data();
}
};

public:
using iterator = iterator_internal<false>;
using const_iterator = iterator_internal<true>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;

image_span(image<channel_type, number_of_channels>& img);

bool empty() const noexcept
{
return this->span.empty();
}

iterator end() noexcept
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return iterator(
utki::make_span(this->span.data() + this->stride * this->dimensions.y(), this->dimensions.x()),
this->stride
);
}

const_iterator cbegin() const noexcept
{
return const_iterator(utki::make_span(this->span.data(), this->dimensions.x()), this->stride);
}

const_iterator cend() const noexcept
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return const_iterator(
utki::make_span(this->span.data() + this->stride * this->dimensions.y(), this->dimensions.x()),
this->stride
);
}

const_reverse_iterator crbegin() const
{
return const_reverse_iterator(this->cend());
}

const_reverse_iterator crend() const
{
return const_reverse_iterator(this->cbegin());
}

reverse_iterator rbegin()
{
return reverse_iterator(this->end());
}

reverse_iterator rend()
{
return reverse_iterator(this->begin());
}

utki::span<pixel_type> operator[](uint32_t line_index) noexcept
{
return *utki::next(this->begin(), line_index);
}

utki::span<const pixel_type> operator[](uint32_t line_index) const noexcept
{
return *utki::next(this->begin(), line_index);
}

void clear(pixel_type val)
{
for (auto l : *this) {
for (auto& p : l) {
p = val;
}
}
}

void swap_red_blue() noexcept
{
using std::swap;
for (auto l : *this) {
for (auto& p : l) {
swap(p.r(), p.b());
}
}
}

void unpremultiply_alpha() noexcept
{
for (auto l : *this) {
for (auto& p : l) {
p = rasterimage::unpremultiply_alpha(p);
}
}
}
};

template <typename channel_type, size_t number_of_channels>
class image : public dimensioned
{
Expand Down Expand Up @@ -268,6 +551,16 @@ class image : public dimensioned
return iterator(utki::make_span(this->buffer.data(), this->dimensions.x()));
}

image_span<channel_type, number_of_channels> span() noexcept
{
return *this;
}

image_span<const channel_type, number_of_channels> span() const noexcept
{
return *this;
}

bool empty() const noexcept
{
return this->buffer.empty();
Expand Down Expand Up @@ -387,4 +680,11 @@ class image : public dimensioned
}
};

template <typename channel_type, size_t number_of_channels>
image_span<channel_type, number_of_channels>::image_span(image<channel_type, number_of_channels>& im) :
dimensioned(im.dims()),
stride(im.dims().x()),
span(im[0])
{}

} // namespace rasterimage

0 comments on commit 3474055

Please sign in to comment.