mirror of https://github.com/KLayout/klayout.git
Added lyimg format for image file persistence.
This commit is contained in:
parent
1939ce683d
commit
ccb8e8831f
|
|
@ -1344,7 +1344,7 @@ public:
|
|||
{
|
||||
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);
|
||||
*mp_image = img::Object (nx, ny, m, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ HEADERS = \
|
|||
imgService.h \
|
||||
imgWidgets.h \
|
||||
imgForceLink.h \
|
||||
imgCommon.h
|
||||
imgCommon.h \
|
||||
imgStream.h
|
||||
|
||||
FORMS = \
|
||||
AddNewImageDialog.ui \
|
||||
|
|
@ -31,7 +32,8 @@ SOURCES = \
|
|||
imgPropertiesPage.cc \
|
||||
imgService.cc \
|
||||
imgWidgets.cc \
|
||||
imgForceLink.cc
|
||||
imgForceLink.cc \
|
||||
imgStream.cc
|
||||
|
||||
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC $$LAYBASIC_INC $$DB_INC
|
||||
DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC $$LAYBASIC_INC $$DB_INC
|
||||
|
|
|
|||
|
|
@ -710,31 +710,16 @@ Object::Object ()
|
|||
mp_pixel_data = 0;
|
||||
}
|
||||
|
||||
Object::Object (size_t w, size_t h, const db::DCplxTrans &trans, bool color)
|
||||
Object::Object (size_t w, size_t h, const db::DCplxTrans &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)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = new DataHeader (w, h, color, false);
|
||||
mp_data = new DataHeader (w, h, color, byte_data);
|
||||
mp_data->add_ref ();
|
||||
|
||||
// The default data type is float
|
||||
tl_assert (! is_byte_data ());
|
||||
|
||||
if (is_color ()) {
|
||||
for (unsigned int c = 0; c < 3; ++c) {
|
||||
float *d = mp_data->float_data (c);
|
||||
for (size_t i = data_length (); i > 0; --i) {
|
||||
*d++ = 0.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
float *d = mp_data->float_data ();
|
||||
for (size_t i = data_length (); i > 0; --i) {
|
||||
*d++ = 0.0;
|
||||
}
|
||||
}
|
||||
clear ();
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
Object::Object (size_t w, size_t h, const db::DCplxTrans &trans, unsigned char *d)
|
||||
|
|
@ -808,32 +793,15 @@ Object::Object (const std::string &filename, const db::DCplxTrans &trans)
|
|||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
Object::Object (size_t w, size_t h, const db::Matrix3d &trans, bool color)
|
||||
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)
|
||||
{
|
||||
m_updates_enabled = false;
|
||||
mp_pixel_data = 0;
|
||||
|
||||
mp_data = new DataHeader (w, h, color, false);
|
||||
mp_data = new DataHeader (w, h, color, byte_data);
|
||||
mp_data->add_ref ();
|
||||
|
||||
// The default data type is float
|
||||
tl_assert (! is_byte_data ());
|
||||
|
||||
if (is_color ()) {
|
||||
for (unsigned int c = 0; c < 3; ++c) {
|
||||
float *d = mp_data->float_data (c);
|
||||
for (size_t i = data_length (); i > 0; --i) {
|
||||
*d++ = 0.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
float *d = mp_data->float_data ();
|
||||
for (size_t i = data_length (); i > 0; --i) {
|
||||
*d++ = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
clear ();
|
||||
m_updates_enabled = true;
|
||||
}
|
||||
|
||||
|
|
@ -1084,6 +1052,48 @@ Object::clone () const
|
|||
return new img::Object (*this);
|
||||
}
|
||||
|
||||
void
|
||||
Object::clear ()
|
||||
{
|
||||
if (is_byte_data ()) {
|
||||
|
||||
if (is_color ()) {
|
||||
|
||||
for (unsigned int c = 0; c < 3; ++c) {
|
||||
unsigned char *d = mp_data->byte_data (c);
|
||||
for (size_t i = data_length (); i > 0; --i) {
|
||||
*d++ = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
unsigned char *d = mp_data->byte_data ();
|
||||
for (size_t i = data_length (); i > 0; --i) {
|
||||
*d++ = 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if (is_color ()) {
|
||||
|
||||
for (unsigned int c = 0; c < 3; ++c) {
|
||||
float *d = mp_data->float_data (c);
|
||||
for (size_t i = data_length (); i > 0; --i) {
|
||||
*d++ = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
float *d = mp_data->float_data ();
|
||||
for (size_t i = data_length (); i > 0; --i) {
|
||||
*d++ = 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
db::DPolygon
|
||||
Object::image_box_poly (const db::DBox vp, const db::DCplxTrans &vpt) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ class DataHeader;
|
|||
struct IMG_PUBLIC DataMapping
|
||||
{
|
||||
public:
|
||||
typedef std::vector< std::pair<double, std::pair<QColor, QColor> > > false_color_nodes_type;
|
||||
|
||||
/**
|
||||
* @brief The constructor
|
||||
*/
|
||||
|
|
@ -73,7 +75,7 @@ public:
|
|||
* Each node is a pair or x-value (normalized to a range of 0..1) and a corresponding color.
|
||||
* The list should have an element with x value of 0.0 and one with an x value of 1.0.
|
||||
*/
|
||||
std::vector< std::pair<double, std::pair<QColor, QColor> > > false_color_nodes;
|
||||
false_color_nodes_type false_color_nodes;
|
||||
|
||||
/**
|
||||
* @brief The brightness value
|
||||
|
|
@ -177,8 +179,9 @@ public:
|
|||
* @param h The height of the image
|
||||
* @param trans The transformation from pixel space to micron space
|
||||
* @param color True to create a color image.
|
||||
* @param byte_data True to make the image store the data in bytes
|
||||
*/
|
||||
Object (size_t w, size_t h, const db::DCplxTrans &trans, bool color);
|
||||
Object (size_t w, size_t h, const db::DCplxTrans &trans, bool color, bool byte_data);
|
||||
|
||||
/**
|
||||
* @brief Constructor for a monochrome image with the given pixel values
|
||||
|
|
@ -301,8 +304,9 @@ public:
|
|||
* @param h The height of the image
|
||||
* @param matrix The 3d transformation matrix from pixel space to micron space
|
||||
* @param color True to create a color image.
|
||||
* @param byte_data True to create n image using bytes rather than floats
|
||||
*/
|
||||
Object (size_t w, size_t h, const db::Matrix3d &matrix, bool color);
|
||||
Object (size_t w, size_t h, const db::Matrix3d &matrix, bool color, bool byte_data);
|
||||
|
||||
/**
|
||||
* @brief Constructor for a monochrome image with the given pixel values
|
||||
|
|
@ -734,6 +738,11 @@ public:
|
|||
*/
|
||||
void set_data (size_t width, size_t height, const std::vector<double> &red, const std::vector<double> &green, const std::vector<double> &blue);
|
||||
|
||||
/**
|
||||
* @brief Clears the pixel data (sets the values to 0)
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Set the transformation matrix
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,470 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "imgStream.h"
|
||||
#include "tlXMLParser.h"
|
||||
#include "tlXMLWriter.h"
|
||||
#include "tlTimer.h"
|
||||
#include "layConverters.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace img
|
||||
{
|
||||
|
||||
class ImageProxy
|
||||
{
|
||||
public:
|
||||
ImageProxy (const img::Object *img = 0)
|
||||
: mp_img (img),
|
||||
m_width (1), m_height (1),
|
||||
m_min_value (0.0), m_max_value (1.0),
|
||||
m_color (false)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
bool is_color () const
|
||||
{
|
||||
return mp_img->is_color ();
|
||||
}
|
||||
|
||||
void set_color (bool f)
|
||||
{
|
||||
m_color = f;
|
||||
}
|
||||
|
||||
size_t width () const
|
||||
{
|
||||
return mp_img->width ();
|
||||
}
|
||||
|
||||
void set_width (size_t w)
|
||||
{
|
||||
m_width = w;
|
||||
}
|
||||
|
||||
size_t height () const
|
||||
{
|
||||
return mp_img->height ();
|
||||
}
|
||||
|
||||
void set_height (size_t h)
|
||||
{
|
||||
m_height = h;
|
||||
}
|
||||
|
||||
std::list<std::string>::const_iterator begin_byte_data () const
|
||||
{
|
||||
return m_byte_data.begin ();
|
||||
}
|
||||
|
||||
std::list<std::string>::const_iterator end_byte_data () const
|
||||
{
|
||||
return m_byte_data.end ();
|
||||
}
|
||||
|
||||
void push_byte_data (const std::string &s)
|
||||
{
|
||||
m_byte_data.push_back (s);
|
||||
}
|
||||
|
||||
std::list<std::string>::const_iterator begin_data () const
|
||||
{
|
||||
return m_data.begin ();
|
||||
}
|
||||
|
||||
std::list<std::string>::const_iterator end_data () const
|
||||
{
|
||||
return m_data.end ();
|
||||
}
|
||||
|
||||
void push_data (const std::string &s)
|
||||
{
|
||||
m_data.push_back (s);
|
||||
}
|
||||
|
||||
const db::Matrix3d &matrix () const
|
||||
{
|
||||
return mp_img->matrix ();
|
||||
}
|
||||
|
||||
void set_matrix (const db::Matrix3d &m)
|
||||
{
|
||||
m_matrix = m;
|
||||
}
|
||||
|
||||
double min_value () const
|
||||
{
|
||||
return mp_img->min_value ();
|
||||
}
|
||||
|
||||
void set_min_value (double h)
|
||||
{
|
||||
m_min_value = h;
|
||||
}
|
||||
|
||||
double max_value () const
|
||||
{
|
||||
return mp_img->max_value ();
|
||||
}
|
||||
|
||||
void set_max_value (double h)
|
||||
{
|
||||
m_max_value = h;
|
||||
}
|
||||
|
||||
const img::DataMapping &data_mapping () const
|
||||
{
|
||||
return mp_img->data_mapping ();
|
||||
}
|
||||
|
||||
void set_data_mapping (const img::DataMapping &dm)
|
||||
{
|
||||
m_data_mapping = dm;
|
||||
}
|
||||
|
||||
const img::Object::landmarks_type &landmarks () const
|
||||
{
|
||||
return mp_img->landmarks ();
|
||||
}
|
||||
|
||||
void set_landmarks (const img::Object::landmarks_type &lm)
|
||||
{
|
||||
m_landmarks = lm;
|
||||
}
|
||||
|
||||
img::Object *get_image () const;
|
||||
|
||||
private:
|
||||
const img::Object *mp_img;
|
||||
|
||||
// reader mode
|
||||
size_t m_width, m_height;
|
||||
img::Object::landmarks_type m_landmarks;
|
||||
img::DataMapping m_data_mapping;
|
||||
double m_min_value, m_max_value;
|
||||
db::Matrix3d m_matrix;
|
||||
std::list<std::string> m_byte_data, m_data;
|
||||
bool m_color;
|
||||
|
||||
void init ();
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
static void
|
||||
string_to_pixels (img::Object *img, const std::string &s, size_t row, size_t w, bool color)
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
|
||||
size_t column = 0;
|
||||
while (! ex.at_end () && column < w) {
|
||||
|
||||
T1 r = 0;
|
||||
T1 g = 0;
|
||||
T1 b = 0;
|
||||
T2 m = 0;
|
||||
|
||||
unsigned int i = 0;
|
||||
bool has_mask = false;
|
||||
|
||||
while (! ex.at_end () && ! ex.test (";")) {
|
||||
|
||||
if (i == 0) {
|
||||
ex.read (r);
|
||||
} else if (color && i == 1) {
|
||||
ex.read (g);
|
||||
} else if (color && i == 2) {
|
||||
ex.read (b);
|
||||
} else {
|
||||
ex.read (m);
|
||||
has_mask = true;
|
||||
}
|
||||
++i;
|
||||
|
||||
ex.test (",");
|
||||
|
||||
}
|
||||
|
||||
if (color) {
|
||||
img->set_pixel (column, row, double (r), double (g), double (b));
|
||||
} else {
|
||||
img->set_pixel (column, row, double (r));
|
||||
}
|
||||
|
||||
if (has_mask) {
|
||||
img->set_mask (column, row, m);
|
||||
}
|
||||
|
||||
++column;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
img::Object *
|
||||
ImageProxy::get_image () const
|
||||
{
|
||||
std::auto_ptr<img::Object> img (new Object (std::max (size_t (1), m_width), std::max (size_t (1), m_height), m_matrix, m_color, ! m_byte_data.empty ()));
|
||||
img->set_min_value (m_min_value);
|
||||
img->set_max_value (m_max_value);
|
||||
img->set_data_mapping (m_data_mapping);
|
||||
img->set_landmarks (m_landmarks);
|
||||
|
||||
if (! m_byte_data.empty ()) {
|
||||
|
||||
std::list<std::string>::const_iterator s = m_byte_data.begin ();
|
||||
for (size_t i = 0; i < m_height; ++i) {
|
||||
string_to_pixels<unsigned char, unsigned char> (img.get (), *s++, i, m_width, m_color);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
std::list<std::string>::const_iterator s = m_data.begin ();
|
||||
for (size_t i = 0; i < m_height; ++i) {
|
||||
string_to_pixels<float, unsigned char> (img.get (), *s++, i, m_width, m_color);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return img.release ();
|
||||
}
|
||||
|
||||
static void add_entry (std::string &heap, const float *&b, bool &first)
|
||||
{
|
||||
if (b) {
|
||||
if (! first) {
|
||||
heap += ",";
|
||||
}
|
||||
heap += tl::to_string (*b++);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_entry (std::string &heap, const unsigned char *&b, bool &first)
|
||||
{
|
||||
if (b) {
|
||||
if (! first) {
|
||||
heap += ",";
|
||||
}
|
||||
heap += tl::to_string ((unsigned int) *b++);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
static const std::string &data_to_string (std::string &heap, size_t l, const T1 *r, const T2 *g, const T3 *b, const T4 *m)
|
||||
{
|
||||
heap.clear ();
|
||||
|
||||
while (l-- > 0) {
|
||||
bool first = true;
|
||||
add_entry (heap, r, first);
|
||||
add_entry (heap, g, first);
|
||||
add_entry (heap, b, first);
|
||||
add_entry (heap, m, first);
|
||||
if (l > 0) {
|
||||
heap += ";";
|
||||
}
|
||||
}
|
||||
|
||||
return heap;
|
||||
}
|
||||
|
||||
void
|
||||
ImageProxy::init ()
|
||||
{
|
||||
if (!mp_img) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t w = mp_img->width ();
|
||||
size_t h = mp_img->height ();
|
||||
|
||||
static std::string s;
|
||||
|
||||
if (mp_img->is_color ()) {
|
||||
|
||||
if (mp_img->is_byte_data ()) {
|
||||
|
||||
const unsigned char *r = mp_img->byte_data (0);
|
||||
const unsigned char *g = mp_img->byte_data (1);
|
||||
const unsigned char *b = mp_img->byte_data (2);
|
||||
const unsigned char *m = mp_img->mask ();
|
||||
|
||||
for (size_t i = 0; i < h; ++i) {
|
||||
m_byte_data.push_back (data_to_string (s, w, r + i * w, g + i * w, b + i * w, m ? (m + i * w) : 0));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const float *r = mp_img->float_data (0);
|
||||
const float *g = mp_img->float_data (1);
|
||||
const float *b = mp_img->float_data (2);
|
||||
const unsigned char *m = mp_img->mask ();
|
||||
|
||||
for (size_t i = 0; i < h; ++i) {
|
||||
m_data.push_back (data_to_string (s, w, r + i * w, g + i * w, b + i * w, m ? (m + i * w) : 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (mp_img->is_byte_data ()) {
|
||||
|
||||
const unsigned char *g = mp_img->byte_data ();
|
||||
const unsigned char *m = mp_img->mask ();
|
||||
|
||||
for (size_t i = 0; i < h; ++i) {
|
||||
m_byte_data.push_back (data_to_string (s, w, g + i * w, (const unsigned char *) 0, (const unsigned char *) 0, m ? (m + i * w) : 0));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const float *g = mp_img->float_data ();
|
||||
const unsigned char *m = mp_img->mask ();
|
||||
|
||||
for (size_t i = 0; i < h; ++i) {
|
||||
m_data.push_back (data_to_string (s, w, g + i * w, (const float *) 0, (const float *) 0, m ? (m + i * w) : 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
|
||||
struct PointConverter
|
||||
{
|
||||
std::string to_string (const db::DPoint &p) const
|
||||
{
|
||||
return p.to_string ();
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, db::DPoint &p) const
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
ex.read (p);
|
||||
}
|
||||
};
|
||||
|
||||
struct ColorMapConverter
|
||||
{
|
||||
std::string to_string (const std::pair<double, std::pair<QColor, QColor> > &cm) const
|
||||
{
|
||||
std::string s;
|
||||
s = tl::to_string (cm.first);
|
||||
s += ":";
|
||||
|
||||
lay::ColorConverter cc;
|
||||
s += tl::to_word_or_quoted_string (cc.to_string (cm.second.first));
|
||||
if (cm.second.first != cm.second.second) {
|
||||
s += ",";
|
||||
s += tl::to_word_or_quoted_string (cc.to_string (cm.second.second));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void from_string (const std::string &s, std::pair<double, std::pair<QColor, QColor> > &cm) const
|
||||
{
|
||||
tl::Extractor ex (s.c_str ());
|
||||
|
||||
ex.read (cm.first);
|
||||
ex.test (":");
|
||||
|
||||
lay::ColorConverter cc;
|
||||
|
||||
std::string w;
|
||||
ex.read_word_or_quoted (w);
|
||||
|
||||
cc.from_string (w, cm.second.first);
|
||||
|
||||
if (ex.test (",")) {
|
||||
|
||||
w.clear ();
|
||||
ex.read_word_or_quoted (w);
|
||||
|
||||
cc.from_string (w, cm.second.second);
|
||||
|
||||
} else {
|
||||
cm.second.second = cm.second.first;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
tl::XMLStruct<ImageProxy> s_img_structure ("image-data",
|
||||
tl::make_member (&ImageProxy::is_color, &ImageProxy::set_color, "color") +
|
||||
tl::make_member (&ImageProxy::width, &ImageProxy::set_width, "width") +
|
||||
tl::make_member (&ImageProxy::height, &ImageProxy::set_height, "height") +
|
||||
tl::make_member (&ImageProxy::matrix, &ImageProxy::set_matrix, "matrix") +
|
||||
tl::make_member (&ImageProxy::min_value, &ImageProxy::set_min_value, "min-value") +
|
||||
tl::make_member (&ImageProxy::max_value, &ImageProxy::set_max_value, "max-value") +
|
||||
tl::make_element (&ImageProxy::data_mapping, &ImageProxy::set_data_mapping, "data-mapping",
|
||||
tl::make_element (&img::DataMapping::false_color_nodes, "color-map",
|
||||
tl::make_member (&img::DataMapping::false_color_nodes_type::begin, &img::DataMapping::false_color_nodes_type::end, &img::DataMapping::false_color_nodes_type::push_back, "color-map-entry", ColorMapConverter ())
|
||||
) +
|
||||
tl::make_member (&img::DataMapping::brightness, "brightness") +
|
||||
tl::make_member (&img::DataMapping::contrast, "contrast") +
|
||||
tl::make_member (&img::DataMapping::gamma, "gamma") +
|
||||
tl::make_member (&img::DataMapping::red_gain, "red-gain") +
|
||||
tl::make_member (&img::DataMapping::green_gain, "green-gain") +
|
||||
tl::make_member (&img::DataMapping::blue_gain, "blue-gain")
|
||||
) +
|
||||
tl::make_element (&ImageProxy::landmarks, &ImageProxy::set_landmarks, "landmarks",
|
||||
tl::make_member (&img::Object::landmarks_type::begin, &img::Object::landmarks_type::end, &img::Object::landmarks_type::push_back, "landmark", PointConverter ())
|
||||
) +
|
||||
tl::make_member (&ImageProxy::begin_byte_data, &ImageProxy::end_byte_data, &ImageProxy::push_byte_data, "byte-data") +
|
||||
tl::make_member (&ImageProxy::begin_data, &ImageProxy::end_data, &ImageProxy::push_data, "data")
|
||||
);
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
img::Object *
|
||||
ImageStreamer::read (tl::InputStream &stream)
|
||||
{
|
||||
ImageProxy proxy;
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Reading image file: ")) + stream.source ());
|
||||
tl::XMLStreamSource in (stream, tl::to_string (tr ("Image file")));
|
||||
s_img_structure.parse (in, proxy);
|
||||
|
||||
return proxy.get_image ();
|
||||
}
|
||||
|
||||
void
|
||||
ImageStreamer::write (tl::OutputStream &stream, const img::Object &img)
|
||||
{
|
||||
ImageProxy proxy (&img);
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Writing image file: ")) + stream.path ());
|
||||
s_img_structure.write (stream, proxy);
|
||||
}
|
||||
|
||||
} // namespace img
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_imgStream
|
||||
#define HDR_imgStream
|
||||
|
||||
#include "imgCommon.h"
|
||||
|
||||
#include "imgObject.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace img {
|
||||
|
||||
/**
|
||||
* @brief An object streaming image data from or to files
|
||||
*/
|
||||
struct IMG_PUBLIC ImageStreamer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The constructor
|
||||
*/
|
||||
ImageStreamer () { }
|
||||
|
||||
/**
|
||||
* @brief Reads an image Object from a stream
|
||||
*
|
||||
* This method returns a new'd object. It's the responsibility of the caller to delete the object.
|
||||
*/
|
||||
static Object *read(tl::InputStream &stream);
|
||||
|
||||
/**
|
||||
* @brief Writes an image object to a stream
|
||||
*/
|
||||
static void write (tl::OutputStream &stream, const img::Object &img);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "imgStream.h"
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
TEST(1_FloatMono)
|
||||
{
|
||||
img::Object image (12, 8, db::DCplxTrans (1.5, 90.0, true, db::DVector (17, -42)), false, false);
|
||||
|
||||
image.set_min_value (-0.25);
|
||||
image.set_max_value (0.75);
|
||||
|
||||
std::vector<db::DPoint> lm;
|
||||
lm.push_back (db::DPoint (1, 2));
|
||||
lm.push_back (db::DPoint (-101, 102));
|
||||
image.set_landmarks (lm);
|
||||
|
||||
img::DataMapping dm;
|
||||
dm.blue_gain = 0.5;
|
||||
dm.green_gain = 0.75;
|
||||
dm.red_gain = 0.25;
|
||||
dm.contrast = -0.5;
|
||||
dm.gamma = 1.5;
|
||||
dm.brightness = 1.25;
|
||||
dm.false_color_nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (0, 0, 0), QColor (0, 0, 0))));
|
||||
dm.false_color_nodes.push_back (std::make_pair (0.5, std::make_pair (QColor (255, 0, 0), QColor (0, 255, 0))));
|
||||
dm.false_color_nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (255, 255, 255), QColor (255, 255, 255))));
|
||||
image.set_data_mapping (dm);
|
||||
|
||||
image.set_pixel (0, 0, 0.25);
|
||||
image.set_pixel (2, 5, 0.25);
|
||||
image.set_pixel (7, 1, 0.125);
|
||||
|
||||
std::string path = tmp_file ("tmp.lyimg");
|
||||
{
|
||||
tl::OutputFile file (path);
|
||||
tl::OutputStream stream (file);
|
||||
img::ImageStreamer::write (stream, image);
|
||||
}
|
||||
|
||||
std::auto_ptr<img::Object> read;
|
||||
|
||||
{
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream stream (file);
|
||||
read.reset (img::ImageStreamer::read (stream));
|
||||
}
|
||||
|
||||
EXPECT_EQ (image.to_string (), read->to_string ());
|
||||
}
|
||||
|
||||
TEST(2_FloatMonoWithMask)
|
||||
{
|
||||
img::Object image (12, 8, db::DCplxTrans (1.5, 90.0, true, db::DVector (17, -42)), false, false);
|
||||
|
||||
image.set_min_value (-0.25);
|
||||
image.set_max_value (0.75);
|
||||
|
||||
image.set_pixel (0, 0, 0.25);
|
||||
image.set_pixel (2, 5, 0.25);
|
||||
image.set_pixel (7, 1, 0.125);
|
||||
|
||||
image.set_mask (1, 0, 1);
|
||||
image.set_mask (1, 2, 1);
|
||||
image.set_mask (1, 3, 0);
|
||||
|
||||
std::string path = tmp_file ("tmp.lyimg");
|
||||
{
|
||||
tl::OutputFile file (path);
|
||||
tl::OutputStream stream (file);
|
||||
img::ImageStreamer::write (stream, image);
|
||||
}
|
||||
|
||||
std::auto_ptr<img::Object> read;
|
||||
|
||||
{
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream stream (file);
|
||||
read.reset (img::ImageStreamer::read (stream));
|
||||
}
|
||||
|
||||
EXPECT_EQ (image.to_string (), read->to_string ());
|
||||
}
|
||||
|
||||
TEST(3_ByteMono)
|
||||
{
|
||||
img::Object image (12, 8, db::Matrix3d (db::DCplxTrans (1.5, 90.0, true, db::DVector (17, -42))), false, true);
|
||||
|
||||
image.set_min_value (10);
|
||||
image.set_max_value (240);
|
||||
|
||||
image.set_pixel (0, 0, 50);
|
||||
image.set_pixel (2, 5, 70);
|
||||
image.set_pixel (7, 1, 120);
|
||||
|
||||
std::string path = tmp_file ("tmp.lyimg");
|
||||
{
|
||||
tl::OutputFile file (path);
|
||||
tl::OutputStream stream (file);
|
||||
img::ImageStreamer::write (stream, image);
|
||||
}
|
||||
|
||||
std::auto_ptr<img::Object> read;
|
||||
|
||||
{
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream stream (file);
|
||||
read.reset (img::ImageStreamer::read (stream));
|
||||
}
|
||||
|
||||
EXPECT_EQ (image.to_string (), read->to_string ());
|
||||
}
|
||||
|
||||
TEST(4_ByteMonoWithMask)
|
||||
{
|
||||
img::Object image (12, 8, db::DCplxTrans (1.5, 90.0, true, db::DVector (17, -42)), false, true);
|
||||
|
||||
image.set_min_value (10);
|
||||
image.set_max_value (240);
|
||||
|
||||
image.set_pixel (0, 0, 50);
|
||||
image.set_pixel (2, 5, 70);
|
||||
image.set_pixel (7, 1, 120);
|
||||
|
||||
image.set_mask (1, 0, 1);
|
||||
image.set_mask (1, 2, 1);
|
||||
image.set_mask (1, 3, 0);
|
||||
|
||||
std::string path = tmp_file ("tmp.lyimg");
|
||||
{
|
||||
tl::OutputFile file (path);
|
||||
tl::OutputStream stream (file);
|
||||
img::ImageStreamer::write (stream, image);
|
||||
}
|
||||
|
||||
std::auto_ptr<img::Object> read;
|
||||
|
||||
{
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream stream (file);
|
||||
read.reset (img::ImageStreamer::read (stream));
|
||||
}
|
||||
|
||||
EXPECT_EQ (image.to_string (), read->to_string ());
|
||||
}
|
||||
|
||||
TEST(5_FloatColor)
|
||||
{
|
||||
img::Object image (12, 8, db::DCplxTrans (1.5, 90.0, true, db::DVector (17, -42)), true, false);
|
||||
|
||||
image.set_min_value (-0.25);
|
||||
image.set_max_value (0.75);
|
||||
|
||||
image.set_pixel (0, 0, 0.25, -0.25, -0.125);
|
||||
image.set_pixel (2, 5, 0.25, 0.125, 0.625);
|
||||
image.set_pixel (7, 1, 0.125, 0.25, 0.75);
|
||||
|
||||
std::string path = tmp_file ("tmp.lyimg");
|
||||
{
|
||||
tl::OutputFile file (path);
|
||||
tl::OutputStream stream (file);
|
||||
img::ImageStreamer::write (stream, image);
|
||||
}
|
||||
|
||||
std::auto_ptr<img::Object> read;
|
||||
|
||||
{
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream stream (file);
|
||||
read.reset (img::ImageStreamer::read (stream));
|
||||
}
|
||||
|
||||
EXPECT_EQ (image.to_string (), read->to_string ());
|
||||
}
|
||||
|
||||
TEST(6_FloatColorWithMask)
|
||||
{
|
||||
img::Object image (12, 8, db::DCplxTrans (1.5, 90.0, true, db::DVector (17, -42)), true, false);
|
||||
|
||||
image.set_min_value (-0.25);
|
||||
image.set_max_value (0.75);
|
||||
|
||||
image.set_pixel (0, 0, 0.25, -0.25, -0.125);
|
||||
image.set_pixel (2, 5, 0.25, 0.125, 0.625);
|
||||
image.set_pixel (7, 1, 0.125, 0.25, 0.75);
|
||||
|
||||
image.set_mask (1, 0, 1);
|
||||
image.set_mask (1, 2, 1);
|
||||
image.set_mask (1, 3, 0);
|
||||
|
||||
std::string path = tmp_file ("tmp.lyimg");
|
||||
{
|
||||
tl::OutputFile file (path);
|
||||
tl::OutputStream stream (file);
|
||||
img::ImageStreamer::write (stream, image);
|
||||
}
|
||||
|
||||
std::auto_ptr<img::Object> read;
|
||||
|
||||
{
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream stream (file);
|
||||
read.reset (img::ImageStreamer::read (stream));
|
||||
}
|
||||
|
||||
EXPECT_EQ (image.to_string (), read->to_string ());
|
||||
}
|
||||
|
||||
TEST(7_ByteColor)
|
||||
{
|
||||
img::Object image (12, 8, db::DCplxTrans (1.5, 90.0, true, db::DVector (17, -42)), true, true);
|
||||
|
||||
image.set_min_value (10);
|
||||
image.set_max_value (240);
|
||||
|
||||
image.set_pixel (0, 0, 10, 20, 30);
|
||||
image.set_pixel (2, 5, 11, 21, 31);
|
||||
image.set_pixel (7, 1, 12, 22, 32);
|
||||
|
||||
std::string path = tmp_file ("tmp.lyimg");
|
||||
{
|
||||
tl::OutputFile file (path);
|
||||
tl::OutputStream stream (file);
|
||||
img::ImageStreamer::write (stream, image);
|
||||
}
|
||||
|
||||
std::auto_ptr<img::Object> read;
|
||||
|
||||
{
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream stream (file);
|
||||
read.reset (img::ImageStreamer::read (stream));
|
||||
}
|
||||
|
||||
EXPECT_EQ (image.to_string (), read->to_string ());
|
||||
}
|
||||
|
||||
TEST(8_ByteColorWithMask)
|
||||
{
|
||||
img::Object image (12, 8, db::DCplxTrans (1.5, 90.0, true, db::DVector (17, -42)), true, true);
|
||||
|
||||
image.set_min_value (10);
|
||||
image.set_max_value (240);
|
||||
|
||||
image.set_pixel (0, 0, 10, 20, 30);
|
||||
image.set_pixel (2, 5, 11, 21, 31);
|
||||
image.set_pixel (7, 1, 12, 22, 32);
|
||||
|
||||
image.set_mask (1, 0, 1);
|
||||
image.set_mask (1, 2, 1);
|
||||
image.set_mask (1, 3, 0);
|
||||
|
||||
std::string path = tmp_file ("tmp.lyimg");
|
||||
{
|
||||
tl::OutputFile file (path);
|
||||
tl::OutputStream stream (file);
|
||||
img::ImageStreamer::write (stream, image);
|
||||
}
|
||||
|
||||
std::auto_ptr<img::Object> read;
|
||||
|
||||
{
|
||||
tl::InputFile file (path);
|
||||
tl::InputStream stream (file);
|
||||
read.reset (img::ImageStreamer::read (stream));
|
||||
}
|
||||
|
||||
EXPECT_EQ (image.to_string (), read->to_string ());
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ static img::Object from_s (const std::string &s)
|
|||
|
||||
TEST(1)
|
||||
{
|
||||
img::Object image (12, 8, db::DCplxTrans (), false);
|
||||
img::Object image (12, 8, db::DCplxTrans (), false, false);
|
||||
|
||||
EXPECT_EQ (image.is_color (), false);
|
||||
EXPECT_EQ (image.is_byte_data (), false);
|
||||
|
|
@ -150,7 +150,7 @@ TEST(1)
|
|||
TEST(2)
|
||||
{
|
||||
for (unsigned int channel = 0; channel < 3; ++channel) {
|
||||
img::Object image (12, 8, db::DCplxTrans (), true);
|
||||
img::Object image (12, 8, db::DCplxTrans (), true, false);
|
||||
|
||||
EXPECT_EQ (image.is_color (), true);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
|
|||
|
||||
SOURCES = \
|
||||
imgObject.cc \
|
||||
imgFile.cc
|
||||
|
||||
INCLUDEPATH += $$IMG_INC $$DB_INC $$TL_INC $$LAYBASIC_INC $$GSI_INC
|
||||
DEPENDPATH += $$IMG_INC $$DB_INC $$TL_INC $$LAYBASIC_INC $$GSI_INC
|
||||
|
|
|
|||
|
|
@ -940,6 +940,15 @@ Extractor::read (unsigned int &value)
|
|||
return *this;
|
||||
}
|
||||
|
||||
Extractor &
|
||||
Extractor::read (unsigned char &value)
|
||||
{
|
||||
if (! try_read (value)) {
|
||||
error (tl::to_string (tr ("Expected an unsigned byte value")));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Extractor &
|
||||
Extractor::read (unsigned long &value)
|
||||
{
|
||||
|
|
@ -967,6 +976,15 @@ Extractor::read (double &value)
|
|||
return *this;
|
||||
}
|
||||
|
||||
Extractor &
|
||||
Extractor::read (float &value)
|
||||
{
|
||||
if (! try_read (value)) {
|
||||
error (tl::to_string (tr ("Expected a real number")));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Extractor &
|
||||
Extractor::read (int &value)
|
||||
{
|
||||
|
|
@ -1099,6 +1117,14 @@ namespace
|
|||
return tl::to_string (tr ("Range overflow on unsigned integer"));
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct overflow_msg_func<unsigned char>
|
||||
{
|
||||
std::string operator() () const
|
||||
{
|
||||
return tl::to_string (tr ("Range overflow on unsigned byte"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class T> bool
|
||||
|
|
@ -1167,6 +1193,12 @@ Extractor::try_read_unsigned_int (T &value)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Extractor::try_read (unsigned char &value)
|
||||
{
|
||||
return try_read_unsigned_int (value);
|
||||
}
|
||||
|
||||
bool
|
||||
Extractor::try_read (unsigned int &value)
|
||||
{
|
||||
|
|
@ -1202,6 +1234,19 @@ Extractor::try_read (long long &value)
|
|||
{
|
||||
return try_read_signed_int (value);
|
||||
}
|
||||
|
||||
bool
|
||||
Extractor::try_read (float &value)
|
||||
{
|
||||
double d = value;
|
||||
if (try_read (d)) {
|
||||
value = d;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Extractor::try_read (double &value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -468,6 +468,11 @@ public:
|
|||
*/
|
||||
Extractor &read (unsigned int &value);
|
||||
|
||||
/**
|
||||
* @brief Read an unsigned char int (see read of an unsigned int)
|
||||
*/
|
||||
Extractor &read (unsigned char &value);
|
||||
|
||||
/**
|
||||
* @brief Read an unsigned long (see read of an unsigned int)
|
||||
*/
|
||||
|
|
@ -483,6 +488,11 @@ public:
|
|||
*/
|
||||
Extractor &read (double &value);
|
||||
|
||||
/**
|
||||
* @brief Read a float (see read of an unsigned int)
|
||||
*/
|
||||
Extractor &read (float &value);
|
||||
|
||||
/**
|
||||
* @brief Read a signed int (see read of an unsigned int)
|
||||
*/
|
||||
|
|
@ -576,6 +586,11 @@ public:
|
|||
*/
|
||||
bool try_read (int &value);
|
||||
|
||||
/**
|
||||
* @brief Try to read an unsigned char int (see try to read an unsigned int)
|
||||
*/
|
||||
bool try_read (unsigned char &value);
|
||||
|
||||
/**
|
||||
* @brief Try to read an unsigned long (see try to read an unsigned int)
|
||||
*/
|
||||
|
|
@ -601,6 +616,11 @@ public:
|
|||
*/
|
||||
bool try_read (double &value);
|
||||
|
||||
/**
|
||||
* @brief Try to read a float (see try to read an unsigned int)
|
||||
*/
|
||||
bool try_read (float &value);
|
||||
|
||||
/**
|
||||
* @brief Try to read a boolean value (see try to read an unsigned int)
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue