WIP: added new lay::Image class

This commit is contained in:
Matthias Koefferlein 2022-05-02 00:02:47 +02:00
parent e49b9a5e8a
commit 0b48cb9020
7 changed files with 446 additions and 7 deletions

View File

@ -0,0 +1,201 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "layImage.h"
#include "tlAssert.h"
namespace lay
{
Image::Image (unsigned int w, unsigned int h, lay::color_t *data)
{
m_width = w;
m_height = h;
m_data.reset (new ImageData (data, w * h));
}
Image::Image (unsigned int w, unsigned int h, const lay::color_t *data, unsigned int stride)
{
m_width = w;
m_height = h;
lay::color_t *d = new color_t [w * h];
if (data) {
for (unsigned int i = 0; i < h; ++i) {
for (unsigned int i = 0; i < h; ++i) {
*d++ = *data++;
}
if (stride > w) {
data += stride - w;
}
}
}
m_data.reset (new ImageData (d, w * h));
}
Image::Image ()
{
m_width = 0;
m_height = 0;
}
Image::Image (const Image &other)
{
operator= (other);
}
Image::Image (Image &&other)
{
swap (other);
}
Image::~Image ()
{
// .. nothing yet ..
}
Image &
Image::operator= (const Image &other)
{
if (this != &other) {
m_width = other.m_width;
m_height = other.m_height;
m_data = other.m_data;
}
return *this;
}
Image &
Image::operator= (Image &&other)
{
if (this != &other) {
swap (other);
}
return *this;
}
void
Image::swap (Image &other)
{
if (this == &other) {
return;
}
std::swap (m_width, other.m_width);
std::swap (m_height, other.m_height);
m_data.swap (other.m_data);
}
void
Image::fill (lay::color_t c)
{
color_t *d = data ();
for (unsigned int i = 0; i < m_height; ++i) {
for (unsigned int j = 0; j < m_width; ++j) {
*d++ = c;
}
}
}
color_t *
Image::scan_line (unsigned int n)
{
tl_assert (n < m_height);
return m_data->data () + n * m_width;
}
const color_t *
Image::scan_line (unsigned int n) const
{
tl_assert (n < m_height);
return m_data->data () + n * m_width;
}
color_t *
Image::data ()
{
return m_data->data ();
}
const color_t *
Image::data () const
{
return m_data->data ();
}
#if defined(HAVE_QT)
QImage
Image::to_image () const
{
return QImage ((const uchar *) data (), m_width, m_height, QImage::Format_ARGB32);
}
#endif
void
Image::patch (const Image &other)
{
tl_assert (width () == other.width ());
tl_assert (height () == other.height ());
const color_t *d = other.data ();
color_t *dd = data ();
for (unsigned int i = 0; i < m_height; ++i) {
for (unsigned int j = 0; j < m_width; ++j) {
color_t c = *d++;
if ((c & 0x80000000) != 0) {
*dd = c;
}
++dd;
}
}
}
Image
Image::diff (const Image &other) const
{
tl_assert (width () == other.width ());
tl_assert (height () == other.height ());
Image res (m_width, m_height);
const color_t *d2 = other.data ();
const color_t *d1 = data ();
color_t *dd = res.data ();
for (unsigned int i = 0; i < m_height; ++i) {
for (unsigned int j = 0; j < m_width; ++j) {
if (((*d1 ^ *d2) & 0xffffff) != 0) {
*dd++ = *d2 | 0xff000000;
} else {
*dd++ = 0;
}
++d1;
++d2;
}
}
return res;
}
}

View File

