mirror of https://github.com/KLayout/klayout.git
1299 lines
50 KiB
C++
1299 lines
50 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2017 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 "gsiSignals.h"
|
|
#include "imgObject.h"
|
|
#include "imgService.h"
|
|
#include "dbTilingProcessor.h"
|
|
#include "layLayoutView.h"
|
|
|
|
namespace gsi
|
|
{
|
|
|
|
static img::DataMapping *new_data_mapping ()
|
|
{
|
|
return new img::DataMapping ();
|
|
}
|
|
|
|
static void clear_colormap (img::DataMapping *dm)
|
|
{
|
|
dm->false_color_nodes.clear ();
|
|
}
|
|
|
|
static void add_colormap (img::DataMapping *dm, double value, lay::color_t color)
|
|
{
|
|
dm->false_color_nodes.push_back (std::make_pair (value, QColor (color)));
|
|
}
|
|
|
|
static size_t num_colormap_entries (const img::DataMapping *dm)
|
|
{
|
|
return dm->false_color_nodes.size ();
|
|
}
|
|
|
|
static lay::color_t colormap_color (const img::DataMapping *dm, size_t i)
|
|
{
|
|
if (i < dm->false_color_nodes.size ()) {
|
|
return dm->false_color_nodes [i].second.rgb ();
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static double colormap_value (const img::DataMapping *dm, size_t i)
|
|
{
|
|
if (i < dm->false_color_nodes.size ()) {
|
|
return dm->false_color_nodes [i].first;
|
|
} else {
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
static void set_brightness (img::DataMapping *dm, double b)
|
|
{
|
|
dm->brightness = b;
|
|
}
|
|
|
|
static double brightness (const img::DataMapping *dm)
|
|
{
|
|
return dm->brightness;
|
|
}
|
|
|
|
static void set_contrast (img::DataMapping *dm, double c)
|
|
{
|
|
dm->contrast = c;
|
|
}
|
|
|
|
static double contrast (const img::DataMapping *dm)
|
|
{
|
|
return dm->contrast;
|
|
}
|
|
|
|
static void set_gamma (img::DataMapping *dm, double g)
|
|
{
|
|
dm->gamma = g;
|
|
}
|
|
|
|
static double gamma (const img::DataMapping *dm)
|
|
{
|
|
return dm->gamma;
|
|
}
|
|
|
|
static void set_red_gain (img::DataMapping *dm, double g)
|
|
{
|
|
dm->red_gain = g;
|
|
}
|
|
|
|
static double red_gain (const img::DataMapping *dm)
|
|
{
|
|
return dm->red_gain;
|
|
}
|
|
|
|
static void set_green_gain (img::DataMapping *dm, double g)
|
|
{
|
|
dm->green_gain = g;
|
|
}
|
|
|
|
static double green_gain (const img::DataMapping *dm)
|
|
{
|
|
return dm->green_gain;
|
|
}
|
|
|
|
static void set_blue_gain (img::DataMapping *dm, double g)
|
|
{
|
|
dm->blue_gain = g;
|
|
}
|
|
|
|
static double blue_gain (const img::DataMapping *dm)
|
|
{
|
|
return dm->blue_gain;
|
|
}
|
|
|
|
gsi::Class<img::DataMapping> decl_ImageDataMapping ("ImageDataMapping",
|
|
gsi::constructor ("new", &gsi::new_data_mapping,
|
|
"@brief Create a new data mapping object with default settings"
|
|
) +
|
|
gsi::method_ext ("clear_colormap", &gsi::clear_colormap,
|
|
"@brief The the color map of this data mapping object."
|
|
) +
|
|
gsi::method_ext ("add_colormap_entry", &gsi::add_colormap,
|
|
"@brief Add a colormap entry for this data mapping object.\n"
|
|
"@args value, color\n"
|
|
"@param value The value at which the given color should be applied.\n"
|
|
"@param color The color to apply (a 32 bit RGB value).\n"
|
|
"\n"
|
|
"This settings establishes a color mapping for a given value in the monochrome channel. "
|
|
"The color must be given as a 32 bit integer, where the lowest order byte describes the "
|
|
"blue component (0 to 255), the second byte the green component and the third byte the "
|
|
"red component, i.e. 0xff0000 is red and 0x0000ff is blue. "
|
|
) +
|
|
gsi::method_ext ("num_colormap_entries", &gsi::num_colormap_entries,
|
|
"@brief Returns the current number of color map entries.\n"
|
|
"@return The number of entries.\n"
|
|
) +
|
|
gsi::method_ext ("colormap_color", &gsi::colormap_color,
|
|
"@brief Returns the color for a given color map entry.\n"
|
|
"@args n\n"
|
|
"@param n The index of the entry (0..\\num_colormap_entries-1)\n"
|
|
"@return The color (see \\add_colormap_entry for a description).\n"
|
|
) +
|
|
gsi::method_ext ("colormap_value", &gsi::colormap_value,
|
|
"@brief Returns the vlue for a given color map entry.\n"
|
|
"@args n\n"
|
|
"@param n The index of the entry (0..\\num_colormap_entries-1)\n"
|
|
"@return The value (see \\add_colormap_entry for a description).\n"
|
|
) +
|
|
gsi::method_ext ("brightness=", &gsi::set_brightness,
|
|
"@brief Set the brightness\n"
|
|
"@args brightness\n"
|
|
"See \\brightness for a description of this property.\n"
|
|
) +
|
|
gsi::method_ext ("brightness", &gsi::brightness,
|
|
"@brief The brightness value\n"
|
|
"\n"
|
|
"The brightness is a double value between roughly -1.0 and 1.0. \n"
|
|
"Neutral (original) brightness is 0.0.\n"
|
|
) +
|
|
gsi::method_ext ("contrast=", &gsi::set_contrast,
|
|
"@brief Set the contrast\n"
|
|
"@args contrast\n"
|
|
"See \\contrast for a description of this property.\n"
|
|
) +
|
|
gsi::method_ext ("contrast", &gsi::contrast,
|
|
"@brief The contrast value\n"
|
|
"\n"
|
|
"The contrast is a double value between roughly -1.0 and 1.0. \n"
|
|
"Neutral (original) contrast is 0.0.\n"
|
|
) +
|
|
gsi::method_ext ("gamma=", &gsi::set_gamma,
|
|
"@brief Set the gamma\n"
|
|
"@args gamma\n"
|
|
"See \\gamma for a description of this property.\n"
|
|
) +
|
|
gsi::method_ext ("gamma", &gsi::gamma,
|
|
"@brief The gamma value\n"
|
|
"\n"
|
|
"The gamma value allows to adjust for non-linearities in the display chain and to enhance contrast.\n"
|
|
"A value for linear intensity reproduction on the screen is roughly 0.5. The exact value depends on the \n"
|
|
"monitor calibration. Values below 1.0 give a \"softer\" appearance while values above 1.0 give a \"harder\" appearance.\n"
|
|
) +
|
|
gsi::method_ext ("red_gain=", &gsi::set_red_gain,
|
|
"@brief Set the red_gain\n"
|
|
"@args red_gain\n"
|
|
"See \\red_gain for a description of this property.\n"
|
|
) +
|
|
gsi::method_ext ("red_gain", &gsi::red_gain,
|
|
"@brief The red channel gain\n"
|
|
"\n"
|
|
"This value is the multiplier by which the red channel is scaled after applying \n"
|
|
"false color transformation and contrast/brightness/gamma.\n"
|
|
"\n"
|
|
"1.0 is a neutral value. The gain should be >=0.0.\n"
|
|
) +
|
|
gsi::method_ext ("green_gain=", &gsi::set_green_gain,
|
|
"@brief Set the green_gain\n"
|
|
"@args green_gain\n"
|
|
"See \\green_gain for a description of this property.\n"
|
|
) +
|
|
gsi::method_ext ("green_gain", &gsi::green_gain,
|
|
"@brief The green channel gain\n"
|
|
"\n"
|
|
"This value is the multiplier by which the green channel is scaled after applying \n"
|
|
"false color transformation and contrast/brightness/gamma.\n"
|
|
"\n"
|
|
"1.0 is a neutral value. The gain should be >=0.0.\n"
|
|
) +
|
|
gsi::method_ext ("blue_gain=", &gsi::set_blue_gain,
|
|
"@brief Set the blue_gain\n"
|
|
"@args blue_gain\n"
|
|
"See \\blue_gain for a description of this property.\n"
|
|
) +
|
|
gsi::method_ext ("blue_gain", &gsi::blue_gain,
|
|
"@brief The blue channel gain\n"
|
|
"\n"
|
|
"This value is the multiplier by which the blue channel is scaled after applying \n"
|
|
"false color transformation and contrast/brightness/gamma.\n"
|
|
"\n"
|
|
"1.0 is a neutral value. The gain should be >=0.0.\n"
|
|
),
|
|
"@brief A structure describing the data mapping of an image object\n"
|
|
"\n"
|
|
"Data mapping is the process of transforming the data into RGB pixel values.\n"
|
|
"This implementation provides four adjustment steps: first, in the case of monochrome\n"
|
|
"data, the data is converted to a RGB triplet using the color map. The default color map\n"
|
|
"will copy the value to all channels rendering a gray scale. After having normalized the data \n"
|
|
"to 0..1 cooresponding to the min_value and max_value settings of the image, a color channel-independent\n"
|
|
"brightness and contrast adjustment is applied. Then, a per-channel multiplier (red_gain, green_gain,\n"
|
|
"blue_gain) is applied. Finally, the gamma function is applied and the result converted into a 0..255 \n"
|
|
"pixel value range and clipped.\n"
|
|
);
|
|
|
|
class ImageRef;
|
|
|
|
static void replace_image (lay::LayoutView *view, size_t id, ImageRef &new_obj);
|
|
static void erase_image (lay::LayoutView *view, size_t id);
|
|
|
|
/**
|
|
* @brief An extension of the img::Object that provides "live" updates of the view
|
|
*/
|
|
class ImageRef
|
|
: public img::Object
|
|
{
|
|
public:
|
|
ImageRef ()
|
|
: img::Object (), dm_update_view (this, &ImageRef::do_update_view)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ImageRef (const img::Object &img)
|
|
: img::Object (img), dm_update_view (this, &ImageRef::do_update_view)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ImageRef (const img::Object &other, lay::LayoutView *view)
|
|
: img::Object (other), mp_view (view), dm_update_view (this, &ImageRef::do_update_view)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ImageRef (const ImageRef &other)
|
|
: img::Object (other), mp_view (other.mp_view), dm_update_view (this, &ImageRef::do_update_view)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ImageRef &operator= (const ImageRef &other)
|
|
{
|
|
// NOTE: assignment changes the properties, not the reference
|
|
if (this != &other) {
|
|
img::Object::operator= (other);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool operator== (const ImageRef &other) const
|
|
{
|
|
return img::Object::operator== (other);
|
|
}
|
|
|
|
bool operator!= (const ImageRef &other) const
|
|
{
|
|
return img::Object::operator!= (other);
|
|
}
|
|
|
|
void detach ()
|
|
{
|
|
mp_view.reset (0);
|
|
}
|
|
|
|
bool is_valid () const
|
|
{
|
|
return mp_view;
|
|
}
|
|
|
|
void erase ()
|
|
{
|
|
if (mp_view) {
|
|
erase_image (mp_view.get (), id ());
|
|
detach ();
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
ImageRef transformed (const T &t) const
|
|
{
|
|
return ImageRef (img::Object::transformed<T> (t), const_cast<lay::LayoutView *> (mp_view.get ()));
|
|
}
|
|
|
|
void set_view (lay::LayoutView *view)
|
|
{
|
|
mp_view.reset (view);
|
|
}
|
|
|
|
void update_view ()
|
|
{
|
|
dm_update_view.cancel ();
|
|
do_update_view ();
|
|
}
|
|
|
|
protected:
|
|
void property_changed ()
|
|
{
|
|
// NOTE: property changes are not reflected immediately since they may be
|
|
// inefficient. Hence we delay their execution.
|
|
dm_update_view ();
|
|
}
|
|
|
|
void do_update_view ()
|
|
{
|
|
if (mp_view) {
|
|
replace_image (mp_view.get (), id (), *this);
|
|
}
|
|
}
|
|
|
|
private:
|
|
tl::weak_ptr<lay::LayoutView> mp_view;
|
|
tl::DeferredMethod<ImageRef> dm_update_view;
|
|
};
|
|
|
|
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)
|
|
{
|
|
return new ImageRef (img::Object (w, h, db::DCplxTrans (), color));
|
|
}
|
|
|
|
static ImageRef *new_image_whtc (size_t w, size_t h, const db::DCplxTrans &trans, bool color)
|
|
{
|
|
return new ImageRef (img::Object (w, h, trans, color));
|
|
}
|
|
*/
|
|
|
|
static ImageRef *new_image_whd (size_t w, size_t h, const std::vector<double> &data)
|
|
{
|
|
return new ImageRef (img::Object (w, h, db::DCplxTrans (), data));
|
|
}
|
|
|
|
static ImageRef *new_image_whtd (size_t w, size_t h, const db::DCplxTrans &trans, const std::vector<double> &data)
|
|
{
|
|
return new ImageRef (img::Object (w, h, trans * db::DCplxTrans (db::DVector (0.5 * w, 0.5 * h)), data));
|
|
}
|
|
|
|
static ImageRef *new_image_whrgb (size_t w, size_t h, const std::vector<double> &red, const std::vector<double> &green, const std::vector<double> &blue)
|
|
{
|
|
return new ImageRef (img::Object (w, h, db::DCplxTrans (), red, green, blue));
|
|
}
|
|
|
|
static ImageRef *new_image_whtrgb (size_t w, size_t h, const db::DCplxTrans &trans, const std::vector<double> &red, const std::vector<double> &green, const std::vector<double> &blue)
|
|
{
|
|
return new ImageRef (img::Object (w, h, trans * db::DCplxTrans (db::DVector (0.5 * w, 0.5 * h)), red, green, blue));
|
|
}
|
|
|
|
static double img_get_pixel_width (const ImageRef *obj)
|
|
{
|
|
return obj->matrix ().mag_x ();
|
|
}
|
|
|
|
static void img_set_pixel_width (ImageRef *obj, double w)
|
|
{
|
|
db::Matrix3d m = obj->matrix ();
|
|
db::Matrix3d n = db::Matrix3d::perspective (m.perspective_tilt_x (1.0), m.perspective_tilt_y (1.0), 1.0) * db::Matrix3d::disp (m.disp ()) * db::Matrix3d::rotation (m.angle ()) * db::Matrix3d::shear (m.shear_angle ()) * db::Matrix3d::mag (w, m.mag_y ()) * db::Matrix3d::mirror (m.is_mirror ());
|
|
obj->set_matrix (n);
|
|
}
|
|
|
|
static double img_get_pixel_height (const ImageRef *obj)
|
|
{
|
|
return obj->matrix ().mag_y ();
|
|
}
|
|
|
|
static void img_set_pixel_height (ImageRef*obj, double h)
|
|
{
|
|
db::Matrix3d m = obj->matrix ();
|
|
db::Matrix3d n = db::Matrix3d::perspective (m.perspective_tilt_x (1.0), m.perspective_tilt_y (1.0), 1.0) * db::Matrix3d::disp (m.disp ()) * db::Matrix3d::rotation (m.angle ()) * db::Matrix3d::shear (m.shear_angle ()) * db::Matrix3d::mag (m.mag_x (), h) * db::Matrix3d::mirror (m.is_mirror ());
|
|
obj->set_matrix (n);
|
|
}
|
|
|
|
static db::DCplxTrans img_get_trans (const ImageRef *obj)
|
|
{
|
|
const db::Matrix3d &m = obj->matrix ();
|
|
return db::DCplxTrans (1.0, m.angle (), m.is_mirror (), m.disp ()) * db::DCplxTrans (db::DVector (obj->width () * -0.5 * m.mag_x (), obj->height () * -0.5 * m.mag_y ()));
|
|
}
|
|
|
|
static void img_set_trans (ImageRef *obj, const db::DCplxTrans &t)
|
|
{
|
|
// to be consistent with the definition of KLayout 0.21, we keep mag_x and mag_y as pixel dimensions
|
|
// and refer to the image's pixel 0,0 as the rotation center.
|
|
db::Matrix3d m = obj->matrix ();
|
|
db::Matrix3d n = db::Matrix3d::disp (t.disp ()) * db::Matrix3d::rotation (t.angle ()) * db::Matrix3d::mag (t.mag () * m.mag_x (), t.mag () * m.mag_y ()) * db::Matrix3d::mirror (t.is_mirror ()) * db::Matrix3d::disp (db::DVector (obj->width () * 0.5, obj->height () * 0.5));
|
|
obj->set_matrix (n);
|
|
}
|
|
|
|
// NOTE: img::Object is available as "BasicImage" to allow binding for other methods.
|
|
gsi::Class<img::Object> decl_BasicImage ("BasicImage", gsi::Methods (), "@hide");
|
|
|
|
gsi::Class<ImageRef> decl_Image (decl_BasicImage, "Image",
|
|
gsi::constructor ("new", &gsi::new_image,
|
|
"@brief Create a new image with the default attributes"
|
|
"\n"
|
|
"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,
|
|
"@brief Constructor from a image file \n"
|
|
"@args filename\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,
|
|
"@brief Constructor from a image file \n"
|
|
"@args filename, trans\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"
|
|
"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"
|
|
) +
|
|
gsi::constructor ("new", &gsi::new_image_whd,
|
|
"@brief Constructor for a monochrome image with the given pixel values\n"
|
|
"@args w, h, data\n"
|
|
"\n"
|
|
"This constructor creates an image from the given pixel values. The values have to be organized\n"
|
|
"line by line. Each line must consist of \"w\" values where the first value is the leftmost pixel.\n"
|
|
"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"
|
|
"Initially the pixel width and heigt will be 1 micron and the data range will be 0 to 1.0 (black to white level). \n"
|
|
"To adjust the data range use the \\min_value and \\max_value properties.\n"
|
|
"\n"
|
|
"@param w The width of the image\n"
|
|
"@param h The height of the image\n"
|
|
"@param d The data (see method description)\n"
|
|
) +
|
|
gsi::constructor ("new", &gsi::new_image_whtd,
|
|
"@brief Constructor for a monochrome image with the given pixel values\n"
|
|
"@args w, h, trans, data\n"
|
|
"\n"
|
|
"This constructor creates an image from the given pixel values. The values have to be organized\n"
|
|
"line by line. Each line must consist of \"w\" values where the first value is the leftmost pixel.\n"
|
|
"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"
|
|
"Initially the pixel width and heigt will be 1 micron and the data range will be 0 to 1.0 (black to white level). \n"
|
|
"To adjust the data range use the \\min_value and \\max_value properties.\n"
|
|
"\n"
|
|
"@param w The width of the image\n"
|
|
"@param h The height of the image\n"
|
|
"@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,
|
|
"@brief Constructor for monochrome or color images with zero pixel values\n"
|
|
"@args w, h, color\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 heigt 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,
|
|
"@brief Constructor for monochrome or color images with zero pixel values\n"
|
|
"@args w, h, trans, color\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 heigt 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,
|
|
"@brief Constructor for a color image with the given pixel values\n"
|
|
"@args w, h, red, green, blue\n"
|
|
"\n"
|
|
"This constructor creates an image from the given pixel values. The values have to be organized\n"
|
|
"line by line and separated by color channel. Each line must consist of \"w\" values where the first value is the leftmost pixel.\n"
|
|
"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"
|
|
"Initially the pixel width and heigt will be 1 micron and the data range will be 0 to 1.0 (black to white level). \n"
|
|
"To adjust the data range use the \\min_value and \\max_value properties.\n"
|
|
"\n"
|
|
"@param w The width of the image\n"
|
|
"@param h The height of the image\n"
|
|
"@param red The red channel data set which will become owned by the image\n"
|
|
"@param green The green channel data set which will become owned by the image\n"
|
|
"@param blue The blue channel data set which will become owned by the image\n"
|
|
) +
|
|
gsi::constructor ("new", &gsi::new_image_whtrgb,
|
|
"@brief Constructor for a color image with the given pixel values\n"
|
|
"@args w, h, trans, red, green, blue\n"
|
|
"\n"
|
|
"This constructor creates an image from the given pixel values. The values have to be organized\n"
|
|
"line by line and separated by color channel. Each line must consist of \"w\" values where the first value is the leftmost pixel.\n"
|
|
"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"
|
|
"Initially the pixel width and heigt will be 1 micron and the data range will be 0 to 1.0 (black to white level). \n"
|
|
"To adjust the data range use the \\min_value and \\max_value properties.\n"
|
|
"\n"
|
|
"@param w The width of the image\n"
|
|
"@param h The height of the image\n"
|
|
"@param trans The transformation from pixel space to micron space\n"
|
|
"@param red The red channel data set which will become owned by the image\n"
|
|
"@param green The green channel data set which will become owned by the image\n"
|
|
"@param blue The blue channel data set which will become owned by the image\n"
|
|
) +
|
|
gsi::method ("box", &ImageRef::box,
|
|
"@brief Gets the bounding box of the image\n"
|
|
"@return The bounding box\n"
|
|
) +
|
|
gsi::method ("transformed", &ImageRef::transformed<db::DTrans>,
|
|
"@brief Transforms the image with the given simple transformation\n"
|
|
"@args t\n"
|
|
"@param t The transformation to apply\n"
|
|
"@return The transformed object\n"
|
|
) +
|
|
gsi::method ("transformed|#transformed_matrix", &ImageRef::transformed<db::Matrix3d>,
|
|
"@brief Transforms the image with the given matrix transformation\n"
|
|
"@args t\n"
|
|
"@param t The transformation to apply (a matrix)\n"
|
|
"@return The transformed object\n"
|
|
"This method has been introduced in version 0.22."
|
|
) +
|
|
gsi::method ("transformed|#transformed_cplx", &ImageRef::transformed<db::DCplxTrans>,
|
|
"@brief Transforms the image with the given complex transformation\n"
|
|
"@args t\n"
|
|
"@param t The magnifying transformation to apply\n"
|
|
"@return The transformed object\n"
|
|
) +
|
|
gsi::method ("width", &ImageRef::width,
|
|
"@brief Gets the width of the image in pixels\n"
|
|
"@return The width in pixels\n"
|
|
) +
|
|
gsi::method ("height", &ImageRef::height,
|
|
"@brief Gets the height of the image in pixels\n"
|
|
"@return The height in pixels\n"
|
|
) +
|
|
gsi::method ("filename", &ImageRef::filename,
|
|
"@brief Gets the name of the file loaded of an empty string if not file is loaded\n"
|
|
"@return The file name (path)\n"
|
|
) +
|
|
gsi::method ("is_empty?", &ImageRef::is_empty,
|
|
"@brief Returns true, if the image does not contain any data (i.e. is default constructed)\n"
|
|
"@return True, if the image is empty\n"
|
|
) +
|
|
gsi::method ("is_color?", &ImageRef::is_color,
|
|
"@brief Returns true, if the image is a color image\n"
|
|
"@return True, if the image is a color image\n"
|
|
) +
|
|
gsi::method ("set_mask", &ImageRef::set_mask,
|
|
"@brief Sets the mask for a pixel\n"
|
|
"@args x, y, m\n"
|
|
"\n"
|
|
"@param x The x coordinate of the pixel (0..width()-1)\n"
|
|
"@param y The y coordinate of the pixel (mathematical order: 0 is the lowest, 0..height()-1)\n"
|
|
"@param m The mask\n"
|
|
"\n"
|
|
"If the mask of a pixel is set to false, the pixel is not drawn. The default is true for all pixels.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.23.\n"
|
|
) +
|
|
gsi::method ("mask", (bool (ImageRef::*) (size_t x, size_t y) const) &ImageRef::mask,
|
|
"@brief Gets the mask for one pixel\n"
|
|
"@args x, y\n"
|
|
"\n"
|
|
"@param x The x coordinate of the pixel (0..width()-1)\n"
|
|
"@param y The y coordinate of the pixel (mathematical order: 0 is the lowest, 0..height()-1)\n"
|
|
"@return false if the pixel is not drawn.\n"
|
|
"\n"
|
|
"See \\set_mask for details about the mask.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.23.\n"
|
|
) +
|
|
gsi::method ("set_pixel", (void (ImageRef::*)(size_t x, size_t y, double v)) &ImageRef::set_pixel,
|
|
"@brief Sets one pixel (monochrome)\n"
|
|
"@args x, y, v\n"
|
|
"\n"
|
|
"@param x The x coordinate of the pixel (0..width()-1)\n"
|
|
"@param y The y coordinate of the pixel (mathematical order: 0 is the lowest, 0..height()-1)\n"
|
|
"@param v The value\n"
|
|
"\n"
|
|
"If the component index, x or y value exceeds the image bounds of the image is a color image,\n"
|
|
"this method does nothing.\n"
|
|
) +
|
|
gsi::method ("set_pixel", (void (ImageRef::*)(size_t x, size_t y, double r, double g, double b)) &ImageRef::set_pixel,
|
|
"@brief Sets one pixel (color)\n"
|
|
"@args x, y, r, g, b\n"
|
|
"\n"
|
|
"@param x The x coordinate of the pixel (0..width()-1)\n"
|
|
"@param y The y coordinate of the pixel (mathematical order: 0 is the lowest, 0..height()-1)\n"
|
|
"@param red The red component\n"
|
|
"@param green The green component\n"
|
|
"@param blue The blue component\n"
|
|
"\n"
|
|
"If the component index, x or y value exceeds the image bounds of the image is not a color image,\n"
|
|
"this method does nothing.\n"
|
|
) +
|
|
gsi::method ("get_pixel", (double (ImageRef::*)(size_t x, size_t y) const) &ImageRef::pixel,
|
|
"@brief Gets one pixel (monochrome only)\n"
|
|
"@args x, y\n"
|
|
"\n"
|
|
"@param x The x coordinate of the pixel (0..width()-1)\n"
|
|
"@param y The y coordinate of the pixel (mathematical order: 0 is the lowest, 0..height()-1)\n"
|
|
"\n"
|
|
"If x or y value exceeds the image bounds, this method \n"
|
|
"returns 0.0. This method is valid for monochrome images only. For color images it will return 0.0 always.\n"
|
|
"Use \\is_color? to decide whether the image is a color image or monochrome one.\n"
|
|
) +
|
|
gsi::method ("get_pixel", (double (ImageRef::*)(size_t x, size_t y, unsigned int component) const) &ImageRef::pixel,
|
|
"@brief Gets one pixel (monochrome and color)\n"
|
|
"@args x, y, component\n"
|
|
"\n"
|
|
"@param x The x coordinate of the pixel (0..width()-1)\n"
|
|
"@param y The y coordinate of the pixel (mathematical order: 0 is the lowest, 0..height()-1)\n"
|
|
"@param component 0 for red, 1 for green, 2 for blue.\n"
|
|
"\n"
|
|
"If the component index, x or y value exceeds the image bounds, this method \n"
|
|
"returns 0.0. For monochrome images, the component index is ignored.\n"
|
|
) +
|
|
gsi::method ("set_data", (void (ImageRef::*)(size_t w, size_t h, const std::vector<double> &d)) &ImageRef::set_data,
|
|
"@brief Writes the image data field (monochrome)\n"
|
|
"@args w, h, d\n"
|
|
"@param w The width of the new data\n"
|
|
"@param h The height of the new data\n"
|
|
"@param d The (monochrome) data to load into the image\n"
|
|
"\n"
|
|
"See the constructor description for the data organisation in that field.\n"
|
|
) +
|
|
gsi::method ("set_data", (void (ImageRef::*)(size_t w, size_t h, const std::vector<double> &r, const std::vector<double> &g, const std::vector<double> &b)) &img::Object::set_data,
|
|
"@brief Writes the image data field (color)\n"
|
|
"@args w, h, r, g, b\n"
|
|
"@param w The width of the new data\n"
|
|
"@param h The height of the new data\n"
|
|
"@param r The red channel data to load into the image\n"
|
|
"@param g The green channel data to load into the image\n"
|
|
"@param b The blue channel data to load into the image\n"
|
|
"\n"
|
|
"See the constructor description for the data organisation in that field.\n"
|
|
) +
|
|
gsi::method_ext ("pixel_width=", &img_set_pixel_width,
|
|
"@brief Sets the pixel width\n"
|
|
"@args w\n"
|
|
"\n"
|
|
"The pixel width determines the width of on pixel in the original space which is transformed to\n"
|
|
"micron space with the transformation.\n"
|
|
"\n"
|
|
"Starting with version 0.22, this property is incorporated into the transformation matrix.\n"
|
|
"This property is provided for convenience only."
|
|
) +
|
|
gsi::method_ext ("pixel_width", &img_get_pixel_width,
|
|
"@brief Gets the pixel width\n"
|
|
"\n"
|
|
"See \\pixel_width= for a description of that property.\n"
|
|
"\n"
|
|
"Starting with version 0.22, this property is incorporated into the transformation matrix.\n"
|
|
"This property is provided for convenience only."
|
|
) +
|
|
gsi::method_ext ("pixel_height=", &img_set_pixel_height,
|
|
"@brief Sets the pixel height\n"
|
|
"@args h\n"
|
|
"\n"
|
|
"The pixel height determines the height of on pixel in the original space which is transformed to\n"
|
|
"micron space with the transformation.\n"
|
|
"\n"
|
|
"Starting with version 0.22, this property is incorporated into the transformation matrix.\n"
|
|
"This property is provided for convenience only."
|
|
) +
|
|
gsi::method_ext ("pixel_height", &img_get_pixel_height,
|
|
"@brief Gets the pixel height\n"
|
|
"\n"
|
|
"See \\pixel_height= for a description of that property.\n"
|
|
"\n"
|
|
"Starting with version 0.22, this property is incorporated into the transformation matrix.\n"
|
|
"This property is provided for convenience only."
|
|
) +
|
|
gsi::method ("z_position", &ImageRef::z_position,
|
|
"@brief Gets the z position of the image\n"
|
|
"Images with a higher z position are painted in front of images with lower z position.\n"
|
|
"The z value is an integer that controls the position relative to other images.\n"
|
|
"\n"
|
|
"This method was introduced in version 0.25."
|
|
) +
|
|
gsi::method ("z_position=", &ImageRef::set_z_position, gsi::arg ("z"),
|
|
"@brief Sets the z position of the image\n"
|
|
"\n"
|
|
"See \\z_position for details about the z position attribute.\n"
|
|
"\n"
|
|
"This method was introduced in version 0.25."
|
|
) +
|
|
gsi::method ("matrix=", &ImageRef::set_matrix,
|
|
"@brief Sets the transformation matrix\n"
|
|
"@args t\n"
|
|
"\n"
|
|
"This transformation matrix converts pixel coordinates (0,0 being the center and each pixel having the dimension of pixel_width and pixel_height)\n"
|
|
"to micron coordinates. The coordinate of the pixel is the lower left corner of the pixel.\n"
|
|
"\n"
|
|
"The matrix is more general than the transformation used before and supports shear and perspective transformation. This property replaces the \\trans property which is "
|
|
"still functional, but deprecated.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.22."
|
|
) +
|
|
gsi::method ("matrix", &ImageRef::matrix,
|
|
"@brief Returns the pixel-to-micron transformation matrix\n"
|
|
"\n"
|
|
"This transformation matrix converts pixel coordinates (0,0 being the center and each pixel having the dimension of pixel_width and pixel_height)\n"
|
|
"to micron coordinates. The coordinate of the pixel is the lower left corner of the pixel.\n"
|
|
"\n"
|
|
"The matrix is more general than the transformation used before and supports shear and perspective transformation. This property replaces the \\trans property which is "
|
|
"still functional, but deprecated.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.22."
|
|
) +
|
|
gsi::method_ext ("trans", &img_get_trans,
|
|
"@brief Returns the pixel-to-micron transformation\n"
|
|
"\n"
|
|
"This transformation converts pixel coordinates (0,0 being the lower left corner and each pixel having the dimension of pixel_width and pixel_height)\n"
|
|
"to micron coordinates. The coordinate of the pixel is the lower left corner of the pixel.\n"
|
|
"\n"
|
|
"The general property is \\matrix which also allows perspective and shear transformation. This property will only "
|
|
"work, if the transformation does not include perspective or shear components. Therefore this property is deprecated."
|
|
"\n"
|
|
"Please note that for backward compatibility, the rotation center is pixel 0,0 (lowest left one), while it "
|
|
"is the image center for the matrix transformation."
|
|
) +
|
|
gsi::method_ext ("trans=", &img_set_trans,
|
|
"@brief Sets the transformation\n"
|
|
"@args t\n"
|
|
"\n"
|
|
"This transformation converts pixel coordinates (0,0 being the lower left corner and each pixel having the dimension of pixel_width and pixel_height)\n"
|
|
"to micron coordinates. The coordinate of the pixel is the lower left corner of the pixel.\n"
|
|
"\n"
|
|
"The general property is \\matrix which also allows perspective and shear transformation."
|
|
"\n"
|
|
"Please note that for backward compatibility, the rotation center is pixel 0,0 (lowest left one), while it "
|
|
"is the image center for the matrix transformation."
|
|
) +
|
|
gsi::method ("min_value=", &ImageRef::set_min_value,
|
|
"@brief Sets the minimum value\n"
|
|
"@args v\n"
|
|
"\n"
|
|
"See \\min_value for the description of the minimum value property.\n"
|
|
) +
|
|
gsi::method ("min_value", &ImageRef::min_value,
|
|
"@brief Gets the upper limit of the values in the data set\n"
|
|
"\n"
|
|
"This value determines the upper end of the data mapping (i.e. white value etc.).\n"
|
|
"It does not necessarily correspond to the minimum value of the data set but it must be\n"
|
|
"larger than that.\n"
|
|
) +
|
|
gsi::method ("max_value=", &ImageRef::set_max_value,
|
|
"@brief Gets the upper limit of the values in the data set\n"
|
|
"@args v\n"
|
|
"\n"
|
|
"This value determines the upper end of the data mapping (i.e. white value etc.).\n"
|
|
"It does not necessarily correspond to the maximum value of the data set but it must be\n"
|
|
"larger than that.\n"
|
|
) +
|
|
gsi::method ("max_value", &ImageRef::max_value,
|
|
"@brief Sets the maximum value\n"
|
|
"\n"
|
|
"See the \\max_value method for the description of the maximum value property.\n"
|
|
) +
|
|
gsi::method ("visible=", &ImageRef::set_visible,
|
|
"@brief Sets the visibility\n"
|
|
"@args v\n"
|
|
"\n"
|
|
"See the \\is_visible? method for a description of this property.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.20.\n"
|
|
) +
|
|
gsi::method ("is_visible?", &ImageRef::is_visible,
|
|
"@brief Gets a flag indicating whether the image object is visible\n"
|
|
"\n"
|
|
"An image object can be made invisible by setting the visible property to false.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.20.\n"
|
|
) +
|
|
gsi::method ("id", (size_t (ImageRef::*) () const) &ImageRef::id,
|
|
"@brief Gets the Id\n"
|
|
"\n"
|
|
"The Id is an arbitrary integer that can be used to track the evolution of an\n"
|
|
"image object. The Id is not changed when the object is edited.\n"
|
|
"On initialization, a unique Id is given to the object. The Id cannot be changed. "
|
|
"This behaviour has been modified in version 0.20."
|
|
) +
|
|
gsi::method ("data_mapping=", &ImageRef::set_data_mapping,
|
|
"@brief Sets the data mapping object\n"
|
|
"@args data_mapping\n"
|
|
"\n"
|
|
"The data mapping describes the transformation of a pixel value (any double value) into pixel data "
|
|
"which can be sent to the graphics cards for display. See \\ImageDataMapping for a more detailed description.\n"
|
|
) +
|
|
gsi::method ("data_mapping", &ImageRef::data_mapping,
|
|
"@brief Gets the data mapping\n"
|
|
"@return The data mapping object\n"
|
|
"\n"
|
|
"The data mapping describes the transformation of a pixel value (any double value) into pixel data "
|
|
"which can be sent to the graphics cards for display. See \\ImageDataMapping for a more detailed description.\n"
|
|
) +
|
|
gsi::method ("detach", &ImageRef::detach,
|
|
"@brief Detaches the image object from the view\n"
|
|
"If the image object was inserted into the view, property changes will be "
|
|
"reflected in the view. To disable this feature, 'detach'' can be called after which "
|
|
"the image object becomes inactive and changes will no longer be reflected in the view.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.25."
|
|
) +
|
|
gsi::method ("update", &ImageRef::update_view,
|
|
"@brief Forces an update of the view\n"
|
|
"Usually it is not required to call this method. The image object is automatically synchronized "
|
|
"with the view's image objects. For performance reasons this update is delayed to collect multiple "
|
|
"update requests. Calling 'update' will ensure immdiate updates.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.25."
|
|
) +
|
|
gsi::method ("delete", &ImageRef::erase,
|
|
"@brief Deletes this image from the view\n"
|
|
"If the image is an \"active\" one, this method will remove it from the view. "
|
|
"This object will become detached and can still be manipulated, but without having an "
|
|
"effect on the view."
|
|
"\n"
|
|
"This method has been introduced in version 0.25."
|
|
) +
|
|
gsi::method ("is_valid?", &ImageRef::is_valid,
|
|
"@brief Returns a value indicating whether the object is a valid reference.\n"
|
|
"If this value is true, the object represents an image on the screen. Otherwise, the "
|
|
"object is a 'detached' image which does not have a representation on the screen.\n"
|
|
"\n"
|
|
"This method was introduced in version 0.25."
|
|
) +
|
|
gsi::method ("to_s", &ImageRef::to_string,
|
|
"@brief Converts the image to a string\n"
|
|
"@return The string\n"
|
|
),
|
|
"@brief An image to be stored as a layout annotation\n"
|
|
"\n"
|
|
"Images can be put onto the layout canvas as annotations, along with rulers and markers.\n"
|
|
"Images can be monochrome (represent scalar data) as well as color (represent color images).\n"
|
|
"The display of images can be adjusted in various ways, i.e. color mapping (translation of scalar values to\n"
|
|
"colors), geometrical transformations (including rotation by arbitrary angles) and similar.\n"
|
|
"Images are always based on floating point data. The actual data range is not fixed and can be adjusted to "
|
|
"the data set (i.e. 0..255 or -1..1). This gives a great flexibility when displaying data which is the result of "
|
|
"some measurement or calculation for example.\n"
|
|
"The basic parameters of an image are the width and height of the data set, the width and height of one pixel, "
|
|
"the geometrical transformation to be applied, the data range (min_value to max_value) and the data mapping which "
|
|
"is described by an own class, \\ImageDataMapping.\n"
|
|
"\n"
|
|
"Starting with version 0.22, the basic transformation is a 3x3 matrix rather than the simple "
|
|
"affine transformation. This matrix includes the pixel dimensions as well. One consequence of that is "
|
|
"that the magnification part of the matrix and the pixel dimensions are no longer separated. "
|
|
"That has certain consequences, i.e. setting an affine transformation with a magnification scales "
|
|
"the pixel sizes as before but an affine transformation returned will no longer contain the pixel dimensions "
|
|
"as magnification because it only supports isotropic scaling. For backward compatibility, the rotation "
|
|
"center for the affine transformations while the default center and the center for matrix transformations "
|
|
"is the image center.\n"
|
|
"\n"
|
|
"As with version 0.25, images become 'live' objects. Changes to image properties will be reflected in the "
|
|
"view automatically once the image object has been inserted into a view. "
|
|
"Note that changes are not immediately reflected in the view, but are delayed until the view is refreshed. "
|
|
"Hence, iterating the view's images will not render the same results than the image objects attached to the view. "
|
|
"To ensure synchonization, call \\Image#update."
|
|
);
|
|
|
|
/**
|
|
* @brief An alternative iterator that returns "live" ImageRef objects
|
|
*/
|
|
struct ImageRefIterator
|
|
: public img::ImageIterator
|
|
{
|
|
public:
|
|
typedef ImageRef reference;
|
|
|
|
ImageRefIterator ()
|
|
: img::ImageIterator ()
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ImageRefIterator (const img::ImageIterator &iter, lay::LayoutView *view)
|
|
: img::ImageIterator (iter), mp_view (view)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
reference operator* () const
|
|
{
|
|
return reference (img::ImageIterator::operator* (), const_cast<lay::LayoutView * >(mp_view.get ()));
|
|
}
|
|
|
|
private:
|
|
tl::weak_ptr<lay::LayoutView> mp_view;
|
|
};
|
|
|
|
static void clear_images (lay::LayoutView *view)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
if (img_service) {
|
|
img_service->clear_images ();
|
|
}
|
|
}
|
|
|
|
static void show_image (lay::LayoutView *view, size_t id, bool visible)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
if (img_service) {
|
|
|
|
const img::Object *img = img_service->object_by_id (id);
|
|
if (img == 0) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("The image Id is not valid")));
|
|
}
|
|
|
|
img::Object new_img (*img);
|
|
new_img.set_visible (visible);
|
|
|
|
img_service->change_image_by_id (id, new_img);
|
|
|
|
}
|
|
}
|
|
|
|
static void replace_image (lay::LayoutView *view, size_t id, ImageRef &new_obj)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
if (img_service) {
|
|
|
|
const img::Object *img = img_service->object_by_id (id);
|
|
if (img == 0) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("The image Id is not valid")));
|
|
}
|
|
|
|
img_service->change_image_by_id (id, new_obj);
|
|
|
|
}
|
|
}
|
|
|
|
static void erase_image (lay::LayoutView *view, size_t id)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
if (img_service) {
|
|
|
|
const img::Object *img = img_service->object_by_id (id);
|
|
if (img == 0) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("The image Id is not valid")));
|
|
}
|
|
|
|
img_service->erase_image_by_id (id);
|
|
|
|
}
|
|
}
|
|
|
|
static void insert_image (lay::LayoutView *view, ImageRef &obj)
|
|
{
|
|
if (obj.is_valid ()) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("The object is already inserted into a view - detach the object first or create a different object.")));
|
|
}
|
|
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
if (img_service) {
|
|
img::Object *inew = img_service->insert_image (obj);
|
|
obj.id (inew->id ());
|
|
obj.set_view (view);
|
|
}
|
|
}
|
|
|
|
static ImageRef get_image (lay::LayoutView *view, size_t id)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
if (img_service) {
|
|
for (ImageRefIterator iter (img_service->begin_images (), view); !iter.at_end(); ++iter) {
|
|
if ((*iter).id () == id) {
|
|
return *iter;
|
|
}
|
|
}
|
|
}
|
|
return ImageRef ();
|
|
}
|
|
|
|
static tl::Event &get_images_changed_event (lay::LayoutView *view)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
tl_assert (img_service != 0);
|
|
return img_service->images_changed_event;
|
|
}
|
|
|
|
static tl::Event &get_image_selection_changed_event (lay::LayoutView *view)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
tl_assert (img_service != 0);
|
|
return img_service->image_selection_changed_event;
|
|
}
|
|
|
|
static tl::event<int> &get_image_changed_event (lay::LayoutView *view)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
tl_assert (img_service != 0);
|
|
return img_service->image_changed_event;
|
|
}
|
|
|
|
static ImageRefIterator begin_images (lay::LayoutView *view)
|
|
{
|
|
img::Service *img_service = view->get_plugin <img::Service> ();
|
|
if (img_service) {
|
|
return ImageRefIterator (img_service->begin_images (), view);
|
|
} else {
|
|
return ImageRefIterator ();
|
|
}
|
|
}
|
|
|
|
static
|
|
gsi::ClassExt<lay::LayoutView> layout_view_decl (
|
|
gsi::method_ext ("clear_images", &gsi::clear_images,
|
|
"@brief Clear all images on this view"
|
|
) +
|
|
gsi::method_ext ("replace_image", &gsi::replace_image, gsi::arg("id"), gsi::arg("new_obj"),
|
|
"@brief Replace an image object with the new image\n"
|
|
"\n"
|
|
"@param id The id of the object to replace\n"
|
|
"@param new_obj The new object to replace the old one\n"
|
|
"\n"
|
|
"Replaces the image with the given Id with the new object. The Id can be obtained with if \"id\" method of the image object.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.20.\n"
|
|
) +
|
|
gsi::method_ext ("erase_image", &gsi::erase_image, gsi::arg("id"),
|
|
"@brief Erase the given image\n"
|
|
"@param id The id of the object to erase\n"
|
|
"\n"
|
|
"Erases the image with the given Id. The Id can be obtained with if \"id\" method of the image object.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.20.\n"
|
|
"\n"
|
|
"With version 0.25, \\Image#delete can be used to achieve the same results."
|
|
) +
|
|
gsi::method_ext ("show_image", &gsi::show_image, gsi::arg("id"), gsi::arg("visible"),
|
|
"@brief Shows or hides the given image\n"
|
|
"@param id The id of the object to show or hide\n"
|
|
"@param visible True, if the image should be shown\n"
|
|
"\n"
|
|
"Sets the visibility of the image with the given Id. The Id can be obtained with if \"id\" method of the image object.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.20.\n"
|
|
"\n"
|
|
"With version 0.25, \\Image#visible= can be used to achieve the same results."
|
|
) +
|
|
gsi::method_ext ("insert_image", &gsi::insert_image, gsi::arg("obj"),
|
|
"@brief Insert an image object into the given view\n"
|
|
"Insert the image object given by obj into the view.\n"
|
|
"\n"
|
|
"With version 0.25, this method will attach the image object to the view and the image object will become a 'live' "
|
|
"object - i.e. changes to the object will change the appearance of the image on the screen.\n"
|
|
) +
|
|
gsi::method_ext ("image", &gsi::get_image, gsi::arg ("id"),
|
|
"@brief Gets the image given by an ID\n"
|
|
"Returns a reference to the image given by the respective ID or an invalid image if the ID is not valid.\n"
|
|
"Use \\Image#is_valid? to determine whether the returned image is valid or not.\n"
|
|
"\n"
|
|
"The returned image is a 'live' object and changing it will update the view.\n"
|
|
"\n"
|
|
"This method has been introduced in version 0.25.\n"
|
|
) +
|
|
gsi::event_ext ("on_images_changed", &get_images_changed_event,
|
|
"@brief A event indicating that images have been added or removed\n"
|
|
"This event has been added in version 0.25.\n"
|
|
) +
|
|
gsi::event_ext ("on_image_selection_changed", &get_image_selection_changed_event,
|
|
"@brief A event indicating that the image selection has changed\n"
|
|
"This event has been added in version 0.25.\n"
|
|
) +
|
|
gsi::event_ext ("on_image_changed", &get_image_changed_event, gsi::arg ("id"),
|
|
"@brief A event indicating that an image has been modified\n"
|
|
"The argument of the event is the ID of the image that was changed.\n"
|
|
"This event has been added in version 0.25.\n"
|
|
) +
|
|
gsi::iterator_ext ("each_image", &gsi::begin_images,
|
|
"@brief Iterate over all images attached to this view\n"
|
|
"\n"
|
|
"With version 0.25, the objects returned by the iterator are references and can be manipulated to change their "
|
|
"appearance.\n"
|
|
),
|
|
""
|
|
);
|
|
|
|
class SelectionIterator
|
|
{
|
|
public:
|
|
typedef ImageRef value_type;
|
|
typedef std::map<img::Service::obj_iterator, unsigned int>::const_iterator iterator_type;
|
|
typedef void pointer;
|
|
typedef const value_type &reference;
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
typedef void difference_type;
|
|
|
|
SelectionIterator (const std::vector<img::Service *> &services)
|
|
: m_services (services), m_service (0)
|
|
{
|
|
if (! m_services.empty ()) {
|
|
m_iter = m_services [m_service]->selection ().begin ();
|
|
next ();
|
|
}
|
|
}
|
|
|
|
bool at_end () const
|
|
{
|
|
return (m_service >= m_services.size ());
|
|
}
|
|
|
|
SelectionIterator &operator++ ()
|
|
{
|
|
++m_iter;
|
|
next ();
|
|
return *this;
|
|
}
|
|
|
|
value_type operator* () const
|
|
{
|
|
return value_type (*(dynamic_cast<const img::Object *> (m_iter->first->ptr ())), m_services[m_service]->view ());
|
|
}
|
|
|
|
private:
|
|
std::vector<img::Service *> m_services;
|
|
unsigned int m_service;
|
|
iterator_type m_iter;
|
|
|
|
void next ()
|
|
{
|
|
while (m_iter == m_services [m_service]->selection ().end ()) {
|
|
++m_service;
|
|
if (m_service < m_services.size ()) {
|
|
m_iter = m_services [m_service]->selection ().begin ();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// extend the layout view by "edtService" specific methods
|
|
|
|
static bool has_image_selection (const lay::LayoutView *view)
|
|
{
|
|
std::vector<img::Service *> img = view->get_plugins <img::Service> ();
|
|
for (std::vector<img::Service *>::const_iterator s = img.begin (); s != img.end (); ++s) {
|
|
if ((*s)->selection_size () > 0) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static SelectionIterator begin_images_selected (const lay::LayoutView *view)
|
|
{
|
|
return SelectionIterator (view->get_plugins <img::Service> ());
|
|
}
|
|
|
|
|
|
static
|
|
gsi::ClassExt<lay::LayoutView> layout_view_decl2 (
|
|
gsi::method_ext ("has_image_selection?", &has_image_selection,
|
|
"@brief Returns true, if images are selected in this view"
|
|
"\n"
|
|
"This method was introduced in version 0.19."
|
|
) +
|
|
gsi::iterator_ext ("each_image_selected", &begin_images_selected,
|
|
"@brief Iterate over each selected image object, yielding a \\Image object for each of them"
|
|
"\n"
|
|
"This method was introduced in version 0.19."
|
|
),
|
|
""
|
|
);
|
|
|
|
/**
|
|
* @brief Extension for tiling processor
|
|
*/
|
|
class ImageCollectingTileOutputReceiver
|
|
: public db::TileOutputReceiver
|
|
{
|
|
public:
|
|
ImageCollectingTileOutputReceiver (img::Object *image)
|
|
: mp_image (image)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
virtual void begin (size_t nx, size_t ny, const db::DPoint &p0, double dx, double dy, const db::DBox & /*frame*/)
|
|
{
|
|
if (mp_image) {
|
|
db::Matrix3d m = db::Matrix3d::disp ((p0 - db::DPoint ()) + db::DVector (nx * dx * 0.5, ny * dy * 0.5)) * db::Matrix3d::mag (dx, dy);
|
|
*mp_image = img::Object (nx, ny, m, false);
|
|
}
|
|
}
|
|
|
|
virtual void put (size_t ix, size_t iy, const db::Box & /*tile*/, size_t /*id*/, const tl::Variant &obj, double /*dbu*/, const db::ICplxTrans & /*trans*/, bool /*clip*/)
|
|
{
|
|
if (mp_image) {
|
|
mp_image->set_pixel (ix, iy, obj.to_double ());
|
|
}
|
|
}
|
|
|
|
private:
|
|
img::Object *mp_image;
|
|
};
|
|
|
|
static void tp_output_image (db::TilingProcessor *proc, const std::string &name, img::Object *i)
|
|
{
|
|
proc->output (name, 0, new ImageCollectingTileOutputReceiver (i), db::ICplxTrans ());
|
|
}
|
|
|
|
// extend the db::TilingProcessor with the ability to feed images
|
|
static
|
|
gsi::ClassExt<db::TilingProcessor> tiling_processor_ext (
|
|
method_ext ("output", &tp_output_image,
|
|
"@brief Specifies output to an image\n"
|
|
"@args name, image\n"
|
|
"This method will establish an output channel which delivers float data to image data. "
|
|
"The image is a monochrome image where each pixel corresponds to a single tile. This "
|
|
"method for example is useful to collect densitity information into an image. The "
|
|
"image is configured such that each pixel covers one tile.\n"
|
|
"\n"
|
|
"The name is the name which must be used in the _output function of the scripts in order to "
|
|
"address that channel.\n"
|
|
),
|
|
""
|
|
);
|
|
|
|
}
|
|
|