GSI binding for PixelBuffer and tests

This commit is contained in:
Matthias Koefferlein 2022-05-07 12:53:00 +02:00
parent 0798c4de51
commit 32813b80f2
9 changed files with 652 additions and 10 deletions

View File

@ -0,0 +1,395 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "gsiDecl.h"
#include "layPixelBuffer.h"
#include <QBuffer>
namespace gsi
{
// -------------------------------------------------------------------------------------
// lay::BitmapBuffer
static lay::PixelBuffer *create_pixel_buffer (unsigned int w, unsigned int h)
{
return new lay::PixelBuffer (w, h);
}
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
static void fill_with_qcolor (lay::PixelBuffer *pb, QColor c)
{
pb->fill (c.rgb ());
}
#endif
lay::color_t get_pixel_from_pixel_buffer (const lay::PixelBuffer *pb, unsigned int x, unsigned int y)
{
if (x < pb->width () && y < pb->height ()) {
return pb->scan_line (y)[x];
} else {
return lay::color_t (0);
}
}
void set_pixel_in_pixel_buffer (lay::PixelBuffer *pb, unsigned int x, unsigned int y, lay::color_t c)
{
if (! pb->transparent ()) {
c |= 0xff000000; // ensures that alpha is set properly even if not required
}
if (x < pb->width () && y < pb->height ()) {
pb->scan_line (y)[x] = c;
}
}
static lay::PixelBuffer read_pixel_buffer (const std::string &file)
{
#if defined(HAVE_PNG)
tl::InputStream stream (file);
return lay::PixelBuffer::read_png (stream);
#elif defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
// QImage is fallback
QImage img;
img.load (tl::to_qstring (file), "PNG");
return lay::PixelBuffer::from_image (img);
#else
throw tl::Exception (tl::to_string (tr ("No PNG support compiled in for PixelBuffer")));
return lay::PixelBuffer ();
#endif
}
// TODO: there should be some more efficient version of byte strings which avoid copies
static lay::PixelBuffer pixel_buffer_from_png (const std::vector<char> &data)
{
#if defined(HAVE_PNG)
tl::InputMemoryStream data_stream (data.begin ().operator-> (), data.size ());
tl::InputStream stream (data_stream);
return lay::PixelBuffer::read_png (stream);
#elif defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
// QImage is fallback
tl_assert (data.size () < std::numeric_limits<int>::max ());
QImage img = QImage::fromData ((const uchar *) data.begin ().operator-> (), int (data.size ()));
return lay::PixelBuffer::from_image (img);
#else
throw tl::Exception (tl::to_string (tr ("No PNG support compiled in for PixelBuffer")));
return lay::PixelBuffer ();
#endif
}
static void write_pixel_buffer (const lay::PixelBuffer *pb, const std::string &file)
{
#if defined(HAVE_PNG)
tl::OutputStream stream (file);
pb->write_png (stream);
#elif defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
// QImage is fallback
QImage img = pb->to_image ();
img.save (tl::to_qstring (file), "PNG");
#else
throw tl::Exception (tl::to_string (tr ("No PNG support compiled in for PixelBuffer")));
#endif
}
// TODO: there should be some more efficient version of byte strings which avoid copies
static std::vector<char> pixel_buffer_to_png (const lay::PixelBuffer *pb)
{
#if defined(HAVE_PNG)
tl::OutputMemoryStream data_stream;
{
tl::OutputStream stream (data_stream);
pb->write_png (stream);
}
return std::vector<char> (data_stream.data (), data_stream.data () + data_stream.size ());
#elif defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
// QImage is fallback
QImage img = pb->to_image ();
QBuffer data;
img.save (&data, "PNG");
return std::vector<char> (data.data ().constData (), data.data ().constEnd ());
#else
throw tl::Exception (tl::to_string (tr ("No PNG support compiled in for PixelBuffer")));
#endif
}
Class<lay::PixelBuffer> decl_PixelBuffer ("lay", "PixelBuffer",
gsi::constructor ("new", &create_pixel_buffer, gsi::arg ("width"), gsi::arg ("height"),
"@brief Creates a pixel buffer object\n"
"\n"
"@param width The width in pixels\n"
"@param height The height in pixels\n"
"\n"
"The pixels are basically uninitialized. You will need to use \\fill to initialize them to a certain value."
) +
gsi::method ("transparent=", &lay::PixelBuffer::set_transparent, gsi::arg ("t"),
"@brief Sets a flag indicating whether the pixel buffer supports an alpha channel\n"
"\n"
"By default, the pixel buffer does not support an alpha channel.\n"
) +
gsi::method ("transparent", &lay::PixelBuffer::transparent,
"@brief Gets a flag indicating whether the pixel buffer supports an alpha channel\n"
) +
gsi::method ("fill", &lay::PixelBuffer::fill, gsi::arg ("color"),
"@brief Fills the pixel buffer with the given pixel value\n"
) +
#if defined(HAVE_QT)
gsi::method_ext ("fill", &fill_with_qcolor, gsi::arg ("color"),
"@brief Fills the pixel buffer with the given QColor\n"
) +
#endif
gsi::method ("swap", &lay::PixelBuffer::swap, gsi::arg ("other"),
"@brief Swaps data with another PixelBuffer object\n"
) +
gsi::method ("width", &lay::PixelBuffer::width,
"@brief Gets the width of the pixel buffer in pixels\n"
) +
gsi::method ("height", &lay::PixelBuffer::height,
"@brief Gets the height of the pixel buffer in pixels\n"
) +
gsi::method_ext ("set_pixel", &set_pixel_in_pixel_buffer, gsi::arg ("x"), gsi::arg ("y"), gsi::arg ("c"),
"@brief Sets the value of the pixel at position x, y\n"
) +
gsi::method_ext ("pixel", &get_pixel_from_pixel_buffer, gsi::arg ("x"), gsi::arg ("y"),
"@brief Gets the value of the pixel at position x, y\n"
) +
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
gsi::method ("to_qimage", &lay::PixelBuffer::to_image_copy,
"@brief Converts the pixel buffer to a \\QImage object"
) +
gsi::method ("from_qimage", &lay::PixelBuffer::from_image, gsi::arg ("qimage"),
"@brief Creates a pixel buffer object from a QImage object\n"
) +
#endif
gsi::method ("read_png", &read_pixel_buffer, gsi::arg ("file"),
"@brief Reads the pixel buffer from a PNG file"
"\n"
"This method may not be available if PNG support is not compiled into KLayout."
) +
gsi::method ("from_png_data", &pixel_buffer_from_png, gsi::arg ("data"),
"@brief Reads the pixel buffer from a PNG byte stream"
"\n"
"This method may not be available if PNG support is not compiled into KLayout."
) +
gsi::method_ext ("write_png", &write_pixel_buffer, gsi::arg ("file"),
"@brief Writes the pixel buffer to a PNG file"
"\n"
"This method may not be available if PNG support is not compiled into KLayout."
) +
gsi::method_ext ("to_png_data", &pixel_buffer_to_png,
"@brief Converts the pixel buffer to a PNG byte stream"
"\n"
"This method may not be available if PNG support is not compiled into KLayout."
) +
gsi::method ("patch", &lay::PixelBuffer::patch, gsi::arg ("other"),
"@brief Patches another pixel buffer into this one\n"
"\n"
"This method is the inverse of \\diff - it will patch the difference image created by diff into this "
"pixel buffer. Note that this method will not do true alpha blending and requires the other pixel buffer "
"to have the same format than self. Self will be modified by this operation."
) +
gsi::method ("diff", &lay::PixelBuffer::diff, gsi::arg ("other"),
"@brief Creates a difference image\n"
"\n"
"This method is provided to support transfer of image differences - i.e. small updates instead of full images. "
"It works for non-transparent images only and generates an image with transpareny enabled and with the new pixel values for pixels that have changed. "
"The alpha value will be 0 for identical images and 255 for pixels with different values. "
"This way, the difference image can be painted over the original image to generate the new image."
),
"@brief A simplistic pixel buffer representing an image of ARGB32 or RGB32 values\n"
"\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 32bit integers. It supports "
"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"
"\n"
"This class supports basic operations such as initialization, single-pixel access and I/O to PNG."
);
// -------------------------------------------------------------------------------------
// lay::BitmapBuffer
static lay::BitmapBuffer *create_bitmap_buffer (unsigned int w, unsigned int h)
{
return new lay::BitmapBuffer (w, h);
}
bool get_pixel_from_bitmap_buffer (const lay::BitmapBuffer *pb, unsigned int x, unsigned int y)
{
if (x < pb->width () && y < pb->height ()) {
return (pb->scan_line (y)[x / 8] & (0x01 << (x % 8))) != 0;
} else {
return false;
}
}
void set_pixel_in_bitmap_buffer (lay::BitmapBuffer *pb, unsigned int x, unsigned int y, bool c)
{
if (x < pb->width () && y < pb->height ()) {
if (c) {
pb->scan_line (y)[x / 8] |= 0x01 << (x % 8);
} else {
pb->scan_line (y)[x / 8] &= ~(0x01 << (x % 8));
}
}
}
static lay::BitmapBuffer read_bitmap_buffer (const std::string &file)
{
#if defined(HAVE_PNG)
tl::InputStream stream (file);
return lay::BitmapBuffer::read_png (stream);
#elif defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
// QImage is fallback
QImage img;
img.load (tl::to_qstring (file), "PNG");
return lay::BitmapBuffer::from_image (img);
#else
throw tl::Exception (tl::to_string (tr ("No PNG support compiled in for BitmapBuffer")));
return lay::BitmapBuffer ();
#endif
}
// TODO: there should be some more efficient version of byte strings which avoid copies
static lay::BitmapBuffer bitmap_buffer_from_png (const std::vector<char> &data)
{
#if defined(HAVE_PNG)
tl::InputMemoryStream data_stream (data.begin ().operator-> (), data.size ());
tl::InputStream stream (data_stream);
return lay::BitmapBuffer::read_png (stream);
#elif defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
// QImage is fallback
tl_assert (data.size () < std::numeric_limits<int>::max ());
QImage img = QImage::fromData ((const uchar *) data.begin ().operator-> (), int (data.size ()));
return lay::BitmapBuffer::from_image (img);
#else
throw tl::Exception (tl::to_string (tr ("No PNG support compiled in for BitmapBuffer")));
return lay::BitmapBuffer ();
#endif
}
static void write_bitmap_buffer (const lay::BitmapBuffer *pb, const std::string &file)
{
#if defined(HAVE_PNG)
tl::OutputStream stream (file);
pb->write_png (stream);
#elif defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
// QImage is fallback
QImage img = pb->to_image ();
img.save (tl::to_qstring (file), "PNG");
#else
throw tl::Exception (tl::to_string (tr ("No PNG support compiled in for BitmapBuffer")));
#endif
}
// TODO: there should be some more efficient version of byte strings which avoid copies
static std::vector<char> bitmap_buffer_to_png (const lay::BitmapBuffer *pb)
{
#if defined(HAVE_PNG)
tl::OutputMemoryStream data_stream;
{
tl::OutputStream stream (data_stream);
pb->write_png (stream);
}
return std::vector<char> (data_stream.data (), data_stream.data () + data_stream.size ());
#elif defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
// QImage is fallback
QImage img = pb->to_image ();
QBuffer data;
img.save (&data, "PNG");
return std::vector<char> (data.data ().constData (), data.data ().constEnd ());
#else
throw tl::Exception (tl::to_string (tr ("No PNG support compiled in for BitmapBuffer")));
#endif
}
Class<lay::BitmapBuffer> decl_BitmapBuffer ("lay", "BitmapBuffer",
gsi::constructor ("new", &create_bitmap_buffer, gsi::arg ("width"), gsi::arg ("height"),
"@brief Creates a pixel buffer object\n"
"\n"
"@param width The width in pixels\n"
"@param height The height in pixels\n"
"\n"
"The pixels are basically uninitialized. You will need to use \\fill to initialize them to a certain value."
) +
gsi::method ("fill", &lay::BitmapBuffer::fill, gsi::arg ("color"),
"@brief Fills the pixel buffer with the given pixel value\n"
) +
#if defined(HAVE_QT)
gsi::method_ext ("fill", &fill_with_qcolor, gsi::arg ("color"),
"@brief Fills the pixel buffer with the given QColor\n"
) +
#endif
gsi::method ("swap", &lay::BitmapBuffer::swap, gsi::arg ("other"),
"@brief Swaps data with another BitmapBuffer object\n"
) +
gsi::method ("width", &lay::BitmapBuffer::width,
"@brief Gets the width of the pixel buffer in pixels\n"
) +
gsi::method ("height", &lay::BitmapBuffer::height,
"@brief Gets the height of the pixel buffer in pixels\n"
) +
gsi::method_ext ("set_pixel", &set_pixel_in_bitmap_buffer, gsi::arg ("x"), gsi::arg ("y"), gsi::arg ("c"),
"@brief Sets the value of the pixel at position x, y\n"
) +
gsi::method_ext ("pixel", &get_pixel_from_bitmap_buffer, gsi::arg ("x"), gsi::arg ("y"),
"@brief Gets the value of the pixel at position x, y\n"
) +
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
gsi::method ("to_qimage", &lay::BitmapBuffer::to_image_copy,
"@brief Converts the pixel buffer to a \\QImage object"
) +
gsi::method ("from_qimage", &lay::BitmapBuffer::from_image, gsi::arg ("qimage"),
"@brief Creates a pixel buffer object from a QImage object\n"
) +
#endif
gsi::method ("read_png", &read_bitmap_buffer, gsi::arg ("file"),
"@brief Reads the pixel buffer from a PNG file"
"\n"
"This method may not be available if PNG support is not compiled into KLayout."
) +
gsi::method ("from_png_data", &bitmap_buffer_from_png, gsi::arg ("data"),
"@brief Reads the pixel buffer from a PNG byte stream"
"\n"
"This method may not be available if PNG support is not compiled into KLayout."
) +
gsi::method_ext ("write_png", &write_bitmap_buffer, gsi::arg ("file"),
"@brief Writes the pixel buffer to a PNG file"
"\n"
"This method may not be available if PNG support is not compiled into KLayout."
) +
gsi::method_ext ("to_png_data", &bitmap_buffer_to_png,
"@brief Converts the pixel buffer to a PNG byte stream"
"\n"
"This method may not be available if PNG support is not compiled into KLayout."
),
"@brief A simplistic pixel buffer representing monochrome image\n"
"\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"
"\n"
"This class supports basic operations such as initialization, single-pixel access and I/O to PNG."
);
}

