mirror of https://github.com/aseprite/aseprite.git
Add new kind of Image iterators line by line: Image::read/writeArea()
This commit is contained in:
parent
70c8924719
commit
8d4c4857ee
|
@ -45,6 +45,7 @@ add_library(doc-lib
|
|||
image.cpp
|
||||
image_impl.cpp
|
||||
image_io.cpp
|
||||
image_iterators2.cpp
|
||||
layer.cpp
|
||||
layer_io.cpp
|
||||
layer_list.cpp
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite Document Library
|
||||
// Copyright (c) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Aseprite Document Library
|
||||
// Copyright (c) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2016 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
|
@ -12,6 +12,7 @@
|
|||
#include "doc/color.h"
|
||||
#include "doc/color_mode.h"
|
||||
#include "doc/image_buffer.h"
|
||||
#include "doc/image_iterators2.h"
|
||||
#include "doc/image_spec.h"
|
||||
#include "doc/object.h"
|
||||
#include "doc/pixel_format.h"
|
||||
|
@ -103,6 +104,21 @@ public:
|
|||
virtual void fillRect(int x1, int y1, int x2, int y2, color_t color) = 0;
|
||||
virtual void blendRect(int x1, int y1, int x2, int y2, color_t color, int opacity) = 0;
|
||||
|
||||
ReadIterator readArea() const { return ReadIterator(this, this->bounds()); }
|
||||
WriteIterator writeArea() { return WriteIterator(this, this->bounds()); }
|
||||
|
||||
ReadIterator readArea(const gfx::Rect& bounds,
|
||||
const IteratorStart start = IteratorStart::TopLeft) const
|
||||
{
|
||||
return ReadIterator(this, bounds, start);
|
||||
}
|
||||
|
||||
WriteIterator writeArea(const gfx::Rect& bounds,
|
||||
const IteratorStart start = IteratorStart::TopLeft)
|
||||
{
|
||||
return WriteIterator(this, bounds, start);
|
||||
}
|
||||
|
||||
protected:
|
||||
Image(const ImageSpec& spec);
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Aseprite Document Library
|
||||
// Copyright (c) 2024 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "doc/image.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
ReadIterator::ReadIterator(const Image* image, const gfx::Rect& bounds, const IteratorStart start)
|
||||
: m_rows(bounds.h)
|
||||
{
|
||||
switch (start) {
|
||||
case IteratorStart::TopLeft:
|
||||
m_addr = image->getPixelAddress(bounds.x, bounds.y);
|
||||
m_nextRow = image->rowBytes();
|
||||
break;
|
||||
case IteratorStart::TopRight:
|
||||
m_addr = image->getPixelAddress(bounds.x2() - 1, bounds.y);
|
||||
m_nextRow = image->rowBytes();
|
||||
break;
|
||||
case IteratorStart::BottomLeft:
|
||||
m_addr = image->getPixelAddress(bounds.x, bounds.y2() - 1);
|
||||
m_nextRow = -image->rowBytes();
|
||||
break;
|
||||
case IteratorStart::BottomRight:
|
||||
m_addr = image->getPixelAddress(bounds.x2() - 1, bounds.y2() - 1);
|
||||
m_nextRow = -image->rowBytes();
|
||||
break;
|
||||
}
|
||||
m_addr -= m_nextRow; // This is canceled in the first nextLine() call.
|
||||
}
|
||||
|
||||
} // namespace doc
|
|
@ -0,0 +1,74 @@
|
|||
// Aseprite Document Library
|
||||
// Copyright (c) 2024 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_IMAGE_ITERATOR2_H_INCLUDED
|
||||
#define DOC_IMAGE_ITERATOR2_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/ints.h"
|
||||
#include "gfx/fwd.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
class Image;
|
||||
|
||||
// New iterators classes.
|
||||
|
||||
enum class IteratorStart : uint8_t { TopLeft, TopRight, BottomLeft, BottomRight };
|
||||
|
||||
class ReadIterator {
|
||||
public:
|
||||
ReadIterator(const Image* image,
|
||||
const gfx::Rect& bounds,
|
||||
IteratorStart start = IteratorStart::TopLeft);
|
||||
|
||||
const uint8_t* addr8() const { return m_addr; }
|
||||
const uint16_t* addr16() const { return (uint16_t*)m_addr; }
|
||||
const uint32_t* addr32() const { return (uint32_t*)m_addr; }
|
||||
|
||||
template<typename ImageTraits>
|
||||
typename ImageTraits::const_address_t addr() const
|
||||
{
|
||||
return (typename ImageTraits::const_address_t)m_addr;
|
||||
}
|
||||
|
||||
bool nextLine()
|
||||
{
|
||||
m_addr += m_nextRow;
|
||||
return (m_rows-- > 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t* m_addr = nullptr;
|
||||
|
||||
private:
|
||||
int m_rows = 0;
|
||||
int m_nextRow = 0;
|
||||
};
|
||||
|
||||
class WriteIterator : public ReadIterator {
|
||||
public:
|
||||
WriteIterator(Image* image,
|
||||
const gfx::Rect& bounds,
|
||||
const IteratorStart start = IteratorStart::TopLeft)
|
||||
: ReadIterator(image, bounds, start)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t* addr8() { return m_addr; }
|
||||
uint16_t* addr16() { return (uint16_t*)m_addr; }
|
||||
uint32_t* addr32() { return (uint32_t*)m_addr; }
|
||||
|
||||
template<typename ImageTraits>
|
||||
uint32_t* addr()
|
||||
{
|
||||
return (typename ImageTraits::address_t)m_addr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "doc/algorithm/random_image.h"
|
||||
#include "doc/image.h"
|
||||
#include "doc/primitives.h"
|
||||
|
||||
|
@ -25,9 +26,27 @@ protected:
|
|||
ImageAllTypes() {}
|
||||
};
|
||||
|
||||
typedef testing::Types<RgbTraits, GrayscaleTraits, IndexedTraits, BitmapTraits> ImageAllTraits;
|
||||
using ImageAllTraits = testing::Types<RgbTraits, GrayscaleTraits, IndexedTraits, BitmapTraits>;
|
||||
|
||||
TYPED_TEST_SUITE(ImageAllTypes, ImageAllTraits);
|
||||
|
||||
#if DOC_USE_BITMAP_AS_1BPP
|
||||
|
||||
template<typename T>
|
||||
class ImageAllTypesNoBitmap : public testing::Test {
|
||||
protected:
|
||||
ImageAllTypesNoBitmap() {}
|
||||
};
|
||||
|
||||
using ImageAllTraitsNoBitmap = testing::Types<RgbTraits, GrayscaleTraits, IndexedTraits>;
|
||||
TYPED_TEST_SUITE(ImageAllTypesNoBitmap, ImageAllTraitsNoBitmap);
|
||||
|
||||
#else // !DOC_USE_BITMAP_AS_1BPP
|
||||
|
||||
#define ImageAllTypesNoBitmap ImageAllTypes
|
||||
|
||||
#endif // !DOC_USE_BITMAP_AS_1BPP
|
||||
|
||||
TYPED_TEST(ImageAllTypes, PutGetAndIterators)
|
||||
{
|
||||
using ImageTraits = TypeParam;
|
||||
|
@ -195,6 +214,75 @@ TYPED_TEST(ImageAllTypes, FillRect)
|
|||
}
|
||||
}
|
||||
|
||||
TYPED_TEST(ImageAllTypesNoBitmap, NewIterators)
|
||||
{
|
||||
using ImageTraits = TypeParam;
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
const int w = 1 + i;
|
||||
const int h = 1 + i;
|
||||
|
||||
std::unique_ptr<Image> image(Image::create(ImageTraits::pixel_format, w, h));
|
||||
doc::algorithm::random_image(image.get());
|
||||
|
||||
// TopLeft
|
||||
{
|
||||
int v = 0;
|
||||
auto it = image->readArea(image->bounds(), IteratorStart::TopLeft);
|
||||
while (it.nextLine()) {
|
||||
auto* addr = (typename ImageTraits::address_t)it.addr8();
|
||||
for (int u = 0; u < w; ++u, ++addr) {
|
||||
auto expected = get_pixel_fast<ImageTraits>(image.get(), u, v);
|
||||
ASSERT_EQ(expected, *addr);
|
||||
}
|
||||
++v;
|
||||
}
|
||||
}
|
||||
|
||||
// TopRight
|
||||
{
|
||||
int v = 0;
|
||||
auto it = image->readArea(image->bounds(), IteratorStart::TopRight);
|
||||
while (it.nextLine()) {
|
||||
auto* addr = (typename ImageTraits::address_t)it.addr8();
|
||||
for (int u = w - 1; u >= 0; --u, --addr) {
|
||||
auto expected = get_pixel_fast<ImageTraits>(image.get(), u, v);
|
||||
ASSERT_EQ(expected, *addr);
|
||||
}
|
||||
++v;
|
||||
}
|
||||
}
|
||||
|
||||
// BottomLeft
|
||||
{
|
||||
int v = h - 1;
|
||||
auto it = image->readArea(image->bounds(), IteratorStart::BottomLeft);
|
||||
while (it.nextLine()) {
|
||||
auto* addr = (typename ImageTraits::address_t)it.addr8();
|
||||
for (int u = 0; u < w; ++u, ++addr) {
|
||||
auto expected = get_pixel_fast<ImageTraits>(image.get(), u, v);
|
||||
ASSERT_EQ(expected, *addr);
|
||||
}
|
||||
--v;
|
||||
}
|
||||
}
|
||||
|
||||
// BottomRight
|
||||
{
|
||||
int v = h - 1;
|
||||
auto it = image->readArea(image->bounds(), IteratorStart::BottomRight);
|
||||
while (it.nextLine()) {
|
||||
auto* addr = (typename ImageTraits::address_t)it.addr8();
|
||||
for (int u = w - 1; u >= 0; --u, --addr) {
|
||||
auto expected = get_pixel_fast<ImageTraits>(image.get(), u, v);
|
||||
ASSERT_EQ(expected, *addr);
|
||||
}
|
||||
--v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
|
Loading…
Reference in New Issue