Equality operator in PixelBuffer

This commit is contained in:
Matthias Koefferlein 2022-05-07 18:48:45 +02:00
parent 958e1f7c59
commit 101544ab78
5 changed files with 134 additions and 30 deletions

View File

@ -143,6 +143,12 @@ Class<lay::PixelBuffer> decl_PixelBuffer ("lay", "PixelBuffer",
"\n" "\n"
"The pixels are basically uninitialized. You will need to use \\fill to initialize them to a certain value." "The pixels are basically uninitialized. You will need to use \\fill to initialize them to a certain value."
) + ) +
gsi::method ("==", &lay::PixelBuffer::operator==, gsi::arg ("other"),
"@brief Returns a value indicating whether self is identical to the other image\n"
) +
gsi::method ("!=", &lay::PixelBuffer::operator!=, gsi::arg ("other"),
"@brief Returns a value indicating whether self is not identical to the other image\n"
) +
gsi::method ("transparent=", &lay::PixelBuffer::set_transparent, gsi::arg ("t"), gsi::method ("transparent=", &lay::PixelBuffer::set_transparent, gsi::arg ("t"),
"@brief Sets a flag indicating whether the pixel buffer supports an alpha channel\n" "@brief Sets a flag indicating whether the pixel buffer supports an alpha channel\n"
"\n" "\n"
@ -224,7 +230,9 @@ Class<lay::PixelBuffer> decl_PixelBuffer ("lay", "PixelBuffer",
"transparency through an optional alpha channel. The color format for a pixel is " "transparency through an optional alpha channel. The color format for a pixel is "
"\"0xAARRGGBB\" where 'AA' is the alpha value which is ignored in non-transparent mode.\n" "\"0xAARRGGBB\" where 'AA' is the alpha value which is ignored in non-transparent mode.\n"
"\n" "\n"
"This class supports basic operations such as initialization, single-pixel access and I/O to PNG." "This class supports basic operations such as initialization, single-pixel access and I/O to PNG.\n"
"\n"
"This class has been introduced in version 0.28."
); );
@ -335,6 +343,12 @@ Class<lay::BitmapBuffer> decl_BitmapBuffer ("lay", "BitmapBuffer",
"\n" "\n"
"The pixels are basically uninitialized. You will need to use \\fill to initialize them to a certain value." "The pixels are basically uninitialized. You will need to use \\fill to initialize them to a certain value."
) + ) +
gsi::method ("==", &lay::BitmapBuffer::operator==, gsi::arg ("other"),
"@brief Returns a value indicating whether self is identical to the other image\n"
) +
gsi::method ("!=", &lay::BitmapBuffer::operator!=, gsi::arg ("other"),
"@brief Returns a value indicating whether self is not identical to the other image\n"
) +
gsi::method ("fill", &lay::BitmapBuffer::fill, gsi::arg ("color"), gsi::method ("fill", &lay::BitmapBuffer::fill, gsi::arg ("color"),
"@brief Fills the pixel buffer with the given pixel value\n" "@brief Fills the pixel buffer with the given pixel value\n"
) + ) +
@ -391,7 +405,9 @@ Class<lay::BitmapBuffer> decl_BitmapBuffer ("lay", "BitmapBuffer",
"This object is mainly provided for offline rendering of layouts in Qt-less environments.\n" "This object is mainly provided for offline rendering of layouts in Qt-less environments.\n"
"It supports a rectangular pixel space with color values encoded in single bits.\n" "It supports a rectangular pixel space with color values encoded in single bits.\n"
"\n" "\n"
"This class supports basic operations such as initialization, single-pixel access and I/O to PNG." "This class supports basic operations such as initialization, single-pixel access and I/O to PNG.\n"
"\n"
"This class has been introduced in version 0.28."
); );
} }

View File

