mirror of https://github.com/KLayout/klayout.git
Added Image constructor from PixelBuffer and QImage
This commit is contained in:
parent
abf2970438
commit
aa4eeebfbb
|
|
@ -30,6 +30,10 @@
|
|||
#include "dbTilingProcessor.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
# include <QImage>
|
||||
#endif
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
|
|
@ -437,27 +441,22 @@ static ImageRef *new_image ()
|
|||
return new ImageRef ();
|
||||
}
|
||||
|
||||
static ImageRef *new_image_f (const std::string &filename)
|
||||
{
|
||||
return new ImageRef (img::Object (filename, db::DCplxTrans ()));
|
||||
}
|
||||
|
||||
static ImageRef *new_image_ft (const std::string &filename, const db::DCplxTrans &trans)
|
||||
{
|
||||
return new ImageRef (img::Object (filename, trans));
|
||||
}
|
||||
|
||||
/*
|
||||
static ImageRef *new_image_whc (size_t w, size_t h, bool color)
|
||||
static ImageRef *new_image_pbt (const tl::PixelBuffer &pixel_buffer, const db::DCplxTrans &trans)
|
||||
{
|
||||
return new ImageRef (img::Object (w, h, db::DCplxTrans (), color));
|
||||
return new ImageRef (img::Object (pixel_buffer, trans));
|
||||
}
|
||||
|
||||
static ImageRef *new_image_whtc (size_t w, size_t h, const db::DCplxTrans &trans, bool color)
|
||||
#if HAVE_QT
|
||||
static ImageRef *new_image_qit (const QImage &image, const db::DCplxTrans &trans)
|
||||
{
|
||||
return new ImageRef (img::Object (w, h, trans, color));
|
||||
return new ImageRef (img::Object (image, trans));
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
static ImageRef *new_image_whd (size_t w, size_t h, const std::vector<double> &data)
|
||||
{
|
||||
|
|
@ -576,17 +575,8 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
|
|||
"This will create an empty image without data and no particular pixel width or related.\n"
|
||||
"Use the \\read_file or \\set_data methods to set image properties and pixel values.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &gsi::new_image_f, gsi::arg ("filename"),
|
||||
"@brief Constructor from a image file \n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a file (which can have any format supported by Qt) and \n"
|
||||
"a unit transformation. The image will originally be put to position 0,0 (lower left corner) and each pixel\n"
|
||||
"will have a size of 1 (micron). \n"
|
||||
"\n"
|
||||
"@param filename The path to the image file to load.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &gsi::new_image_ft, gsi::arg ("filename"), gsi::arg ("trans"),
|
||||
"@brief Constructor from a image file \n"
|
||||
gsi::constructor ("new", &gsi::new_image_ft, gsi::arg ("filename"), gsi::arg ("trans", db::DCplxTrans (), "unity"),
|
||||
"@brief Constructor from a image file\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a file (which can have any format supported by Qt) and \n"
|
||||
"a transformation. The image will originally be put to position 0,0 (lower left corner) and each pixel\n"
|
||||
|
|
@ -595,6 +585,31 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
|
|||
"@param filename The path to the image file to load.\n"
|
||||
"@param trans The transformation to apply to the image when displaying it.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &gsi::new_image_pbt, gsi::arg ("pixels"), gsi::arg ("trans", db::DCplxTrans (), "unity"),
|
||||
"@brief Constructor from a image pixel buffer\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a pixel buffer object. This object holds RGB or mono image data similar to "
|
||||
"QImage, except it is available also when Qt is not available (e.g. inside the Python module).\n"
|
||||
"\n"
|
||||
"The image will originally be put to position 0,0 (lower left corner) and each pixel\n"
|
||||
"will have a size of 1. The transformation describes how to transform this image into micron space.\n"
|
||||
"\n"
|
||||
"@param filename The path to the image file to load.\n"
|
||||
"@param trans The transformation to apply to the image when displaying it.\n"
|
||||
) +
|
||||
#if defined(HAVE_QT)
|
||||
gsi::constructor ("new", &gsi::new_image_qit, gsi::arg ("image"), gsi::arg ("trans", db::DCplxTrans (), "unity"),
|
||||
"@brief Constructor from a image pixel buffer\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a pixel QImage object and uses RGB or mono image data to generate the image.\n"
|
||||
"\n"
|
||||
"The image will originally be put to position 0,0 (lower left corner) and each pixel\n"
|
||||
"will have a size of 1. The transformation describes how to transform this image into micron space.\n"
|
||||
"\n"
|
||||
"@param filename The path to the image file to load.\n"
|
||||
"@param trans The transformation to apply to the image when displaying it.\n"
|
||||
) +
|
||||
#endif
|
||||
gsi::constructor ("new", &gsi::new_image_whd, gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("data"),
|
||||
"@brief Constructor for a monochrome image with the given pixel values\n"
|
||||
"\n"
|
||||
|
|
@ -624,39 +639,6 @@ gsi::Class<ImageRef> decl_Image (decl_BasicImage, "lay", "Image",
|
|||
"@param trans The transformation from pixel space to micron space\n"
|
||||
"@param d The data (see method description)\n"
|
||||
) +
|
||||
/* HINT: these declarations cannot be used currently since any array is case to the boolean color parameter
|
||||
gsi::constructor ("new", &img::new_image_whc, gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("color"),
|
||||
"@brief Constructor for monochrome or color images with zero pixel values\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a data set describing one monochrome channel\n"
|
||||
"or three color channels.\n"
|
||||
"Each channel consists of an array of x*y values where the first \"x\" values describe the first (lowest!) row\n"
|
||||
"and so on. Note, that the rows are oriented in the mathematical sense (first one is the lowest) contrary to \n"
|
||||
"the common convention for image data.\n"
|
||||
"The data fields can be accessed with the \"data\", \"set_data\", \"pixel\" or \"set_pixel\" methods.\n"
|
||||
"Initially the pixel width and height will be 1 micron and the data range will be 0 to 1.0 (black to white level). \n"
|
||||
"\n"
|
||||
"@param w The width of the image\n"
|
||||
"@param h The height of the image\n"
|
||||
"@param color True to create a color image.\n"
|
||||
) +
|
||||
gsi::constructor ("new", &img::new_image_whtc, gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("trans"), gsi::arg ("color"),
|
||||
"@brief Constructor for monochrome or color images with zero pixel values\n"
|
||||
"\n"
|
||||
"This constructor creates an image object from a data set describing one monochrome channel\n"
|
||||
"or three color channels.\n"
|
||||
"Each channel consists of an array of x*y values where the first \"x\" values describe the first (lowest!) row\n"
|
||||
"and so on. Note, that the rows are oriented in the mathematical sense (first one is the lowest) contrary to \n"
|
||||
"the common convention for image data.\n"
|
||||
"The data fields can be accessed with the \"data\", \"set_data\", \"pixel\" or \"set_pixel\" methods.\n"
|
||||
"Initially the pixel width and height will be 1 micron and the data range will be 0 to 1.0 (black to white level). \n"
|
||||
"\n"
|
||||
"@param w The width of the image\n"
|
||||
"@param h The height of the image\n"
|
||||
"@param trans The transformation to apply to the image when displaying it\n"
|
||||
"@param color True to create a color image.\n"
|
||||
) +
|
||||
*/
|
||||
gsi::constructor ("new", &gsi::new_image_whrgb, gsi::arg ("w"), gsi::arg ("h"), gsi::arg ("red"), gsi::arg ("green"), gsi::arg ("blue"),
|
||||
"@brief Constructor for a color image with the given pixel values\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -851,6 +851,30 @@ Object::Object (const std::string &filename, const db::DCplxTrans &trans)
|
|||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
Object::Object (const tl::PixelBuffer &pixel_buffer, const db::DCplxTrans &trans)
|
||||
: m_filename ("<object>"), m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = 0;
|
||||
create_from_pixel_buffer (pixel_buffer);
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
Object::Object (const QImage &qimage, const db::DCplxTrans &trans)
|
||||
: m_filename ("<object>"), m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = 0;
|
||||
create_from_qimage (qimage);
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Object::Object (size_t w, size_t h, const db::Matrix3d &trans, bool color, bool byte_data)
|
||||
: m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
|
|
@ -934,6 +958,31 @@ Object::Object (const std::string &filename, const db::Matrix3d &trans)
|
|||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
Object::Object (const tl::PixelBuffer &pixel_buffer, const db::Matrix3d &trans)
|
||||
: m_filename ("<object>"), m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = 0;
|
||||
create_from_pixel_buffer (pixel_buffer);
|
||||
read_file ();
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
Object::Object (const QImage &qimage, const db::Matrix3d &trans)
|
||||
: m_filename ("<object>"), m_trans (trans), m_id (make_id ()), m_min_value (0.0), m_max_value (1.0), m_min_value_set (false), m_max_value_set (false), m_visible (true), m_z_position (0)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = 0;
|
||||
create_from_qimage (qimage);
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Object::Object (const img::Object &d)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
|
|
@ -1566,65 +1615,7 @@ Object::read_file ()
|
|||
#if defined(HAVE_QT)
|
||||
|
||||
QImage qimage (tl::to_qstring (m_filename));
|
||||
|
||||
if (! qimage.isNull ()) {
|
||||
|
||||
if (! m_min_value_set) {
|
||||
m_min_value = 0.0;
|
||||
}
|
||||
|
||||
if (! m_max_value_set) {
|
||||
m_max_value = 255.0;
|
||||
}
|
||||
|
||||
m_min_value_set = true;
|
||||
m_max_value_set = true;
|
||||
|
||||
size_t w = qimage.width (), h = qimage.height ();
|
||||
|
||||
mp_data = new DataHeader (w, h, ! qimage.isGrayscale (), true);
|
||||
mp_data->add_ref ();
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
if (is_color ()) {
|
||||
|
||||
unsigned char *red = mp_data->byte_data (0);
|
||||
unsigned char *green = mp_data->byte_data (1);
|
||||
unsigned char *blue = mp_data->byte_data (2);
|
||||
unsigned char *msk = qimage.hasAlphaChannel () ? mp_data->set_mask () : 0;
|
||||
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x) {
|
||||
QRgb rgb = qimage.pixel (QPoint (int (x), int (h - y - 1)));
|
||||
red[i] = qRed (rgb);
|
||||
green[i] = qGreen (rgb);
|
||||
blue[i] = qBlue (rgb);
|
||||
if (msk) {
|
||||
msk[i] = qAlpha (rgb) > 128;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
unsigned char *d = mp_data->byte_data ();
|
||||
unsigned char *msk = qimage.hasAlphaChannel () ? mp_data->set_mask () : 0;
|
||||
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x) {
|
||||
QRgb rgb = qimage.pixel (QPoint (int (x), int (h - y - 1)));
|
||||
*d++ = qGreen (rgb);
|
||||
if (msk) {
|
||||
msk[i] = qAlpha (rgb) > 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
create_from_qimage (qimage);
|
||||
|
||||
#elif defined(HAVE_PNG)
|
||||
|
||||
|
|
@ -1635,6 +1626,82 @@ Object::read_file ()
|
|||
img = tl::PixelBuffer::read_png (stream);
|
||||
}
|
||||
|
||||
create_from_pixel_buffer (img);
|
||||
|
||||
#else
|
||||
throw tl::Exception ("No PNG support compiled in - cannot load PNG files");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Object::create_from_qimage (const QImage &qimage)
|
||||
{
|
||||
if (qimage.isNull ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! m_min_value_set) {
|
||||
m_min_value = 0.0;
|
||||
}
|
||||
|
||||
if (! m_max_value_set) {
|
||||
m_max_value = 255.0;
|
||||
}
|
||||
|
||||
m_min_value_set = true;
|
||||
m_max_value_set = true;
|
||||
|
||||
size_t w = qimage.width (), h = qimage.height ();
|
||||
|
||||
mp_data = new DataHeader (w, h, ! qimage.isGrayscale (), true);
|
||||
mp_data->add_ref ();
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
if (is_color ()) {
|
||||
|
||||
unsigned char *red = mp_data->byte_data (0);
|
||||
unsigned char *green = mp_data->byte_data (1);
|
||||
unsigned char *blue = mp_data->byte_data (2);
|
||||
unsigned char *msk = qimage.hasAlphaChannel () ? mp_data->set_mask () : 0;
|
||||
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x) {
|
||||
QRgb rgb = qimage.pixel (QPoint (int (x), int (h - y - 1)));
|
||||
red[i] = qRed (rgb);
|
||||
green[i] = qGreen (rgb);
|
||||
blue[i] = qBlue (rgb);
|
||||
if (msk) {
|
||||
msk[i] = qAlpha (rgb) > 128;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
unsigned char *d = mp_data->byte_data ();
|
||||
unsigned char *msk = qimage.hasAlphaChannel () ? mp_data->set_mask () : 0;
|
||||
|
||||
for (size_t y = 0; y < h; ++y) {
|
||||
for (size_t x = 0; x < w; ++x) {
|
||||
QRgb rgb = qimage.pixel (QPoint (int (x), int (h - y - 1)));
|
||||
*d++ = qGreen (rgb);
|
||||
if (msk) {
|
||||
msk[i] = qAlpha (rgb) > 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Object::create_from_pixel_buffer (const tl::PixelBuffer &img)
|
||||
{
|
||||
bool is_color = false;
|
||||
for (unsigned int i = 0; i < img.height () && ! is_color; ++i) {
|
||||
const tl::color_t *d = img.scan_line (i);
|
||||
|
|
@ -1700,10 +1767,6 @@ Object::read_file ()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
throw tl::Exception ("No PNG support compiled in - cannot load PNG files");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef HDR_imgObject
|
||||
#define HDR_imgObject
|
||||
|
||||
|
|
@ -34,10 +33,15 @@
|
|||
#include "dbPolygon.h"
|
||||
#include "tlDataMapping.h"
|
||||
#include "tlColor.h"
|
||||
#include "tlPixelBuffer.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
class QImage;
|
||||
#endif
|
||||
|
||||
namespace img {
|
||||
|
||||
class DataHeader;
|
||||
|
|
@ -293,6 +297,26 @@ public:
|
|||
*/
|
||||
Object (const std::string &filename, const db::DCplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a PixelBuffer object
|
||||
*
|
||||
* This constructor creates an image object from a PixelBuffer object.
|
||||
* The image will originally be put to position 0, 0 (lower left corner) and each pixel
|
||||
* will have a size of 1. The transformation describes how to transform this image into micron space.
|
||||
*/
|
||||
Object (const tl::PixelBuffer &pixel_buffer, const db::DCplxTrans &trans);
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Constructor from a QImage object
|
||||
*
|
||||
* This constructor creates an image object from a QImage object.
|
||||
* The image will originally be put to position 0, 0 (lower left corner) and each pixel
|
||||
* will have a size of 1. The transformation describes how to transform this image into micron space.
|
||||
*/
|
||||
Object (const QImage &image, const db::DCplxTrans &trans);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Constructor for monochrome or color images with zero pixel values
|
||||
*
|
||||
|
|
@ -418,6 +442,26 @@ public:
|
|||
*/
|
||||
Object (const std::string &filename, const db::Matrix3d &trans);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a PixelBuffer object
|
||||
*
|
||||
* This constructor creates an image object from a PixelBuffer object.
|
||||
* The image will originally be put to position 0, 0 (lower left corner) and each pixel
|
||||
* will have a size of 1. The transformation describes how to transform this image into micron space.
|
||||
*/
|
||||
Object (const tl::PixelBuffer &pixel_buffer, const db::Matrix3d &trans);
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Constructor from a QImage object
|
||||
*
|
||||
* This constructor creates an image object from a QImage object.
|
||||
* The image will originally be put to position 0, 0 (lower left corner) and each pixel
|
||||
* will have a size of 1. The transformation describes how to transform this image into micron space.
|
||||
*/
|
||||
Object (const QImage &image, const db::Matrix3d &trans);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
|
|
@ -984,6 +1028,8 @@ private:
|
|||
void validate_pixel_data () const;
|
||||
void allocate (bool color);
|
||||
void read_file ();
|
||||
void create_from_qimage (const QImage &qimage);
|
||||
void create_from_pixel_buffer (const tl::PixelBuffer &img);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -415,6 +415,38 @@ class IMG_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# Construction from PixelBuffer
|
||||
def test_6
|
||||
|
||||
fn = ENV["TESTSRC"] + "/testdata/img/gs.png"
|
||||
pb = RBA::PixelBuffer::read_png(fn)
|
||||
|
||||
image = RBA::Image.new(pb)
|
||||
assert_equal(image.trans.to_s, "r0 *1 -513.5,-349")
|
||||
|
||||
assert_equal(image.width, 1027)
|
||||
assert_equal(image.height, 698)
|
||||
|
||||
end
|
||||
|
||||
# Construction from QImage
|
||||
def test_7
|
||||
|
||||
if RBA.constants.find { |x| x == :QImage }
|
||||
|
||||
fn = ENV["TESTSRC"] + "/testdata/img/gs.png"
|
||||
qimage = RBA::QImage::new(fn)
|
||||
|
||||
image = RBA::Image.new(qimage)
|
||||
assert_equal(image.trans.to_s, "r0 *1 -513.5,-349")
|
||||
|
||||
assert_equal(image.width, 1027)
|
||||
assert_equal(image.height, 698)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue