This commit is contained in:
Matthias Koefferlein 2022-05-07 19:57:34 +02:00
parent 41cbef1e5a
commit 0198c7cd69
5 changed files with 181 additions and 17 deletions

View File

@ -566,7 +566,7 @@ LayoutCanvas::update_image ()
void
LayoutCanvas::free_resources ()
{
#if defined(HAVE_QT) // @@@
#if defined(HAVE_QT)
if (mp_pixmap) {
delete mp_pixmap;
mp_pixmap = 0;
@ -574,7 +574,7 @@ LayoutCanvas::free_resources ()
#endif
}
#if defined(HAVE_QT) // @@@
#if defined(HAVE_QT)
void
LayoutCanvas::paintEvent (QPaintEvent *)
{
@ -1006,7 +1006,7 @@ LayoutCanvas::screenshot ()
return img;
}
#if defined(HAVE_QT)
#if defined(HAVE_QT) // @@@
void
LayoutCanvas::resizeEvent (QResizeEvent *)
{
@ -1090,7 +1090,7 @@ LayoutCanvas::do_update_image ()
update_image ();
}
#if defined(HAVE_QT) // @@@
#if defined(HAVE_QT)
bool
LayoutCanvas::event (QEvent *e)
{

View File

@ -64,6 +64,9 @@
# include <QImageWriter>
#endif
// Enable this if you have both Qt and libpng and want to use libpng for saving images:
// #define PREFER_LIBPNG_FOR_SAVE 1
#include <limits>
namespace lay
@ -2512,7 +2515,7 @@ png_texts (const lay::LayoutViewBase *view, const db::DBox &box)
return texts;
}
#if defined(HAVE_QT)
#if defined(HAVE_QT) && !defined(PREFER_LIBPNG_FOR_SAVE)
void
LayoutViewBase::save_screenshot (const std::string &fn)
{
@ -2544,9 +2547,9 @@ LayoutViewBase::save_screenshot (const std::string &fn)
tl::DeferredMethodScheduler::execute ();
tl::OutputStream stream (fn);
// @@@ TODO: add texts
// @@@ mp_canvas->screenshot ().write_png (stream, png_texts (this, box ()));
mp_canvas->screenshot ().write_png (stream);
lay::PixelBuffer img = mp_canvas->screenshot ();
img.set_texts (png_texts (this, box ()));
img.write_png (stream);
tl::log << "Saved screen shot to " << fn;
}
@ -2596,7 +2599,7 @@ LayoutViewBase::get_image_with_options (unsigned int width, unsigned int height,
lay::PixelBuffer
LayoutViewBase::get_pixels_with_options (unsigned int width, unsigned int height, int linewidth, int oversampling, double resolution,
lay::Color background, lay::Color foreground, lay::Color active, const db::DBox &target_box)
lay::Color background, lay::Color foreground, lay::Color active, const db::DBox &target_box)
{
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Get image")));
@ -2608,7 +2611,7 @@ LayoutViewBase::get_pixels_with_options (unsigned int width, unsigned int height
lay::BitmapBuffer
LayoutViewBase::get_pixels_with_options_mono (unsigned int width, unsigned int height, int linewidth,
lay::Color background, lay::Color foreground, lay::Color active, const db::DBox &target_box)
lay::Color background, lay::Color foreground, lay::Color active, const db::DBox &target_box)
{
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Get image")));
@ -2618,7 +2621,7 @@ LayoutViewBase::get_pixels_with_options_mono (unsigned int width, unsigned int h
return mp_canvas->image_with_options_mono (width, height, linewidth, background, foreground, active, target_box);
}
#if defined(HAVE_QT)
#if defined(HAVE_QT) && !defined(PREFER_LIBPNG_FOR_SAVE)
void
LayoutViewBase::save_image (const std::string &fn, unsigned int width, unsigned int height)
{
@ -2648,19 +2651,21 @@ LayoutViewBase::save_image (const std::string &fn, unsigned int width, unsigned
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Save image")));
lay::Viewport vp (width, height, mp_canvas->viewport ().target_box ());
std::vector<std::pair<std::string, std::string> > texts = png_texts (this, vp.box ());
// Execute all deferred methods - ensure there are no pending tasks
tl::DeferredMethodScheduler::execute ();
tl::OutputStream stream (fn);
mp_canvas->image (width, height).write_png (stream);
lay::PixelBuffer img = mp_canvas->image (width, height);
std::vector<std::pair<std::string, std::string> > texts = png_texts (this, vp.box ());
img.set_texts (texts);
img.write_png (stream);
tl::log << "Saved image to " << fn;
}
#endif
#if defined(HAVE_QT)
#if defined(HAVE_QT) && !defined(PREFER_LIBPNG_FOR_SAVE)
void
LayoutViewBase::save_image_with_options (const std::string &fn,
unsigned int width, unsigned int height, int linewidth, int oversampling, double resolution,
@ -2680,7 +2685,7 @@ LayoutViewBase::save_image_with_options (const std::string &fn,
tl::DeferredMethodScheduler::execute ();
if (monochrome) {
if (! writer.write (mp_canvas->image_with_options_mono (width, height, linewidth, background.to_mono (), foreground.to_mono (), active.to_mono (), target_box).to_image ())) {
if (! writer.write (mp_canvas->image_with_options_mono (width, height, linewidth, background, foreground, active, target_box).to_image ())) {
throw tl::Exception (tl::to_string (QObject::tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
}
} else {
@ -2707,9 +2712,17 @@ LayoutViewBase::save_image_with_options (const std::string &fn,
tl::OutputStream stream (fn);
if (monochrome) {
mp_canvas->image_with_options_mono (width, height, linewidth, background.to_mono (), foreground.to_mono (), active.to_mono (), target_box).write_png (stream);
lay::BitmapBuffer img = mp_canvas->image_with_options_mono (width, height, linewidth, background, foreground, active, target_box);
img.set_texts (texts);
img.write_png (stream);
} else {
mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, background, foreground, active, target_box).write_png (stream);
lay::PixelBuffer img = mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, background, foreground, active, target_box);
img.set_texts (texts);
img.write_png (stream);
}
tl::log << "Saved image to " << fn;

View File

@ -202,6 +202,7 @@ PixelBuffer::operator= (const PixelBuffer &other)
m_height = other.m_height;
m_data = other.m_data;
m_transparent = other.m_transparent;
m_texts = other.m_texts;
}
return *this;
}
@ -232,6 +233,7 @@ PixelBuffer::swap (PixelBuffer &other)
std::swap (m_height, other.m_height);
std::swap (m_transparent, other.m_transparent);
m_data.swap (other.m_data);
m_texts.swap (other.m_texts);
}
void
@ -435,6 +437,15 @@ PixelBuffer::write_png (tl::OutputStream &output) const
png_set_IHDR (png_ptr, info_ptr, width (), height (), bd, fmt, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
std::vector<png_text> tptrs;
for (auto i = m_texts.begin (); i != m_texts.end (); ++i) {
tptrs.push_back (png_text ());
tptrs.back ().compression = PNG_TEXT_COMPRESSION_NONE;
tptrs.back ().key = const_cast<char *> (i->first.c_str ());
tptrs.back ().text = const_cast<char *> (i->second.c_str ());
}
png_set_text (png_ptr, info_ptr, tptrs.begin ().operator-> (), m_texts.size ());
png_write_info (png_ptr, info_ptr);
for (unsigned int i = 0; i < height (); ++i) {
@ -546,6 +557,7 @@ BitmapBuffer::operator= (const BitmapBuffer &other)
m_height = other.m_height;
m_stride = other.m_stride;
m_data = other.m_data;
m_texts = other.m_texts;
}
return *this;
}
@ -570,6 +582,7 @@ BitmapBuffer::swap (BitmapBuffer &other)
std::swap (m_height, other.m_height);
std::swap (m_stride, other.m_stride);
m_data.swap (other.m_data);
m_texts.swap (other.m_texts);
}
void
@ -708,6 +721,15 @@ BitmapBuffer::write_png (tl::OutputStream &output) const
png_set_IHDR (png_ptr, info_ptr, width (), height (), bd, fmt, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
std::vector<png_text> tptrs;
for (auto i = m_texts.begin (); i != m_texts.end (); ++i) {
tptrs.push_back (png_text ());
tptrs.back ().compression = PNG_TEXT_COMPRESSION_NONE;
tptrs.back ().key = const_cast<char *> (i->first.c_str ());
tptrs.back ().text = const_cast<char *> (i->second.c_str ());
}
png_set_text (png_ptr, info_ptr, tptrs.begin ().operator-> (), m_texts.size ());
png_write_info (png_ptr, info_ptr);
for (unsigned int i = 0; i < height (); ++i) {

View File

@ -258,6 +258,26 @@ public:
*/
PixelBuffer diff (const PixelBuffer &other) const;
/**
* @brief Gets the texts
*
* Texts are annotations which can be stored to PNG and back.
*/
const std::vector<std::pair<std::string, std::string> > &texts () const
{
return m_texts;
}
/**
* @brief Sets the texts
*
* Texts are annotations which can be stored to PNG and back.
*/
void set_texts (const std::vector<std::pair<std::string, std::string> > &texts)
{
m_texts = texts;
}
private:
class ImageData
{
@ -301,6 +321,7 @@ private:
unsigned int m_width, m_height;
bool m_transparent;
tl::copy_on_write_ptr<ImageData> m_data;
std::vector<std::pair<std::string, std::string> > m_texts;
};
/**
@ -466,6 +487,26 @@ public:
void write_png (tl::OutputStream &output) const;
#endif
/**
* @brief Gets the texts
*
* Texts are annotations which can be stored to PNG and back.
*/
const std::vector<std::pair<std::string, std::string> > &texts () const
{
return m_texts;
}
/**
* @brief Sets the texts
*
* Texts are annotations which can be stored to PNG and back.
*/
void set_texts (const std::vector<std::pair<std::string, std::string> > &texts)
{
m_texts = texts;
}
private:
class MonoImageData
{
@ -509,6 +550,7 @@ private:
unsigned int m_width, m_height;
unsigned int m_stride;
tl::copy_on_write_ptr<MonoImageData> m_data;
std::vector<std::pair<std::string, std::string> > m_texts;
};
}

View File

@ -236,3 +236,90 @@ TEST(13)
EXPECT_EQ (compare_images (img, au_img), true);
}
#endif
#if defined(HAVE_PNG) || defined(HAVE_QT)
TEST(21)
{
lay::LayoutView lv (0, false, 0);
lv.cell_box_color (lay::Color (0, 0, 0));
lv.load_layout (tl::testsrc () + "/testdata/gds/t10.gds", true);
std::string tmp = tmp_file ("test.png");
lv.save_image_with_options (tmp, 500, 500, 1, 1, 1.0, lay::Color (255, 255, 255), lay::Color (0, 0, 0), lay::Color (128, 128, 128), db::DBox (), false);
lay::PixelBuffer img;
{
tl::InputStream stream (tmp);
img = lay::PixelBuffer::read_png (stream);
}
tl::info << "PNG file read from " << tmp;
std::string au = tl::testsrc () + "/testdata/lay/au_lv1.png";
lay::PixelBuffer au_img;
{
tl::InputStream stream (au);
au_img = lay::PixelBuffer::read_png (stream);
}
tl::info << "PNG file read from " << au;
EXPECT_EQ (compare_images (img, au_img), true);
}
TEST(22)
{
lay::LayoutView lv (0, false, 0);
lv.full_hier_new_cell (true);
lv.load_layout (tl::testsrc () + "/testdata/gds/t10.gds", true);
std::string tmp = tmp_file ("test.png");
lv.save_image_with_options (tmp, 500, 500, 1, 1, 1.0, lay::Color (255, 255, 255), lay::Color (0, 0, 0), lay::Color (128, 128, 128), db::DBox (), false);
lay::PixelBuffer img;
{
tl::InputStream stream (tmp);
img = lay::PixelBuffer::read_png (stream);
}
tl::info << "PNG file read from " << tmp;
std::string au = tl::testsrc () + "/testdata/lay/au_lv2.png";
lay::PixelBuffer au_img;
{
tl::InputStream stream (au);
au_img = lay::PixelBuffer::read_png (stream);
}
tl::info << "PNG file read from " << au;
EXPECT_EQ (compare_images (img, au_img), true);
}
// monochrome
TEST(23)
{
lay::LayoutView lv (0, false, 0);
lv.full_hier_new_cell (true);
lv.load_layout (tl::testsrc () + "/testdata/gds/t10.gds", true);
std::string tmp = tmp_file ("test.png");
lv.save_image_with_options (tmp, 500, 500, 1, 1, 1.0, lay::Color (255, 255, 255), lay::Color (0, 0, 0), lay::Color (128, 128, 128), db::DBox (), true);
lay::BitmapBuffer img;
{
tl::InputStream stream (tmp);
img = lay::BitmapBuffer::read_png (stream);
}
tl::info << "PNG file read from " << tmp;
std::string au = tl::testsrc () + "/testdata/lay/au_lv3.png";
lay::BitmapBuffer au_img;
{
tl::InputStream stream (au);
au_img = lay::BitmapBuffer::read_png (stream);
}
tl::info << "PNG file read from " << au;
EXPECT_EQ (compare_images (img, au_img), true);
}
#endif