@ -169,6 +169,31 @@ PixelBuffer::~PixelBuffer ()
// .. nothing yet .. // .. nothing yet ..
} }
bool
PixelBuffer::operator== (const PixelBuffer &other) const
{
if (width () != other.width () || height () != other.height ()) {
return false;
}
if (transparent () != other.transparent ()) {
return false;
}
lay::color_t m = transparent () ? 0xffffffff : 0xffffff;
for (unsigned int i = 0; i < other.height (); ++i) {
const lay::color_t *d = scan_line (i);
const lay::color_t *de = d + width ();
const lay::color_t *dd = other.scan_line (i);
while (d != de) {
if (((*d++ ^ *dd++) & m) != 0) {
return false;
}
}
}
return true;
}
PixelBuffer & PixelBuffer &
PixelBuffer::operator= (const PixelBuffer &other) PixelBuffer::operator= (const PixelBuffer &other)
{ {
@ -485,6 +510,34 @@ BitmapBuffer::~BitmapBuffer ()
// .. nothing yet .. // .. nothing yet ..
} }
bool
BitmapBuffer::operator== (const BitmapBuffer &other) const
{
if (width () != other.width () || height () != other.height ()) {
return false;
}
for (unsigned int i = 0; i < other.height (); ++i) {
const uint8_t *d = scan_line (i);
const uint8_t *dd = other.scan_line (i);
unsigned int bits_left = width ();
while (bits_left >= 8) {
if (*d++ != *dd++) {
return false;
}
bits_left -= 8;
}
if (bits_left > 0) {
unsigned int m = (0x01 << bits_left) - 1;
if (((*d ^ *dd) & m) != 0) {
return false;
}
}
}
return true;
}
BitmapBuffer & BitmapBuffer &
BitmapBuffer::operator= (const BitmapBuffer &other) BitmapBuffer::operator= (const BitmapBuffer &other)
{ {

View File

@ -111,6 +111,19 @@ public:
*/ */
~PixelBuffer (); ~PixelBuffer ();
/**
* @brief Equality
*/
bool operator== (const PixelBuffer &other) const;
/**
* @brief Inequality
*/
bool operator!= (const PixelBuffer &other) const
{
return !operator== (other);
}
/** /**
* @brief Assignment * @brief Assignment
*/ */
@ -334,6 +347,19 @@ public:
*/ */
BitmapBuffer (BitmapBuffer &&other); BitmapBuffer (BitmapBuffer &&other);
/**
* @brief Equality
*/
bool operator== (const BitmapBuffer &other) const;
/**
* @brief Inequality
*/
bool operator!= (const BitmapBuffer &other) const
{
return !operator== (other);
}
/** /**
* @brief Destructor * @brief Destructor
*/ */

View File

@ -74,35 +74,12 @@ static bool compare_images_mono (const QImage &qimg, const std::string &au)
static bool compare_images (const lay::PixelBuffer &img, const lay::PixelBuffer &img2) static bool compare_images (const lay::PixelBuffer &img, const lay::PixelBuffer &img2)
{ {
if (img2.width () == img.width () && img2.height () == img.height ()) { return img == img2;
for (unsigned int j = 0; j < img.height (); ++j) {
for (unsigned int i = 0; i < img.width (); ++i) {
if (((const lay::color_t *) img.scan_line (j))[i] != ((const lay::color_t *) img2.scan_line (j))[i]) {
return false;
}
}
}
return true;
} else {
return false;
}
} }
static bool compare_images (const lay::BitmapBuffer &img, const lay::BitmapBuffer &img2) static bool compare_images (const lay::BitmapBuffer &img, const lay::BitmapBuffer &img2)
{ {
if (img2.width () == img.width () && img2.height () == img.height ()) { return img == img2;
// NOTE: slooooow ...
for (unsigned int j = 0; j < img.height (); ++j) {
for (unsigned int i = 0; i < img.width (); ++i) {
if ((img.scan_line (j)[i / 8] & (0x01 << (i % 8))) != (img2.scan_line (j)[i / 8] & (0x01 << (i % 8)))) {
return false;
}
}
}
return true;
} else {
return false;
}
} }
TEST(1) TEST(1)

View File

@ -41,17 +41,21 @@ class LAYPixelBuffer_TestClass < TestBase
def test_1 def test_1
pb = RBA::PixelBuffer::new pb_null = RBA::PixelBuffer::new
assert_equal(pb.width, 0) assert_equal(pb_null.width, 0)
assert_equal(pb.height, 0) assert_equal(pb_null.height, 0)
pb = RBA::PixelBuffer::new(10, 20) pb = RBA::PixelBuffer::new(10, 20)
assert_equal(compare(pb_null, pb), false)
assert_equal(pb_null == pb, false)
assert_equal(pb.width, 10) assert_equal(pb.width, 10)
assert_equal(pb.height, 20) assert_equal(pb.height, 20)
assert_equal(pb.transparent, false) assert_equal(pb.transparent, false)
pb_copy = pb.dup
pb.transparent = true pb.transparent = true
assert_equal(pb.transparent, true) assert_equal(pb.transparent, true)
assert_equal(pb_copy == pb, false)
pb.fill(0xf0010203) pb.fill(0xf0010203)
assert_equal(pb.pixel(0, 0), 0xf0010203) assert_equal(pb.pixel(0, 0), 0xf0010203)
@ -66,12 +70,14 @@ class LAYPixelBuffer_TestClass < TestBase
pb_copy = pb.dup pb_copy = pb.dup
assert_equal(compare(pb_copy, pb), true) assert_equal(compare(pb_copy, pb), true)
assert_equal(pb_copy == pb, true)
pb.set_pixel(1, 2, 0x112233) pb.set_pixel(1, 2, 0x112233)
assert_equal(pb.pixel(0, 0), 0xf0010203) assert_equal(pb.pixel(0, 0), 0xf0010203)
assert_equal(pb.pixel(1, 2), 0xff112233) assert_equal(pb.pixel(1, 2), 0xff112233)
assert_equal(pb_copy.pixel(1, 2), 0xff102030) assert_equal(pb_copy.pixel(1, 2), 0xff102030)
assert_equal(compare(pb_copy, pb), false) assert_equal(compare(pb_copy, pb), false)
assert_equal(pb_copy == pb, false)
pb_copy.swap(pb) pb_copy.swap(pb)
assert_equal(pb_copy.pixel(1, 2), 0xff112233) assert_equal(pb_copy.pixel(1, 2), 0xff112233)
@ -88,14 +94,40 @@ class LAYPixelBuffer_TestClass < TestBase
pb.set_pixel(1, 2, 0x112233) pb.set_pixel(1, 2, 0x112233)
assert_equal(compare(pb1, pb), false) assert_equal(compare(pb1, pb), false)
assert_equal(pb1 == pb, false)
diff = pb1.diff(pb) diff = pb1.diff(pb)
pb1.patch(diff) pb1.patch(diff)
assert_equal(compare(pb1, pb), true) assert_equal(compare(pb1, pb), true)
assert_equal(pb1 == pb, true)
end end
def test_3 def test_3
pb = RBA::PixelBuffer::new(10, 20)
pb.fill(0xf0010203)
pb1 = pb.dup
pb.set_pixel(1, 2, 0x112233)
pb1 = pb.dup
pb.set_pixel(1, 2, 0xf0112233)
assert_equal(compare(pb1, pb), true)
assert_equal(pb1 == pb, true) # not transparent -> alpha is ignored
pb1.transparent = true
pb.transparent = true
assert_equal(compare(pb1, pb), true)
assert_equal(pb1 == pb, true)
pb.set_pixel(1, 2, 0xf0112233)
assert_equal(compare(pb1, pb), false)
assert_equal(pb1 == pb, false) # now, alpha matters
end
def test_4
pb = RBA::PixelBuffer::new(10, 20) pb = RBA::PixelBuffer::new(10, 20)
pb.transparent = true pb.transparent = true