mirror of https://github.com/KLayout/klayout.git
GSI binding for PixelBuffer and tests
This commit is contained in:
parent
0798c4de51
commit
32813b80f2
|
|
@ -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."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -212,6 +212,10 @@ PixelBuffer::swap (PixelBuffer &other)
|
|||
void
|
||||
PixelBuffer::fill (lay::color_t c)
|
||||
{
|
||||
if (! transparent ()) {
|
||||
c |= 0xff000000; // ensures that alpha is properly set
|
||||
}
|
||||
|
||||
color_t *d = data ();
|
||||
for (unsigned int i = 0; i < m_height; ++i) {
|
||||
for (unsigned int j = 0; j < m_width; ++j) {
|
||||
|
|
@ -260,6 +264,17 @@ PixelBuffer::to_image_copy () const
|
|||
memcpy (img.bits (), data (), img.sizeInBytes ());
|
||||
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
|
||||
|
||||
void
|
||||
|
|
@ -376,7 +391,7 @@ PixelBuffer::read_png (tl::InputStream &input)
|
|||
}
|
||||
|
||||
void
|
||||
PixelBuffer::write_png (tl::OutputStream &output)
|
||||
PixelBuffer::write_png (tl::OutputStream &output) const
|
||||
{
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
|
|
@ -559,6 +574,17 @@ BitmapBuffer::to_image_copy () const
|
|||
memcpy (img.bits (), data (), img.sizeInBytes ());
|
||||
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
|
||||
|
||||
#if defined(HAVE_PNG)
|
||||
|
|
@ -610,7 +636,7 @@ BitmapBuffer::read_png (tl::InputStream &input)
|
|||
}
|
||||
|
||||
void
|
||||
BitmapBuffer::write_png (tl::OutputStream &output)
|
||||
BitmapBuffer::write_png (tl::OutputStream &output) const
|
||||
{
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
|
|
|
|||
|
|
@ -204,6 +204,11 @@ public:
|
|||
* PixelBuffer.
|
||||
*/
|
||||
QImage to_image_copy () const;
|
||||
|
||||
/**
|
||||
* @brief Creates a pixel buffer from a QImage object
|
||||
*/
|
||||
static PixelBuffer from_image (const QImage &img);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PNG)
|
||||
|
|
@ -217,7 +222,7 @@ public:
|
|||
* @brief Writes the PixelBuffer object to a PNG file
|
||||
* Throws a PixelBufferWriteError if an error occurs.
|
||||
*/
|
||||
void write_png (tl::OutputStream &output);
|
||||
void write_png (tl::OutputStream &output) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -414,6 +419,11 @@ public:
|
|||
* BitmapBuffer.
|
||||
*/
|
||||
QImage to_image_copy () const;
|
||||
|
||||
/**
|
||||
* @brief Creates a pixel buffer from a QImage object
|
||||
*/
|
||||
static BitmapBuffer from_image (const QImage &img);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_PNG)
|
||||
|
|
@ -427,7 +437,7 @@ public:
|
|||
* @brief Writes the PixelBuffer object to a PNG file
|
||||
* Throws a PixelBufferWriteError if an error occurs.
|
||||
*/
|
||||
void write_png (tl::OutputStream &output);
|
||||
void write_png (tl::OutputStream &output) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -242,6 +242,7 @@ SOURCES += \
|
|||
gsiDeclLayLayoutView.cc \
|
||||
gsiDeclLayMarker.cc \
|
||||
gsiDeclLayPlugin.cc \
|
||||
gsiDeclLayPixelBuffer.cc \
|
||||
layAnnotationShapes.cc \
|
||||
layBitmap.cc \
|
||||
layBitmapRenderer.cc \
|
||||
|
|
|
|||
|
|
@ -153,33 +153,33 @@ TEST(1)
|
|||
EXPECT_EQ (compare_images (img, img2), false);
|
||||
|
||||
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);
|
||||
EXPECT_EQ (compare_images (img, img2), false);
|
||||
EXPECT_EQ (img.width (), 10);
|
||||
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);
|
||||
EXPECT_EQ (compare_images (img, img3), true);
|
||||
EXPECT_EQ (img3.width (), 10);
|
||||
EXPECT_EQ (img3.height (), 16);
|
||||
EXPECT_EQ (img3.scan_line (5)[8], 0x010203);
|
||||
EXPECT_EQ (img3.scan_line (5)[8], 0xff010203);
|
||||
|
||||
img.fill (0x102030);
|
||||
EXPECT_EQ (compare_images (img, img3), false);
|
||||
EXPECT_EQ (img3.width (), 10);
|
||||
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.height (), 16);
|
||||
EXPECT_EQ (img.scan_line (5)[8], 0x102030);
|
||||
EXPECT_EQ (img.scan_line (5)[8], 0xff102030);
|
||||
|
||||
lay::PixelBuffer img4 (std::move (img));
|
||||
EXPECT_EQ (img4.width (), 10);
|
||||
EXPECT_EQ (img4.height (), 16);
|
||||
EXPECT_EQ (img4.scan_line (5)[8], 0x102030);
|
||||
EXPECT_EQ (img4.scan_line (5)[8], 0xff102030);
|
||||
|
||||
// other constructors
|
||||
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);
|
||||
|
||||
lay::PixelBuffer img_returned = lay::PixelBuffer::from_image (qimg);
|
||||
EXPECT_EQ (compare_images (img, img_returned), true);
|
||||
|
||||
lay::PixelBuffer img_saved (img);
|
||||
img.scan_line (52) [42] = 0xff000000;
|
||||
|
||||
|
|
@ -529,6 +532,9 @@ TEST(12)
|
|||
|
||||
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 ();
|
||||
img.fill (false);
|
||||
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ RUBYTEST (layLayoutView, "layLayoutView.rb")
|
|||
RUBYTEST (layMarkers, "layMarkers.rb")
|
||||
RUBYTEST (layMacro, "layMacro.rb")
|
||||
RUBYTEST (layMenuTest, "layMenuTest.rb")
|
||||
RUBYTEST (layPixelBuffer, "layPixelBuffer.rb")
|
||||
RUBYTEST (laySession, "laySession.rb")
|
||||
RUBYTEST (layTechnologies, "layTechnologies.rb")
|
||||
RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb")
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
|
|
@ -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")
|
||||
Loading…
Reference in New Issue