@ -0,0 +1,219 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_layImage
#define HDR_layImage
#include "laybasicCommon.h"
#include "layColor.h"
#include "tlCopyOnWrite.h"
#include <string.h>
#if defined(HAVE_QT)
# include <QImage>
#endif
namespace lay
{
/**
* @brief An 32bit RGBA image class
*
* This class substitutes QImage in Qt-less applications.
* It provides 32bit RGBA pixels with the format used by lay::Color.
*/
class LAYBASIC_PUBLIC Image
{
public:
/**
* @brief Creates an image with the given height and width
*
* If data is given, the image is initialized with the given data and will take ownership over the
* data block.
*
* The size of the data block needs to be w*h elements.
*/
Image (unsigned int w, unsigned int h, lay::color_t *data);
/**
* @brief Creates an image with the given height and width
*
* If data is given, the image is initialized with the given data. A copy of the data is created.
*
* "stride" specifies the stride (distance between two rows of data).
* The size of the data block needs to be stride*h elements or w*h if stride is not given.
*/
Image (unsigned int w, unsigned int h, const lay::color_t *data = 0, unsigned int stride = 0);
/**
* @brief Default constructor
*/
Image ();
/**
* @brief Copy constructor
*/
Image (const Image &other);
/**
* @brief Move constructor
*/
Image (Image &&other);
/**
* @brief Destructor
*/
~Image ();
/**
* @brief Assignment
*/
Image &operator= (const Image &other);
/**
* @brief Move constructor
*/
Image &operator= (Image &&other);
/**
* @brief Swaps this image with another one
*/
void swap (Image &other);
/**
* @brief Gets the images width
*/
unsigned int width () const
{
return m_width;
}
/**
* @brief Gets the images width
*/
unsigned int height () const
{
return m_height;
}
/**
* @brief Fills the image with the given color
*/
void fill (lay::color_t);
/**
* @brief Gets the scanline for row n
*/
color_t *scan_line (unsigned int n);
/**
* @brief Gets the scanline for row n (const version)
*/
const color_t *scan_line (unsigned int n) const;
/**
* @brief Gets the data pointer
*/
color_t *data ();
/**
* @brief Gets the data pointer (const version)
*/
const color_t *data () const;
#if defined(HAVE_QT)
/**
* @brief Produces a QImage object from the image
*/
QImage to_image () const;
#endif
/**
* @brief Overlays the other image with this one
*
* This feature does not implement real alpha blending. Instead all
* pixels with an alpha value >= 128 from the other image are patched into this image.
*/
void patch (const Image &other);
/**
* @brief Generates the image difference
*
* This feature produces a binary-alpha image of *this and other. The
* result can be patched into this image to render the same image than
* "other".
*
* alpha values from this and other are ignored.
*/
Image diff (const Image &other) const;
private:
class ImageData
{
public:
ImageData ()
: mp_data (0), m_length (0)
{
// .. nothing yet ..
}
ImageData (lay::color_t *data, size_t length)
: mp_data (data), m_length (length)
{
// .. nothing yet ..
}
ImageData (const ImageData &other)
{
m_length = other.length ();
mp_data = new lay::color_t [other.length ()];
memcpy (mp_data, other.data (), m_length * sizeof (lay::color_t));
}
~ImageData ()
{
delete[] mp_data;
mp_data = 0;
}
size_t length () const { return m_length; }
lay::color_t *data () { return mp_data; }
const lay::color_t *data () const { return mp_data; }
private:
lay::color_t *mp_data;
size_t m_length;
size_t m_stride;
ImageData &operator= (const ImageData &other);
};
unsigned int m_width, m_height;
tl::copy_on_write_ptr<ImageData> m_data;
};
}
#endif

View File

@ -118,6 +118,7 @@ DEFINES += MAKE_LAYBASIC_LIBRARY
layGenericSyntaxHighlighter.cc \
layGridNetConfigPage.cc \
layHierarchyControlPanel.cc \
layImage.cc \
layIndexedNetlistModel.cc \
layItemDelegates.cc \
layLayerControlPanel.cc \
@ -191,6 +192,7 @@ DEFINES += MAKE_LAYBASIC_LIBRARY
layGenericSyntaxHighlighter.h \
layGridNetConfigPage.h \
layHierarchyControlPanel.h \
layImage.h \
layIndexedNetlistModel.h \
layItemDelegates.h \
layLayerControlPanel.h \

View File

View File

@ -10,13 +10,14 @@ SOURCES = \
layAnnotationShapes.cc \
layBitmap.cc \
layBitmapsToImage.cc \
layImageTests.cc \
layColorTests.cc \
layLayerProperties.cc \
layParsedLayerSource.cc \
layRenderer.cc \
layNetlistBrowserModelTests.cc \
layNetlistBrowserTreeModelTests.cc \
layAbstractMenuTests.cc \
layNetlistBrowserTreeModelTests.cc \
layAbstractMenuTests.cc \
laySnapTests.cc
INCLUDEPATH += $$TL_INC $$LAYBASIC_INC $$DB_INC $$GSI_INC $$OUT_PWD/../laybasic

View File

@ -143,6 +143,22 @@ public:
release ();
}
/**
* @brief Swaps two pointers
*/
void swap (copy_on_write_ptr<X, Dup> &other)
{
if (this == &other) {
return;
}
tl::MutexLocker locker1 (&ms_lock);
tl::MutexLocker locker2 (&other.ms_lock);
std::swap (mp_x, other.mp_x);
std::swap (mp_holder, other.mp_holder);
}
/**
* @brief Gets a writable object
* This is when we will create a new copy if the object is shared.

View File

@ -19,6 +19,7 @@ SOURCES = \
tlFileSystemWatcherTests.cc \
tlFileUtilsTests.cc \
tlHttpStreamTests.cc \
tlImageTests.cc \
tlIncludeTests.cc \
tlInt128SupportTests.cc \
tlIntervalMapTests.cc \
@ -36,11 +37,10 @@ SOURCES = \
tlUniqueIdTests.cc \
tlListTests.cc \
tlEquivalenceClustersTests.cc \
tlUniqueNameTests.cc \
tlGlobPatternTests.cc \
tlRecipeTests.cc \
tlUriTests.cc \
tlUtilsTests.cc \
tlUniqueNameTests.cc \
tlGlobPatternTests.cc \
tlRecipeTests.cc \
tlUriTests.cc \
tlVariantTests.cc \
tlWebDAVTests.cc \
tlXMLParserTests.cc