View File

@ -212,6 +212,10 @@ PixelBuffer::swap (PixelBuffer &other)
void void
PixelBuffer::fill (lay::color_t c) PixelBuffer::fill (lay::color_t c)
{ {
if (! transparent ()) {
c |= 0xff000000; // ensures that alpha is properly set
}
color_t *d = data (); color_t *d = data ();
for (unsigned int i = 0; i < m_height; ++i) { for (unsigned int i = 0; i < m_height; ++i) {
for (unsigned int j = 0; j < m_width; ++j) { for (unsigned int j = 0; j < m_width; ++j) {
@ -260,6 +264,17 @@ PixelBuffer::to_image_copy () const
memcpy (img.bits (), data (), img.sizeInBytes ()); memcpy (img.bits (), data (), img.sizeInBytes ());
return img; return img;
} }
PixelBuffer
PixelBuffer::from_image (const QImage &img)
{
if (img.format () != QImage::Format_ARGB32 && img.format () != QImage::Format_RGB32) {
QImage img_argb32 = img.convertToFormat (QImage::Format_ARGB32);
return PixelBuffer (img_argb32.width (), img_argb32.height (), (const lay::color_t *) img_argb32.bits ());
} else {
return PixelBuffer (img.width (), img.height (), (const lay::color_t *) img.bits ());
}
}
#endif #endif
void void
@ -376,7 +391,7 @@ PixelBuffer::read_png (tl::InputStream &input)
} }
void void
PixelBuffer::write_png (tl::OutputStream &output) PixelBuffer::write_png (tl::OutputStream &output) const
{ {
png_structp png_ptr = NULL; png_structp png_ptr = NULL;
png_infop info_ptr = NULL; png_infop info_ptr = NULL;
@ -559,6 +574,17 @@ BitmapBuffer::to_image_copy () const
memcpy (img.bits (), data (), img.sizeInBytes ()); memcpy (img.bits (), data (), img.sizeInBytes ());
return img; return img;
} }
BitmapBuffer
BitmapBuffer::from_image (const QImage &img)
{
if (img.format () != QImage::Format_MonoLSB) {
QImage img_monolsb = img.convertToFormat (QImage::Format_MonoLSB);
return BitmapBuffer (img_monolsb.width (), img_monolsb.height (), (const uint8_t *) img_monolsb.bits ());
} else {
return BitmapBuffer (img.width (), img.height (), (const uint8_t *) img.bits ());
}
}
#endif #endif
#if defined(HAVE_PNG) #if defined(HAVE_PNG)
@ -610,7 +636,7 @@ BitmapBuffer::read_png (tl::InputStream &input)
} }
void void
BitmapBuffer::write_png (tl::OutputStream &output) BitmapBuffer::write_png (tl::OutputStream &output) const
{ {
png_structp png_ptr = NULL; png_structp png_ptr = NULL;
png_infop info_ptr = NULL; png_infop info_ptr = NULL;

View File

@ -204,6 +204,11 @@ public:
* PixelBuffer. * PixelBuffer.
*/ */
QImage to_image_copy () const; QImage to_image_copy () const;
/**
* @brief Creates a pixel buffer from a QImage object
*/
static PixelBuffer from_image (const QImage &img);
#endif #endif
#if defined(HAVE_PNG) #if defined(HAVE_PNG)
@ -217,7 +222,7 @@ public:
* @brief Writes the PixelBuffer object to a PNG file * @brief Writes the PixelBuffer object to a PNG file
* Throws a PixelBufferWriteError if an error occurs. * Throws a PixelBufferWriteError if an error occurs.
*/ */
void write_png (tl::OutputStream &output); void write_png (tl::OutputStream &output) const;
#endif #endif
/** /**
@ -414,6 +419,11 @@ public:
* BitmapBuffer. * BitmapBuffer.
*/ */
QImage to_image_copy () const; QImage to_image_copy () const;
/**
* @brief Creates a pixel buffer from a QImage object
*/
static BitmapBuffer from_image (const QImage &img);
#endif #endif
#if defined(HAVE_PNG) #if defined(HAVE_PNG)
@ -427,7 +437,7 @@ public:
* @brief Writes the PixelBuffer object to a PNG file * @brief Writes the PixelBuffer object to a PNG file
* Throws a PixelBufferWriteError if an error occurs. * Throws a PixelBufferWriteError if an error occurs.
*/ */
void write_png (tl::OutputStream &output); void write_png (tl::OutputStream &output) const;
#endif #endif
private: private:

View File

@ -242,6 +242,7 @@ SOURCES += \
gsiDeclLayLayoutView.cc \ gsiDeclLayLayoutView.cc \
gsiDeclLayMarker.cc \ gsiDeclLayMarker.cc \
gsiDeclLayPlugin.cc \ gsiDeclLayPlugin.cc \
gsiDeclLayPixelBuffer.cc \
layAnnotationShapes.cc \ layAnnotationShapes.cc \
layBitmap.cc \ layBitmap.cc \
layBitmapRenderer.cc \ layBitmapRenderer.cc \

View File

@ -153,33 +153,33 @@ TEST(1)
EXPECT_EQ (compare_images (img, img2), false); EXPECT_EQ (compare_images (img, img2), false);
EXPECT_EQ (img.scan_line (5)[10], 0x332211); EXPECT_EQ (img.scan_line (5)[10], 0x332211);
EXPECT_EQ (img2.scan_line (5)[8], 0x010203); EXPECT_EQ (img2.scan_line (5)[8], 0xff010203);
img = std::move (img2); img = std::move (img2);
EXPECT_EQ (compare_images (img, img2), false); EXPECT_EQ (compare_images (img, img2), false);
EXPECT_EQ (img.width (), 10); EXPECT_EQ (img.width (), 10);
EXPECT_EQ (img.height (), 16); EXPECT_EQ (img.height (), 16);
EXPECT_EQ (img.scan_line (5)[8], 0x010203); EXPECT_EQ (img.scan_line (5)[8], 0xff010203);
lay::PixelBuffer img3 (img); lay::PixelBuffer img3 (img);
EXPECT_EQ (compare_images (img, img3), true); EXPECT_EQ (compare_images (img, img3), true);
EXPECT_EQ (img3.width (), 10); EXPECT_EQ (img3.width (), 10);
EXPECT_EQ (img3.height (), 16); EXPECT_EQ (img3.height (), 16);
EXPECT_EQ (img3.scan_line (5)[8], 0x010203); EXPECT_EQ (img3.scan_line (5)[8], 0xff010203);
img.fill (0x102030); img.fill (0x102030);
EXPECT_EQ (compare_images (img, img3), false); EXPECT_EQ (compare_images (img, img3), false);
EXPECT_EQ (img3.width (), 10); EXPECT_EQ (img3.width (), 10);
EXPECT_EQ (img3.height (), 16); EXPECT_EQ (img3.height (), 16);
EXPECT_EQ (img3.scan_line (5)[8], 0x010203); EXPECT_EQ (img3.scan_line (5)[8], 0xff010203);
EXPECT_EQ (img.width (), 10); EXPECT_EQ (img.width (), 10);
EXPECT_EQ (img.height (), 16); EXPECT_EQ (img.height (), 16);
EXPECT_EQ (img.scan_line (5)[8], 0x102030); EXPECT_EQ (img.scan_line (5)[8], 0xff102030);
lay::PixelBuffer img4 (std::move (img)); lay::PixelBuffer img4 (std::move (img));
EXPECT_EQ (img4.width (), 10); EXPECT_EQ (img4.width (), 10);
EXPECT_EQ (img4.height (), 16); EXPECT_EQ (img4.height (), 16);
EXPECT_EQ (img4.scan_line (5)[8], 0x102030); EXPECT_EQ (img4.scan_line (5)[8], 0xff102030);
// other constructors // other constructors
EXPECT_EQ (compare_images (lay::PixelBuffer (img4.width (), img4.height (), (const lay::color_t *) img4.data ()), img4), true); EXPECT_EQ (compare_images (lay::PixelBuffer (img4.width (), img4.height (), (const lay::color_t *) img4.data ()), img4), true);
@ -215,6 +215,9 @@ TEST(2)
EXPECT_EQ (compare_images (qimg, au), true); EXPECT_EQ (compare_images (qimg, au), true);
lay::PixelBuffer img_returned = lay::PixelBuffer::from_image (qimg);
EXPECT_EQ (compare_images (img, img_returned), true);
lay::PixelBuffer img_saved (img); lay::PixelBuffer img_saved (img);
img.scan_line (52) [42] = 0xff000000; img.scan_line (52) [42] = 0xff000000;
@ -529,6 +532,9 @@ TEST(12)
EXPECT_EQ (compare_images_mono (qimg, au), true); EXPECT_EQ (compare_images_mono (qimg, au), true);
lay::BitmapBuffer img_returned = lay::BitmapBuffer::from_image (qimg);
EXPECT_EQ (compare_images (img, img_returned), true);
qimg = img.to_image_copy (); qimg = img.to_image_copy ();
img.fill (false); img.fill (false);

View File

@ -143,6 +143,7 @@ RUBYTEST (layLayoutView, "layLayoutView.rb")
RUBYTEST (layMarkers, "layMarkers.rb") RUBYTEST (layMarkers, "layMarkers.rb")
RUBYTEST (layMacro, "layMacro.rb") RUBYTEST (layMacro, "layMacro.rb")
RUBYTEST (layMenuTest, "layMenuTest.rb") RUBYTEST (layMenuTest, "layMenuTest.rb")
RUBYTEST (layPixelBuffer, "layPixelBuffer.rb")
RUBYTEST (laySession, "laySession.rb") RUBYTEST (laySession, "laySession.rb")
RUBYTEST (layTechnologies, "layTechnologies.rb") RUBYTEST (layTechnologies, "layTechnologies.rb")
RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb") RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb")

BIN
testdata/lay/png1.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
testdata/lay/png2.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

203
testdata/ruby/layPixelBuffer.rb vendored Normal file
View File

@ -0,0 +1,203 @@
# encoding: UTF-8
# KLayout Layout Viewer
# Copyright (C) 2006-2022 Matthias Koefferlein
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
if !$:.member?(File::dirname($0))
$:.push(File::dirname($0))
end
load("test_prologue.rb")
class LAYPixelBuffer_TestClass < TestBase
def compare(pb1, pb2)
if pb1.width != pb2.width || pb1.height != pb2.height
return false
end
pb1.width.times do |x|
pb1.height.times do |y|
if pb1.pixel(x, y) != pb2.pixel(x, y)
return false
end
end
end
return true
end
def test_1
pb = RBA::PixelBuffer::new
assert_equal(pb.width, 0)
assert_equal(pb.height, 0)
pb = RBA::PixelBuffer::new(10, 20)
assert_equal(pb.width, 10)
assert_equal(pb.height, 20)
assert_equal(pb.transparent, false)
pb.transparent = true
assert_equal(pb.transparent, true)
pb.fill(0xf0010203)
assert_equal(pb.pixel(0, 0), 0xf0010203)
assert_equal(pb.pixel(1, 2), 0xf0010203)
pb.set_pixel(1, 2, 0xff102030)
assert_equal(pb.pixel(0, 0), 0xf0010203)
assert_equal(pb.pixel(1, 2), 0xff102030)
pb.transparent = false
assert_equal(pb.transparent, false)
pb_copy = pb.dup
assert_equal(compare(pb_copy, pb), true)
pb.set_pixel(1, 2, 0x112233)
assert_equal(pb.pixel(0, 0), 0xf0010203)
assert_equal(pb.pixel(1, 2), 0xff112233)
assert_equal(pb_copy.pixel(1, 2), 0xff102030)
assert_equal(compare(pb_copy, pb), false)
pb_copy.swap(pb)
assert_equal(pb_copy.pixel(1, 2), 0xff112233)
assert_equal(pb.pixel(1, 2), 0xff102030)
end
def test_2
pb = RBA::PixelBuffer::new(10, 20)
pb.fill(0xf0010203)
pb1 = pb.dup
pb.set_pixel(1, 2, 0x112233)
assert_equal(compare(pb1, pb), false)
diff = pb1.diff(pb)
pb1.patch(diff)
assert_equal(compare(pb1, pb), true)
end
def test_3
pb = RBA::PixelBuffer::new(10, 20)
pb.transparent = true
pb.fill(0xf0010203)
if pb.respond_to?(:to_qimage)
assert_equal(pb.to_qimage.pixel(2, 3), 0xf0010203)
pb_copy = RBA::PixelBuffer::from_qimage(pb.to_qimage)
assert_equal(compare(pb, pb_copy), true)
end
png = nil
begin
png = pb.to_png_data
rescue => ex
# No PNG support
end
if png
assert_equal(png.size > 20 && png.size < 200, true) # some range because implementations may differ
pb_copy = RBA::PixelBuffer.from_png_data(png)
assert_equal(compare(pb, pb_copy), true)
tmp = File::join($ut_testtmp, "tmp.png")
pb.write_png(tmp)
pb_copy = RBA::PixelBuffer.read_png(tmp)
assert_equal(compare(pb, pb_copy), true)
end
end
def test_11
pb = RBA::BitmapBuffer::new
assert_equal(pb.width, 0)
assert_equal(pb.height, 0)
pb = RBA::BitmapBuffer::new(10, 20)
assert_equal(pb.width, 10)
assert_equal(pb.height, 20)
pb.fill(false)
assert_equal(pb.pixel(0, 0), false)
assert_equal(pb.pixel(1, 2), false)
pb.set_pixel(1, 2, true)
assert_equal(pb.pixel(0, 0), false)
assert_equal(pb.pixel(1, 2), true)
pb_copy = pb.dup
assert_equal(compare(pb_copy, pb), true)
pb.set_pixel(1, 3, true)
assert_equal(pb.pixel(0, 0), false)
assert_equal(pb.pixel(1, 2), true)
assert_equal(pb.pixel(1, 3), true)
assert_equal(pb_copy.pixel(1, 3), false)
assert_equal(compare(pb_copy, pb), false)
pb_copy.swap(pb)
assert_equal(pb.pixel(1, 3), false)
assert_equal(pb_copy.pixel(1, 3), true)
end
def test_12
pb = RBA::BitmapBuffer::new(10, 20)
pb.fill(false)
pb.set_pixel(2, 3, true)
if pb.respond_to?(:to_qimage)
assert_equal(pb.to_qimage.pixel(0, 0), 0xff000000)
assert_equal(pb.to_qimage.pixel(2, 3), 0xffffffff)
pb_copy = RBA::BitmapBuffer::from_qimage(pb.to_qimage)
assert_equal(compare(pb, pb_copy), true)
end
png = nil
begin
png = pb.to_png_data
rescue => ex
# No PNG support
end
if png
assert_equal(png.size > 20 && png.size < 200, true) # some range because implementations may differ
pb_copy = RBA::BitmapBuffer.from_png_data(png)
assert_equal(compare(pb, pb_copy), true)
tmp = File::join($ut_testtmp, "tmp.png")
pb.write_png(tmp)
pb_copy = RBA::BitmapBuffer.read_png(tmp)
assert_equal(compare(pb, pb_copy), true)
end
end
end
load("test_epilogue.rb")