Refactoring: substitute QImage by lay::PixelBuffer

This commit is contained in:
Matthias Koefferlein 2022-05-04 23:34:34 +02:00
parent 5fa984324e
commit 0877de73d4
16 changed files with 552 additions and 381 deletions

View File

@ -83,7 +83,7 @@ private:
// -------------------------------------------------------------
static void
draw_scanline (unsigned int level, const img::Object &image_object, QImage &qimage, int y, const db::Matrix3d &t, const db::Matrix3d &it, const db::DPoint &q1, const db::DPoint &q2)
draw_scanline (unsigned int level, const img::Object &image_object, lay::PixelBuffer &pxbuffer, int y, const db::Matrix3d &t, const db::Matrix3d &it, const db::DPoint &q1, const db::DPoint &q2)
{
double source_width = image_object.width ();
double source_height = image_object.height ();
@ -95,8 +95,8 @@ draw_scanline (unsigned int level, const img::Object &image_object, QImage &qima
std::swap (x1, x2);
}
int xstart = int (std::max (0.0, std::min (floor (x1), double (qimage.width ()))));
int xstop = int (std::max (0.0, std::min (ceil (x2) + 1.0, double (qimage.width ()))));
int xstart = int (std::max (0.0, std::min (floor (x1), double (pxbuffer.width ()))));
int xstop = int (std::max (0.0, std::min (ceil (x2) + 1.0, double (pxbuffer.width ()))));
db::DPoint p1 = it.trans (db::DPoint (xstart, y));
db::DPoint p2 = it.trans (db::DPoint (xstop, y));
@ -106,8 +106,8 @@ draw_scanline (unsigned int level, const img::Object &image_object, QImage &qima
if (level < 7 && xstop > xstart + 1 && fabs (xm - (xstart + xstop) / 2) > 1.0 && xm > xstart + 1 && xm < xstop - 1) {
draw_scanline (level + 1, image_object, qimage, y, t, it, q1, qm);
draw_scanline (level + 1, image_object, qimage, y, t, it, qm, q2);
draw_scanline (level + 1, image_object, pxbuffer, y, t, it, q1, qm);
draw_scanline (level + 1, image_object, pxbuffer, y, t, it, qm, q2);
} else {
@ -115,8 +115,8 @@ draw_scanline (unsigned int level, const img::Object &image_object, QImage &qima
double dpx = (p2.x () - p1.x ()) / double (xstop - xstart);
double dpy = (p2.y () - p1.y ()) / double (xstop - xstart);
QRgb *scanline_data = (QRgb *) qimage.scanLine (qimage.height () - y - 1) + xstart;
QRgb *pixel_data = (QRgb *) image_object.pixel_data ();
lay::color_t *scanline_data = pxbuffer.scan_line (pxbuffer.height () - y - 1) + xstart;
lay::color_t *pixel_data = (lay::color_t *) image_object.pixel_data ();
const unsigned char *mask_data = image_object.mask ();
for (int x = xstart; x < xstop; ++x) {
@ -144,15 +144,15 @@ draw_image (const img::Object &image_object, const lay::Viewport &vp, lay::ViewO
{
// TODO: currently, the images can only be rendered to a bitmap canvas ..
lay::BitmapViewObjectCanvas *bmp_canvas = dynamic_cast<lay::BitmapViewObjectCanvas *> (&canvas);
if (! bmp_canvas) {
if (! bmp_canvas || ! bmp_canvas->bg_image ()) {
return;
}
QImage &qimage = bmp_canvas->bg_image ();
lay::PixelBuffer &image = *bmp_canvas->bg_image ();
db::DBox source_image_box (0.0, 0.0, image_object.width (), image_object.height ());
// safety measure to avoid division by zero.
if (qimage.width () < 1 || qimage.height () < 1) {
if (image.width () < 1 || image.height () < 1) {
return;
}
@ -165,7 +165,7 @@ draw_image (const img::Object &image_object, const lay::Viewport &vp, lay::ViewO
db::DBox image_box = source_image_box.transformed (t);
int y1 = int (floor (std::max (0.0, image_box.bottom ())));
int y2 = int (floor (std::min (double (qimage.height ()) - 1, image_box.top ())));
int y2 = int (floor (std::min (double (image.height ()) - 1, image_box.top ())));
for (int y = y1; y <= y2; ++y) {
@ -175,7 +175,7 @@ draw_image (const img::Object &image_object, const lay::Viewport &vp, lay::ViewO
// clip the transformed scanline to the original image
std::pair<bool, db::DEdge> clipped = scanline.clipped_line (source_image_box);
if (clipped.first) {
draw_scanline (0, image_object, qimage, y, t, it, clipped.second.p1 (), clipped.second.p2 ());
draw_scanline (0, image_object, image, y, t, it, clipped.second.p1 (), clipped.second.p2 ());
}
}

View File

@ -25,11 +25,10 @@
#include "layBitmap.h"
#include "layDitherPattern.h"
#include "layLineStyles.h"
#include "layPixelBuffer.h"
#include "tlTimer.h"
#include "tlAssert.h"
#include <QMutex>
#include <QImage>
#include "tlThreads.h"
namespace lay
{
@ -422,16 +421,17 @@ static void create_precursor_bitmaps (const std::vector<lay::ViewOp> &view_ops_i
}
}
static void
bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
const std::vector<lay::Bitmap *> &pbitmaps_in,
const lay::DitherPattern &dp,
const lay::LineStyles &ls,
QImage *pimage, unsigned int width, unsigned int height,
bool use_bitmap_index,
bool transparent,
tl::Mutex *mutex)
void
bitmaps_to_image (const std::vector<lay::ViewOp> &view_ops_in,
const std::vector<lay::Bitmap *> &pbitmaps_in,
const lay::DitherPattern &dp,
const lay::LineStyles &ls,
PixelBuffer *pimage, unsigned int width, unsigned int height,
bool use_bitmap_index,
tl::Mutex *mutex)
{
bool transparent = pimage->transparent ();
std::vector<unsigned int> bm_map;
std::vector<unsigned int> vo_map;
@ -588,7 +588,7 @@ bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
if (masks.size () > 0) {
lay::color_t *pt = (lay::color_t *) pimage->scanLine (height - 1 - y);
lay::color_t *pt = (lay::color_t *) pimage->scan_line (height - 1 - y);
uint32_t *dptr_end = dptr;
unsigned int i = 0;
@ -661,14 +661,14 @@ bitmaps_to_image_rgb (const std::vector<lay::ViewOp> &view_ops_in,
delete [] buffer;
}
static void
bitmaps_to_image_mono (const std::vector<lay::ViewOp> &view_ops_in,
const std::vector<lay::Bitmap *> &pbitmaps_in,
const lay::DitherPattern &dp,
const lay::LineStyles &ls,
QImage *pimage, unsigned int width, unsigned int height,
bool use_bitmap_index,
tl::Mutex *mutex)
void
bitmaps_to_image (const std::vector<lay::ViewOp> &view_ops_in,
const std::vector<lay::Bitmap *> &pbitmaps_in,
const lay::DitherPattern &dp,
const lay::LineStyles &ls,
lay::BitmapBuffer *pimage, unsigned int width, unsigned int height,
bool use_bitmap_index,
tl::Mutex *mutex)
{
std::vector<unsigned int> bm_map;
std::vector<unsigned int> vo_map;
@ -825,7 +825,7 @@ bitmaps_to_image_mono (const std::vector<lay::ViewOp> &view_ops_in,
if (masks.size () > 0) {
lay::color_t *pt = (lay::color_t *) pimage->scanLine (height - 1 - y);
lay::color_t *pt = (lay::color_t *) pimage->scan_line (height - 1 - y);
uint32_t *dptr_end = dptr;
unsigned int i = 0;
@ -866,23 +866,6 @@ bitmaps_to_image_mono (const std::vector<lay::ViewOp> &view_ops_in,
delete [] buffer;
}
void
bitmaps_to_image (const std::vector<lay::ViewOp> &view_ops_in,
const std::vector<lay::Bitmap *> &pbitmaps_in,
const lay::DitherPattern &dp,
const lay::LineStyles &ls,
QImage *pimage, unsigned int width, unsigned int height,
bool use_bitmap_index,
tl::Mutex *mutex)
{
if (pimage->depth () <= 1) {
bitmaps_to_image_mono (view_ops_in, pbitmaps_in, dp, ls, pimage, width, height, use_bitmap_index, mutex);
} else {
bool transparent = (pimage->format () == QImage::Format_ARGB32);
bitmaps_to_image_rgb (view_ops_in, pbitmaps_in, dp, ls, pimage, width, height, use_bitmap_index, transparent, mutex);
}
}
void
bitmap_to_bitmap (const lay::ViewOp &view_op, const lay::Bitmap &bitmap,
unsigned char *data,

View File

@ -29,17 +29,17 @@
#include <vector>
class QImage;
namespace lay
{
class DitherPattern;
class LineStyles;
class Bitmap;
class PixelBuffer;
class BitmapBuffer;
/**
* @brief This function converts the given set of bitmaps to a QImage
* @brief This function converts the given set of bitmaps to a PixelBuffer
*
* This function uses the set of bitmaps in "pbitmaps" with the given set
* of view operands in "view_ops" and converts these into the QImage
@ -58,12 +58,26 @@ bitmaps_to_image (const std::vector <lay::ViewOp> &view_ops,
const std::vector <lay::Bitmap *> &pbitmaps,
const lay::DitherPattern &dp,
const lay::LineStyles &ls,
QImage *pimage, unsigned int width, unsigned int height,
lay::PixelBuffer *pimage, unsigned int width, unsigned int height,
bool use_bitmap_index,
tl::Mutex *mutex);
/**
* @brief Convert a lay::Bitmap to a unsigned char * data field to be passed to QBitmap
* @brief This function converts the given set of bitmaps to a BitmapBuffer
*
* This is the monochrome version of the previous bitmaps_to_image function.
*/
LAYBASIC_PUBLIC void
bitmaps_to_image (const std::vector <lay::ViewOp> &view_ops,
const std::vector <lay::Bitmap *> &pbitmaps,
const lay::DitherPattern &dp,
const lay::LineStyles &ls,
lay::BitmapBuffer *pimage, unsigned int width, unsigned int height,
bool use_bitmap_index,
tl::Mutex *mutex);
/**
* @brief Convert a lay::Bitmap to a unsigned char * data field to be passed to lay::BitmapBuffer
*
* This function converts the bitmap given the view_op into a raw byte data
* field that can be passed to a QBitmap constructor. The data field is not

View File

@ -26,6 +26,7 @@
#include "layConverters.h"
#include "layLayoutView.h"
#include "layFixedFont.h"
#include "layPixelBufferPainter.h"
#include "laySnap.h"
#include "dbTrans.h"
@ -206,153 +207,7 @@ GridNet::configure (const std::string &name, const std::string &value)
return taken;
}
#if defined(HAVE_QT) // @@@
class ImagePainter
{
public:
ImagePainter (lay::BitmapViewObjectCanvas &canvas)
: mp_img (&canvas.bg_image ()),
m_resolution (canvas.resolution ()), m_width (canvas.canvas_width ()), m_height (canvas.canvas_height ())
{
// .. nothing yet ..
}
void set (const db::Point &p, lay::Color c)
{
if (p.x () >= 0 && p.x () < m_width && p.y () >= 0 && p.y () < m_height) {
((unsigned int *) mp_img->scanLine (p.y ())) [p.x ()] = c.rgb ();
}
}
void draw_line (const db::Point &p1, const db::Point &p2, lay::Color c)
{
if (p1.x () == p2.x ()) {
int x = p1.x ();
int y1 = std::min (p1.y (), p2.y ());
int y2 = std::max (p1.y (), p2.y ());
if ((y2 >= 0 || y1 < m_height) && x >= 0 && x < m_width) {
y1 = std::max (y1, 0);
y2 = std::min (y2, m_height - 1);
for (int y = y1; y <= y2; ++y) {
((unsigned int *) mp_img->scanLine (y)) [x] = c.rgb ();
}
}
} else if (p1.y () == p2.y ()) {
int y = p1.y ();
int x1 = std::min (p1.x (), p2.x ());
int x2 = std::max (p1.x (), p2.x ());
if ((x2 >= 0 || x1 < m_width) && y >= 0 && y < m_height) {
x1 = std::max (x1, 0);
x2 = std::min (x2, m_width - 1);
unsigned int *sl = (unsigned int *) mp_img->scanLine (y) + x1;
for (int x = x1; x <= x2; ++x) {
*sl++ = c.rgb ();
}
}
} else {
// TODO: not implemented yet.
}
}
void fill_rect (const db::Point &p1, const db::Point &p2, lay::Color c)
{
int y1 = std::min (p1.y (), p2.y ());
int y2 = std::max (p1.y (), p2.y ());
for (int y = y1; y <= y2; ++y) {
draw_line (db::Point (p1.x (), y), db::Point (p2.x (), y), c);
}
}
void draw_rect (const db::Point &p1, const db::Point &p2, lay::Color c)
{
int y1 = std::min (p1.y (), p2.y ());
int y2 = std::max (p1.y (), p2.y ());
int x1 = std::min (p1.x (), p2.x ());
int x2 = std::max (p1.x (), p2.x ());
draw_line (db::Point (x1, y1), db::Point (x2, y1), c);
draw_line (db::Point (x1, y2), db::Point (x2, y2), c);
draw_line (db::Point (x1, y1), db::Point (x1, y2), c);
draw_line (db::Point (x2, y1), db::Point (x2, y2), c);
}
void draw_text (const char *t, const db::Point &p, lay::Color c, int halign, int valign)
{
const lay::FixedFont &ff = lay::FixedFont::get_font (m_resolution);
int x = p.x (), y = p.y ();
if (halign < 0) {
x -= ff.width () * int (strlen (t));
} else if (halign == 0) {
x -= ff.width () * int (strlen (t)) / 2;
}
if (valign < 0) {
y += ff.height ();
} else if (valign == 0) {
y += ff.height () / 2;
}
// TODO: simple implementation
for (; *t; ++t) {
unsigned char ch = *t;
if (x < -int (ff.width ()) || x >= int (mp_img->width ()) || y < 0 || y >= int (mp_img->height () + ff.height ())) {
continue;
}
if (ch < ff.first_char () || (ch - ff.first_char ()) >= ff.n_chars ()) {
continue;
}
const uint32_t *dc = ff.data () + size_t (ch - ff.first_char ()) * ff.height () * ff.stride ();
for (unsigned int i = 0; i < ff.height (); ++i, dc += ff.stride ()) {
int iy = y - ff.height () + i + 1;
if (iy >= 0 || iy < mp_img->height ()) {
uint32_t *d = (uint32_t *) mp_img->scanLine (y - ff.height () + i);
uint32_t m = 1;
int ix = x;
const uint32_t *ds = dc;
for (unsigned int j = 0; j < ff.width (); ++j, ++ix) {
if ((*ds & m) && ix >= 0 && ix < mp_img->width ()) {
d[ix] = c.rgb ();
}
m <<= 1;
// word wrap
if (m == 0) {
++ds;
m = 1;
}
}
}
}
x += ff.width ();
}
}
private:
QImage *mp_img;
double m_resolution;
int m_width, m_height;
};
#endif
void
void
GridNet::render_bg (const lay::Viewport &vp, ViewObjectCanvas &canvas)
{
if (m_visible) {
@ -377,12 +232,11 @@ GridNet::render_bg (const lay::Viewport &vp, ViewObjectCanvas &canvas)
// TODO: currently, the grid net can only be rendered to a bitmap canvas ..
BitmapViewObjectCanvas *bmp_canvas = dynamic_cast<BitmapViewObjectCanvas *> (&canvas);
if (! bmp_canvas) {
if (! bmp_canvas || ! bmp_canvas->bg_image ()) {
return;
}
#if defined(HAVE_QT) // @@@
ImagePainter painter (*bmp_canvas);
PixelBufferPainter painter (*bmp_canvas->bg_image (), bmp_canvas->canvas_width (), bmp_canvas->canvas_height (), bmp_canvas->resolution ());
db::DCplxTrans trans = vp.trans ();
db::DCplxTrans::inverse_trans trans_inv (trans.inverted ());
@ -694,7 +548,6 @@ GridNet::render_bg (const lay::Viewport &vp, ViewObjectCanvas &canvas)
}
}
#endif
}
}

View File

@ -523,7 +523,7 @@ LayerTreeModel::parent (const QModelIndex &index) const
*/
static void
single_bitmap_to_image (const lay::ViewOp &view_op, lay::Bitmap &bitmap,
QImage *pimage, const lay::DitherPattern &dither_pattern, const lay::LineStyles &line_styles,
lay::PixelBuffer *pimage, const lay::DitherPattern &dither_pattern, const lay::LineStyles &line_styles,
unsigned int width, unsigned int height)
{
std::vector <lay::ViewOp> view_ops;
@ -640,11 +640,12 @@ LayerTreeModel::icon_for_layer (const lay::LayerPropertiesConstIterator &iter, l
lay::color_t fill_color = iter->has_fill_color (true) ? iter->eff_fill_color (true) : def_color;
lay::color_t frame_color = iter->has_frame_color (true) ? iter->eff_frame_color (true) : def_color;
QImage image (w, h, QImage::Format_ARGB32);
lay::PixelBuffer image (w, h);
image.set_transparent (true);
image.fill (view->background_color ().rgb ());
// upper scanline is a dummy one
uint32_t *sl0 = (uint32_t *) image.scanLine (0);
uint32_t *sl0 = (uint32_t *) image.scan_line (0);
uint32_t transparent = QColor (Qt::transparent).rgba ();
for (size_t i = 0; i < w; ++i) {
*sl0++ = transparent;
@ -773,7 +774,7 @@ LayerTreeModel::icon_for_layer (const lay::LayerPropertiesConstIterator &iter, l
// create vertex
single_bitmap_to_image (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, iter->marked (true) ? 9/*mark size*/ : 0), vertex, &image, view->dither_pattern (), view->line_styles (), w, h);
QPixmap pixmap = QPixmap::fromImage (image); // Qt 4.6.0 workaround
QPixmap pixmap = QPixmap::fromImage (image.to_image ()); // Qt 4.6.0 workaround
return QIcon (pixmap);
}

View File

@ -136,17 +136,16 @@ std::string ImageCacheEntry::to_string () const
// ----------------------------------------------------------------------------
#if defined(HAVE_QT) // @@@
static void
blowup (const QImage &src, QImage &dest, unsigned int os)
blowup (const lay::PixelBuffer &src, lay::PixelBuffer &dest, unsigned int os)
{
unsigned int ymax = src.height ();
unsigned int xmax = src.width ();
for (unsigned int y = 0; y < ymax; ++y) {
for (unsigned int i = 0; i < os; ++i) {
const uint32_t *psrc = (const uint32_t *) src.scanLine (y);
uint32_t *pdest = (uint32_t *) dest.scanLine (y * os + i);
const uint32_t *psrc = (const uint32_t *) src.scan_line (y);
uint32_t *pdest = (uint32_t *) dest.scan_line (y * os + i);
for (unsigned int x = 0; x < xmax; ++x) {
for (unsigned int j = 0; j < os; ++j) {
*pdest++ = *psrc;
@ -158,7 +157,7 @@ blowup (const QImage &src, QImage &dest, unsigned int os)
}
static void
subsample (const QImage &src, QImage &dest, unsigned int os, double g)
subsample (const lay::PixelBuffer &src, lay::PixelBuffer &dest, unsigned int os, double g)
{
// TODO: this is probably not compatible with the endianess of SPARC ..
@ -203,7 +202,7 @@ subsample (const QImage &src, QImage &dest, unsigned int os, double g)
{
const unsigned char *psrc = src.scanLine (y * os);
const unsigned char *psrc = (const unsigned char *) src.scan_line (y * os);
unsigned short *pdest = buffer;
for (unsigned int x = 0; x < xmax; ++x) {
@ -230,7 +229,7 @@ subsample (const QImage &src, QImage &dest, unsigned int os, double g)
for (unsigned int i = 1; i < os; ++i) {
const unsigned char *psrc = src.scanLine (y * os + i);
const unsigned char *psrc = (const unsigned char *) src.scan_line (y * os + i);
unsigned short *pdest = buffer;
for (unsigned int x = 0; x < xmax; ++x) {
@ -251,7 +250,7 @@ subsample (const QImage &src, QImage &dest, unsigned int os, double g)
{
unsigned char *pdest = dest.scanLine (y);
unsigned char *pdest = (unsigned char *) dest.scan_line (y);
const unsigned short *psrc = buffer;
for (unsigned int x = 0; x < xmax; ++x) {
@ -279,9 +278,7 @@ invert (unsigned char *data, unsigned int width, unsigned int height)
}
}
}
#endif
#if defined(HAVE_QT) // @@@
LayoutCanvas::LayoutCanvas (QWidget *parent, lay::LayoutViewBase *view, const char *name)
: lay::ViewObjectWidget (parent, name),
mp_view (view),
@ -296,25 +293,11 @@ LayoutCanvas::LayoutCanvas (QWidget *parent, lay::LayoutViewBase *view, const ch
m_do_update_image_dm (this, &LayoutCanvas::do_update_image),
m_do_end_of_drawing_dm (this, &LayoutCanvas::do_end_of_drawing),
m_image_cache_size (1)
#else
LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view)
: lay::ViewObjectWidget (),
mp_view (view),
// @@@ mp_image (0), mp_image_bg (0), mp_pixmap (0),
m_background (0), m_foreground (0), m_active (0),
m_oversampling (1),
m_dpr (1),
m_need_redraw (false),
m_redraw_clearing (false),
m_redraw_force_update (true),
m_update_image (true),
m_do_update_image_dm (this, &LayoutCanvas::do_update_image),
m_do_end_of_drawing_dm (this, &LayoutCanvas::do_end_of_drawing),
m_image_cache_size (1)
#endif
{
#if defined(HAVE_QT)
#if QT_VERSION > 0x050000
m_dpr = devicePixelRatio ();
#endif
#endif
// The gamma value used for subsampling: something between 1.8 and 2.2.
@ -326,12 +309,14 @@ LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view)
mp_redraw_thread = new lay::RedrawThread (this, view);
#if defined(HAVE_QT) // @@@
#if defined(HAVE_QT)
setBackgroundRole (QPalette::NoRole);
set_colors (lay::Color (palette ().color (QPalette::Normal, QPalette::Window).rgb ()),
lay::Color (palette ().color (QPalette::Normal, QPalette::Text).rgb ()),
lay::Color (palette ().color (QPalette::Normal, QPalette::Mid).rgb ()));
setAttribute (Qt::WA_NoSystemBackground);
#else
set_colors (0xffffffff, 0xff000000, 0xffc0c0c0);
#endif
}
@ -340,7 +325,6 @@ LayoutCanvas::~LayoutCanvas ()
// Detach all listeners so we don't trigger events in the destructor
viewport_changed_event.clear ();
#if defined(HAVE_QT) // @@@
if (mp_image) {
delete mp_image;
mp_image = 0;
@ -349,6 +333,7 @@ LayoutCanvas::~LayoutCanvas ()
delete mp_image_bg;
mp_image_bg = 0;
}
#if defined(HAVE_QT)
if (mp_pixmap) {
delete mp_pixmap;
mp_pixmap = 0;
@ -415,12 +400,10 @@ LayoutCanvas::set_colors (lay::Color background, lay::Color foreground, lay::Col
m_active = active.rgb ();
// force regeneration of background image ..
#if defined(HAVE_QT) // @@@
if (mp_image_bg) {
delete mp_image_bg;
}
mp_image_bg = 0;
#endif
update_image ();
}
@ -459,17 +442,13 @@ LayoutCanvas::prepare_drawing ()
BitmapViewObjectCanvas::set_size (m_viewport_l.width (), m_viewport_l.height (), 1.0 / double (m_oversampling * m_dpr));
#if defined(HAVE_QT) // @@@
if (! mp_image ||
(unsigned int) mp_image->width () != m_viewport_l.width () ||
(unsigned int) mp_image->height () != m_viewport_l.height ()) {
if (mp_image) {
delete mp_image;
}
mp_image = new QImage (m_viewport_l.width (), m_viewport_l.height (), QImage::Format_RGB32);
#if QT_VERSION > 0x050000
mp_image->setDevicePixelRatio (double (m_dpr));
#endif
mp_image = new lay::PixelBuffer (m_viewport_l.width (), m_viewport_l.height ());
if (mp_pixmap) {
delete mp_pixmap;
mp_pixmap = 0;
@ -477,7 +456,6 @@ LayoutCanvas::prepare_drawing ()
}
mp_image->fill (m_background);
#endif
// Cancel any pending "finish" event so there is no race between finish and restart (important for caching)
m_do_end_of_drawing_dm.cancel ();
@ -613,7 +591,7 @@ LayoutCanvas::paintEvent (QPaintEvent *)
if (mp_image_bg) {
delete mp_image_bg;
}
mp_image_bg = new QImage (*mp_image);
mp_image_bg = new lay::PixelBuffer (*mp_image);
} else {
// else reuse the saved image
@ -636,8 +614,8 @@ LayoutCanvas::paintEvent (QPaintEvent *)
// and static foreground objects
if (! mp_pixmap || needs_update_static () ||
mp_image->size ().width () != mp_pixmap->size ().width () * int (m_oversampling) ||
mp_image->size ().height () != mp_pixmap->size ().height () * int (m_oversampling)) {
int (mp_image->width ()) != mp_pixmap->size ().width () * int (m_oversampling) ||
int (mp_image->height ()) != mp_pixmap->size ().height () * int (m_oversampling)) {
if (mp_pixmap) {
delete mp_pixmap;
@ -650,36 +628,45 @@ LayoutCanvas::paintEvent (QPaintEvent *)
if (fg_bitmaps () > 0) {
QImage full_image (*mp_image);
#if QT_VERSION > 0x050000
full_image.setDevicePixelRatio (double (m_dpr));
#endif
lay::PixelBuffer full_image (*mp_image);
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
// render the foreground parts ..
if (m_oversampling == 1) {
*mp_pixmap = QPixmap::fromImage (full_image); // Qt 4.6.0 workaround
} else {
QImage subsampled_image (m_viewport.width (), m_viewport.height (), mp_image->format ());
QImage img = full_image.to_image ();
#if QT_VERSION > 0x050000
subsampled_image.setDevicePixelRatio (double (m_dpr));
img.setDevicePixelRatio (double (m_dpr));
#endif
*mp_pixmap = QPixmap::fromImage (img); // Qt 4.6.0 workaround
} else {
lay::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
subsampled_image.set_transparent (mp_image->transparent ());
subsample (full_image, subsampled_image, m_oversampling, m_gamma);
*mp_pixmap = QPixmap::fromImage (subsampled_image); // Qt 4.6.0 workaround
QImage img = subsampled_image.to_image ();
#if QT_VERSION > 0x050000
img.setDevicePixelRatio (double (m_dpr));
#endif
*mp_pixmap = QPixmap::fromImage (img); // Qt 4.6.0 workaround
}
} else if (m_oversampling == 1) {
*mp_pixmap = QPixmap::fromImage (*mp_image);
QImage img = mp_image->to_image ();
#if QT_VERSION > 0x050000
img.setDevicePixelRatio (double (m_dpr));
#endif
*mp_pixmap = QPixmap::fromImage (img);
} else {
QImage subsampled_image (m_viewport.width (), m_viewport.height (), mp_image->format ());
#if QT_VERSION > 0x050000
subsampled_image.setDevicePixelRatio (double (m_dpr));
#endif
lay::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
subsampled_image.set_transparent (mp_image->transparent ());
subsample (*mp_image, subsampled_image, m_oversampling, m_gamma);
*mp_pixmap = QPixmap::fromImage (subsampled_image);
QImage img = subsampled_image.to_image ();
#if QT_VERSION > 0x050000
img.setDevicePixelRatio (double (m_dpr));
#endif
*mp_pixmap = QPixmap::fromImage (img);
}
@ -697,24 +684,28 @@ LayoutCanvas::paintEvent (QPaintEvent *)
if (fg_bitmaps () > 0) {
QImage full_image (mp_image->size ().width (), mp_image->size ().height (), QImage::Format_ARGB32);
lay::PixelBuffer full_image (mp_image->width (), mp_image->height ());
full_image.set_transparent (true);
full_image.fill (0);
#if QT_VERSION > 0x050000
full_image.setDevicePixelRatio (double (m_dpr));
#endif
bitmaps_to_image (fg_view_op_vector (), fg_bitmap_vector (), dither_pattern (), line_styles (), &full_image, m_viewport_l.width (), m_viewport_l.height (), false, &m_mutex);
// render the foreground parts ..
if (m_oversampling == 1) {
painter.drawPixmap (QPoint (0, 0), QPixmap::fromImage (full_image));
} else {
QImage subsampled_image (m_viewport.width (), m_viewport.height (), QImage::Format_ARGB32);
QImage img = full_image.to_image ();
#if QT_VERSION > 0x050000
subsampled_image.setDevicePixelRatio (double (m_dpr));
img.setDevicePixelRatio (double (m_dpr));
#endif
painter.drawPixmap (QPoint (0, 0), QPixmap::fromImage (img));
} else {
lay::PixelBuffer subsampled_image (m_viewport.width (), m_viewport.height ());
subsampled_image.set_transparent (true);
subsample (full_image, subsampled_image, m_oversampling, m_gamma);
painter.drawPixmap (QPoint (0, 0), QPixmap::fromImage (subsampled_image));
QImage img = subsampled_image.to_image ();
#if QT_VERSION > 0x050000
img.setDevicePixelRatio (double (m_dpr));
#endif
painter.drawPixmap (QPoint (0, 0), QPixmap::fromImage (img));
}
}
@ -731,20 +722,20 @@ LayoutCanvas::paintEvent (QPaintEvent *)
}
#endif
#if defined(HAVE_QT) // @@@
class DetachedViewObjectCanvas
: public BitmapViewObjectCanvas
{
public:
DetachedViewObjectCanvas (lay::Color bg, lay::Color fg, lay::Color ac, unsigned int width_l, unsigned int height_l, double resolution, QImage *img)
DetachedViewObjectCanvas (lay::Color bg, lay::Color fg, lay::Color ac, unsigned int width_l, unsigned int height_l, double resolution, lay::PixelBuffer *img)
: BitmapViewObjectCanvas (width_l, height_l, resolution),
m_bg (bg), m_fg (fg), m_ac (ac), mp_image (img)
{
// TODO: Good choice?
m_gamma = 2.0;
if (img->width () != int (width_l) || img->height () != int (height_l)) {
mp_image_l = new QImage (width_l, height_l, img->format ());
if (img->width () != width_l || img->height () != height_l) {
mp_image_l = new lay::PixelBuffer (width_l, height_l);
mp_image_l->set_transparent (img->transparent ());
mp_image_l->fill (bg.rgb ());
} else {
mp_image_l = 0;
@ -776,9 +767,9 @@ public:
return m_ac;
}
virtual QImage &bg_image ()
virtual lay::PixelBuffer *bg_image ()
{
return mp_image_l ? *mp_image_l : *mp_image;
return mp_image_l ? mp_image_l : mp_image;
}
void transfer_to_image (const lay::DitherPattern &dp, const lay::LineStyles &ls, unsigned int width, unsigned int height)
@ -804,23 +795,61 @@ public:
private:
lay::Color m_bg, m_fg, m_ac;
QImage *mp_image;
QImage *mp_image_l;
lay::PixelBuffer *mp_image;
lay::PixelBuffer *mp_image_l;
double m_gamma;
};
#endif
#if defined(HAVE_QT) // @@@
QImage
/**
* @brief A simplistic monochrome canvas
*
* NOTE: this canvas does not support background painting (currently the background objects
* do not support monochrome background painting anyway).
* Nor does it support subsampling (that would mean grayscale).
*/
class DetachedViewObjectCanvasMono
: public BitmapViewObjectCanvas
{
public:
DetachedViewObjectCanvasMono (bool bg, bool fg, bool ac, unsigned int width, unsigned int height)
: BitmapViewObjectCanvas (width, height, 1.0),
m_bg (bg), m_fg (fg), m_ac (ac)
{
// .. nothing yet ..
}
~DetachedViewObjectCanvasMono ()
{
clear_fg_bitmaps ();
}
lay::Color background_color () const
{
return m_bg ? 0xffffffff : 0;
}
lay::Color foreground_color () const
{
return m_fg ? 0xffffffff : 0;
}
lay::Color active_color () const
{
return m_ac ? 0xffffffff : 0;
}
private:
bool m_bg, m_fg, m_ac;
};
lay::PixelBuffer
LayoutCanvas::image (unsigned int width, unsigned int height)
{
return image_with_options (width, height, -1, -1, -1.0, lay::Color (), lay::Color (), lay::Color (), db::DBox (), false);
return image_with_options (width, height, -1, -1, -1.0, lay::Color (), lay::Color (), lay::Color (), db::DBox ());
}
#endif
#if defined(HAVE_QT) // @@@
QImage
LayoutCanvas::image_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, bool is_mono)
lay::PixelBuffer
LayoutCanvas::image_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)
{
if (oversampling <= 0) {
oversampling = m_oversampling;
@ -842,19 +871,14 @@ LayoutCanvas::image_with_options (unsigned int width, unsigned int height, int l
}
// TODO: for other architectures MonoLSB may not be the right format
QImage img (width, height, is_mono ? QImage::Format_MonoLSB : QImage::Format_RGB32);
lay::PixelBuffer img (width, height);
// this may happen for BIG images:
if (img.width () != int (width) || img.height () != int (height)) {
throw tl::Exception (tl::to_string (QObject::tr ("Unable to create an image with size %dx%d pixels")), width, height);
if (img.width () != width || img.height () != height) {
throw tl::Exception (tl::to_string (tr ("Unable to create an image with size %dx%d pixels")), width, height);
}
if (is_mono) {
// in mono mode the background's color is white for green > 128 and black otherwise
img.fill ((background.rgb () & 0x8000) >> 15);
} else {
img.fill (background.rgb ());
}
img.fill (background.rgb ());
// provide canvas objects for the layout bitmaps and the foreground/background objects
BitmapRedrawThreadCanvas rd_canvas;
@ -882,43 +906,71 @@ LayoutCanvas::image_with_options (unsigned int width, unsigned int height, int l
redraw_thread.stop (); // safety
// paint the background objects. It uses "img" to paint on.
if (! is_mono) {
do_render_bg (vp, vo_canvas);
do_render_bg (vp, vo_canvas);
// paint the layout bitmaps
rd_canvas.to_image (view_ops, dither_pattern (), line_styles (), background, foreground, active, this, *vo_canvas.bg_image (), vp.width (), vp.height ());
// paint the layout bitmaps
rd_canvas.to_image (view_ops, dither_pattern (), line_styles (), background, foreground, active, this, vo_canvas.bg_image (), vp.width (), vp.height ());
// subsample current image to provide the background for the foreground objects
vo_canvas.make_background ();
// subsample current image to provide the background for the foreground objects
vo_canvas.make_background ();
// render the foreground parts ..
do_render (vp, vo_canvas, true);
vo_canvas.transfer_to_image (dither_pattern (), line_styles (), width, height);
// render the foreground parts ..
do_render (vp, vo_canvas, true);
vo_canvas.transfer_to_image (dither_pattern (), line_styles (), width, height);
do_render (vp, vo_canvas, false);
vo_canvas.transfer_to_image (dither_pattern (), line_styles (), width, height);
} else {
// TODO: Painting of background objects???
// paint the layout bitmaps
rd_canvas.to_image (view_ops, dither_pattern (), line_styles (), background, foreground, active, this, vo_canvas.bg_image (), vp.width (), vp.height ());
}
do_render (vp, vo_canvas, false);
vo_canvas.transfer_to_image (dither_pattern (), line_styles (), width, height);
return img;
}
#endif
#if defined(HAVE_QT) // @@@
QImage
lay::BitmapBuffer
LayoutCanvas::image_with_options_mono (unsigned int width, unsigned int height, int linewidth, bool background, bool foreground, bool active, const db::DBox &target_box)
{
if (linewidth <= 0) {
linewidth = 1;
}
// provide canvas objects for the layout bitmaps and the foreground/background objects
BitmapRedrawThreadCanvas rd_canvas;
DetachedViewObjectCanvasMono vo_canvas (background, foreground, active, width, height);
// compute the new viewport
db::DBox tb (target_box);
if (tb.empty ()) {
tb = m_viewport.target_box ();
}
Viewport vp (width, height, tb);
vp.set_global_trans (m_viewport.global_trans ());
std::vector<lay::ViewOp> view_ops (m_view_ops);
if (linewidth > 1) {
for (std::vector<lay::ViewOp>::iterator vo = view_ops.begin (); vo != view_ops.end (); ++vo) {
vo->width (std::min (31, vo->width () * linewidth));
}
}
lay::RedrawThread redraw_thread (&rd_canvas, mp_view);
// render the layout
redraw_thread.start (0 /*synchronous*/, m_layers, vp, 1.0, true);
redraw_thread.stop (); // safety
lay::BitmapBuffer img (width, height);
img.fill (background);
rd_canvas.to_image_mono (view_ops, dither_pattern (), line_styles (), background, foreground, active, this, img, vp.width (), vp.height ());
return img;
}
lay::PixelBuffer
LayoutCanvas::screenshot ()
{
// if required, start the redraw thread ..
prepare_drawing ();
QImage img (m_viewport.width (), m_viewport.height (), QImage::Format_RGB32);
lay::PixelBuffer img (m_viewport.width (), m_viewport.height ());
img.fill (m_background);
DetachedViewObjectCanvas vo_canvas (background_color (), foreground_color (), active_color (), m_viewport_l.width (), m_viewport_l.height (), 1.0 / double (m_oversampling * m_dpr), &img);
@ -927,7 +979,7 @@ LayoutCanvas::screenshot ()
do_render_bg (m_viewport_l, vo_canvas);
// paint the layout bitmaps
to_image (m_view_ops, dither_pattern (), line_styles (), background_color (), foreground_color (), active_color (), this, vo_canvas.bg_image (), m_viewport_l.width (), m_viewport_l.height ());
to_image (m_view_ops, dither_pattern (), line_styles (), background_color (), foreground_color (), active_color (), this, *vo_canvas.bg_image (), m_viewport_l.width (), m_viewport_l.height ());
// subsample current image to provide the background for the foreground objects
vo_canvas.make_background ();
@ -941,7 +993,6 @@ LayoutCanvas::screenshot ()
return img;
}
#endif
#if defined(HAVE_QT)
void
@ -1036,7 +1087,7 @@ LayoutCanvas::event (QEvent *e)
// GTF probe event
// record the contents (the screenshot) as ASCII text
if (gtf::Recorder::instance () && gtf::Recorder::instance ()->recording ()) {
gtf::Recorder::instance ()->probe (this, gtf::image_to_variant (screenshot ()));
gtf::Recorder::instance ()->probe (this, gtf::image_to_variant (screenshot ().to_image_copy ()));
}
e->accept ();

View File

@ -170,11 +170,10 @@ public:
return m_view_ops;
}
#if defined(HAVE_QT) // @@@
QImage screenshot ();
QImage image (unsigned int width, unsigned int height);
QImage image_with_options (unsigned int width, unsigned int height, int linewidth, int oversampling, double resolution, lay::Color background, lay::Color foreground, lay::Color active_color, const db::DBox &target_box, bool monochrome);
#endif
lay::PixelBuffer screenshot ();
lay::PixelBuffer image (unsigned int width, unsigned int height);
lay::PixelBuffer image_with_options (unsigned int width, unsigned int height, int linewidth, int oversampling, double resolution, lay::Color background, lay::Color foreground, lay::Color active_color, const db::DBox &target_box);
lay::BitmapBuffer image_with_options_mono (unsigned int width, unsigned int height, int linewidth, bool background, bool foreground, bool active_color, const db::DBox &target_box);
void update_image ();
@ -316,15 +315,13 @@ public:
return lay::Color (m_active);
}
#if defined(HAVE_QT) // @@@
/**
* @brief Reimplementation of ViewObjectCanvas: background image
*/
QImage &bg_image ()
lay::PixelBuffer *bg_image ()
{
return *mp_image;
return mp_image;
}
#endif
/**
* @brief Reimplementation of RedrawThreadCanvas: signal end of drawing
@ -362,9 +359,9 @@ public:
private:
lay::LayoutViewBase *mp_view;
lay::PixelBuffer *mp_image;
lay::PixelBuffer *mp_image_bg;
#if defined(HAVE_QT) // @@@
QImage *mp_image;
QImage *mp_image_bg;
QPixmap *mp_pixmap;
#endif
db::DBox m_precious_box;

View File

@ -2452,7 +2452,7 @@ LayoutViewBase::init_layer_properties (LayerProperties &p, const LayerProperties
p.set_marked (false);
}
#if defined(HAVE_QT)
#if defined(HAVE_QT) // @@@ add methods without QImage!!!!
QImage
LayoutViewBase::get_screenshot ()
{
@ -2461,7 +2461,7 @@ LayoutViewBase::get_screenshot ()
// Execute all deferred methods - ensure there are no pending tasks
tl::DeferredMethodScheduler::execute ();
return mp_canvas->screenshot ();
return mp_canvas->screenshot ().to_image_copy ();
}
void
@ -2491,7 +2491,7 @@ LayoutViewBase::save_screenshot (const std::string &fn)
// Execute all deferred methods - ensure there are no pending tasks
tl::DeferredMethodScheduler::execute ();
if (! writer.write (mp_canvas->screenshot ())) {
if (! writer.write (mp_canvas->screenshot ().to_image ())) {
throw tl::Exception (tl::to_string (QObject::tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
}
@ -2506,19 +2506,23 @@ LayoutViewBase::get_image (unsigned int width, unsigned int height)
// Execute all deferred methods - ensure there are no pending tasks
tl::DeferredMethodScheduler::execute ();
return mp_canvas->image (width, height);
return mp_canvas->image (width, height).to_image_copy ();
}
QImage
LayoutViewBase::get_image_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, bool monochrome)
lay::Color background, lay::Color foreground, lay::Color active, const db::DBox &target_box, bool monochrome)
{
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Save image")));
// Execute all deferred methods - ensure there are no pending tasks
tl::DeferredMethodScheduler::execute ();
return mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, background, foreground, active, target_box, monochrome);
if (monochrome) {
return mp_canvas->image_with_options_mono (width, height, linewidth, background.green () >= 128, foreground.green () >= 128, active.green () >= 128, target_box).to_image_copy ();
} else {
return mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, background, foreground, active, target_box).to_image_copy ();
}
}
void
@ -2544,7 +2548,7 @@ LayoutViewBase::save_image (const std::string &fn, unsigned int width, unsigned
// Execute all deferred methods - ensure there are no pending tasks
tl::DeferredMethodScheduler::execute ();
if (! writer.write (mp_canvas->image (width, height))) {
if (! writer.write (mp_canvas->image (width, height).to_image ())) {
throw tl::Exception (tl::to_string (QObject::tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
}
@ -2575,9 +2579,15 @@ LayoutViewBase::save_image_with_options (const std::string &fn,
// Execute all deferred methods - ensure there are no pending tasks
tl::DeferredMethodScheduler::execute ();
if (! writer.write (mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, background, foreground, active, target_box, monochrome))) {
throw tl::Exception (tl::to_string (QObject::tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
if (monochrome) {
if (! writer.write (mp_canvas->image_with_options_mono (width, height, linewidth, background.green () >= 128, foreground.green () >= 128, active.green () >= 128, 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 {
if (! writer.write (mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, 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 ()));
}
}
tl::log << "Saved screen shot to " << fn;
@ -2741,7 +2751,6 @@ LayoutViewBase::reload_layout (unsigned int cv_index)
set_properties (new_props);
goto_view (state);
}
unsigned int

View File

@ -0,0 +1,171 @@
/*
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 "layPixelBufferPainter.h"
#include "layFixedFont.h"
#include "layPixelBuffer.h"
namespace lay
{
PixelBufferPainter::PixelBufferPainter (lay::PixelBuffer &img, unsigned int width, unsigned int height, double resolution)
: mp_img (&img),
m_resolution (resolution), m_width (width), m_height (height)
{
// .. nothing yet ..
}
void
PixelBufferPainter::set (const db::Point &p, lay::Color c)
{
if (p.x () >= 0 && p.x () < m_width && p.y () >= 0 && p.y () < m_height) {
((unsigned int *) mp_img->scan_line (p.y ())) [p.x ()] = c.rgb ();
}
}
void
PixelBufferPainter::draw_line (const db::Point &p1, const db::Point &p2, lay::Color c)
{
if (p1.x () == p2.x ()) {
int x = p1.x ();
int y1 = std::min (p1.y (), p2.y ());
int y2 = std::max (p1.y (), p2.y ());
if ((y2 >= 0 || y1 < m_height) && x >= 0 && x < m_width) {
y1 = std::max (y1, 0);
y2 = std::min (y2, m_height - 1);
for (int y = y1; y <= y2; ++y) {
((unsigned int *) mp_img->scan_line (y)) [x] = c.rgb ();
}
}
} else if (p1.y () == p2.y ()) {
int y = p1.y ();
int x1 = std::min (p1.x (), p2.x ());
int x2 = std::max (p1.x (), p2.x ());
if ((x2 >= 0 || x1 < m_width) && y >= 0 && y < m_height) {
x1 = std::max (x1, 0);
x2 = std::min (x2, m_width - 1);
unsigned int *sl = (unsigned int *) mp_img->scan_line (y) + x1;
for (int x = x1; x <= x2; ++x) {
*sl++ = c.rgb ();
}
}
} else {
// TODO: not implemented yet.
}
}
void
PixelBufferPainter::fill_rect (const db::Point &p1, const db::Point &p2, lay::Color c)
{
int y1 = std::min (p1.y (), p2.y ());
int y2 = std::max (p1.y (), p2.y ());
for (int y = y1; y <= y2; ++y) {
draw_line (db::Point (p1.x (), y), db::Point (p2.x (), y), c);
}
}
void
PixelBufferPainter::draw_rect (const db::Point &p1, const db::Point &p2, lay::Color c)
{
int y1 = std::min (p1.y (), p2.y ());
int y2 = std::max (p1.y (), p2.y ());
int x1 = std::min (p1.x (), p2.x ());
int x2 = std::max (p1.x (), p2.x ());
draw_line (db::Point (x1, y1), db::Point (x2, y1), c);
draw_line (db::Point (x1, y2), db::Point (x2, y2), c);
draw_line (db::Point (x1, y1), db::Point (x1, y2), c);
draw_line (db::Point (x2, y1), db::Point (x2, y2), c);
}
void
PixelBufferPainter::draw_text (const char *t, const db::Point &p, lay::Color c, int halign, int valign)
{
const lay::FixedFont &ff = lay::FixedFont::get_font (m_resolution);
int x = p.x (), y = p.y ();
if (halign < 0) {
x -= ff.width () * int (strlen (t));
} else if (halign == 0) {
x -= ff.width () * int (strlen (t)) / 2;
}
if (valign < 0) {
y += ff.height ();
} else if (valign == 0) {
y += ff.height () / 2;
}
// TODO: simple implementation
for (; *t; ++t) {
unsigned char ch = *t;
if (x < -int (ff.width ()) || x >= int (mp_img->width ()) || y < 0 || y >= int (mp_img->height () + ff.height ())) {
continue;
}
if (ch < ff.first_char () || (ch - ff.first_char ()) >= ff.n_chars ()) {
continue;
}
const uint32_t *dc = ff.data () + size_t (ch - ff.first_char ()) * ff.height () * ff.stride ();
for (unsigned int i = 0; i < ff.height (); ++i, dc += ff.stride ()) {
int iy = y - ff.height () + i + 1;
if (iy >= 0 || iy < int (mp_img->height ())) {
uint32_t *d = (uint32_t *) mp_img->scan_line (y - ff.height () + i);
uint32_t m = 1;
int ix = x;
const uint32_t *ds = dc;
for (unsigned int j = 0; j < ff.width (); ++j, ++ix) {
if ((*ds & m) && ix >= 0 && ix < int (mp_img->width ())) {
d[ix] = c.rgb ();
}
m <<= 1;
// word wrap
if (m == 0) {
++ds;
m = 1;
}
}
}
}
x += ff.width ();
}
}
}

View File

@ -0,0 +1,61 @@
/*
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_layPixelBufferPainter
#define HDR_layPixelBufferPainter
#include "laybasicCommon.h"
#include "layColor.h"
#include "dbPoint.h"
namespace lay {
class PixelBuffer;
/**
* @brief A very simplistic painter for lay::PixelBuffer
*
* This painter supports very few primitives currently and is used to paint the
* background grid for example.
*/
class LAYBASIC_PUBLIC PixelBufferPainter
{
public:
PixelBufferPainter (lay::PixelBuffer &img, unsigned int width, unsigned int height, double resolution);
void set (const db::Point &p, lay::Color c);
void draw_line (const db::Point &p1, const db::Point &p2, lay::Color c);
void fill_rect (const db::Point &p1, const db::Point &p2, lay::Color c);
void draw_rect (const db::Point &p1, const db::Point &p2, lay::Color c);
void draw_text (const char *t, const db::Point &p, lay::Color c, int halign, int valign);
private:
lay::PixelBuffer *mp_img;
double m_resolution;
int m_width, m_height;
};
}
#endif

View File

@ -23,16 +23,10 @@
#include "layRedrawThreadCanvas.h"
#include "layCanvasPlane.h"
#if defined(HAVE_QT)
#include "layBitmapsToImage.h"
#endif
#include "layDrawing.h"
#include "layBitmap.h"
#if defined(HAVE_QT) // @@@
#include <QImage>
#endif
namespace lay
{
@ -397,9 +391,8 @@ BitmapRedrawThreadCanvas::initialize_plane (lay::CanvasPlane *plane, unsigned in
unlock ();
}
#if defined(HAVE_QT) // @@@
void
BitmapRedrawThreadCanvas::to_image (const std::vector <lay::ViewOp> &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, lay::Color background, lay::Color foreground, lay::Color active, const lay::Drawings *drawings, QImage &img, unsigned int width, unsigned int height)
void
BitmapRedrawThreadCanvas::to_image (const std::vector <lay::ViewOp> &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, lay::Color background, lay::Color foreground, lay::Color active, const lay::Drawings *drawings, lay::PixelBuffer &img, unsigned int width, unsigned int height)
{
if (width > m_width) {
width = m_width;
@ -417,7 +410,27 @@ BitmapRedrawThreadCanvas::to_image (const std::vector <lay::ViewOp> &view_ops, c
bitmaps_to_image (d->get_view_ops (*this, background, foreground, active), *bt, dp, ls, &img, width, height, true, &mutex ());
}
}
#endif
void
BitmapRedrawThreadCanvas::to_image_mono (const std::vector <lay::ViewOp> &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, bool background, bool foreground, bool active, const lay::Drawings *drawings, lay::BitmapBuffer &img, unsigned int width, unsigned int height)
{
if (width > m_width) {
width = m_width;
}
if (height > m_height) {
height = m_height;
}
unsigned int all_one = 0xffffffff;
// convert the plane data to image data
bitmaps_to_image (view_ops, mp_plane_buffers, dp, ls, &img, width, height, true, &mutex ());
// convert the planes of the "drawing" objects too:
std::vector <std::vector <lay::Bitmap *> >::const_iterator bt = mp_drawing_plane_buffers.begin ();
for (lay::Drawings::const_iterator d = drawings->begin (); d != drawings->end () && bt != mp_drawing_plane_buffers.end (); ++d, ++bt) {
bitmaps_to_image (d->get_view_ops (*this, background ? all_one : 0, foreground ? all_one : 0, active ? all_one : 0), *bt, dp, ls, &img, width, height, true, &mutex ());
}
}
}

View File

@ -29,6 +29,7 @@
#include "dbTrans.h"
#include "layViewOp.h"
#include "layBitmapRenderer.h"
#include "layPixelBuffer.h"
#include "tlThreads.h"
#include <vector>
@ -315,12 +316,15 @@ public:
return new lay::BitmapRenderer (m_width, m_height, resolution ());
}
#if defined(HAVE_QT) // @@@
/**
* @brief Transfer the content to an QImage
* @brief Transfer the content to a PixelBuffer
*/
void to_image (const std::vector <lay::ViewOp> &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, lay::Color background, lay::Color foreground, lay::Color active, const lay::Drawings *drawings, QImage &img, unsigned int width, unsigned int height);
#endif
void to_image (const std::vector <lay::ViewOp> &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, lay::Color background, lay::Color foreground, lay::Color active, const lay::Drawings *drawings, PixelBuffer &img, unsigned int width, unsigned int height);
/**
* @brief Transfer the content to a BitmapBuffer (monochrome)
*/
void to_image_mono (const std::vector <lay::ViewOp> &view_ops, const lay::DitherPattern &dp, const lay::LineStyles &ls, bool background, bool foreground, bool active, const lay::Drawings *drawings, lay::BitmapBuffer &img, unsigned int width, unsigned int height);
/**
* @brief Gets the current bitmap data as a BitmapCanvasData object

View File

@ -1244,5 +1244,18 @@ BitmapViewObjectCanvas::set_size (double resolution)
m_resolution = resolution;
}
lay::PixelBuffer *
BitmapViewObjectCanvas::bg_image ()
{
return 0;
}
lay::BitmapBuffer *
BitmapViewObjectCanvas::bg_bitmap ()
{
return 0;
}
}

View File

@ -70,6 +70,8 @@ class ViewObjectWidget;
class ViewObjectCanvas;
class CanvasPlane;
class Bitmap;
class PixelBuffer;
class BitmapBuffer;
LAYBASIC_PUBLIC const char *drag_drop_mime_type ();
@ -1350,13 +1352,6 @@ public:
*/
void clear_fg_bitmaps ();
#if defined(HAVE_QT) // @@@
/**
* @brief Return the background image
*/
virtual QImage &bg_image () = 0;
#endif
/**
* @brief Set the width and height and resolution
*/
@ -1388,6 +1383,16 @@ public:
return m_height;
}
/**
* @brief Gets the pixel buffer that background objects render to
*/
virtual lay::PixelBuffer *bg_image ();
/**
* @brief Gets the monochrome pixel buffer that background objects render to
*/
virtual lay::BitmapBuffer *bg_bitmap ();
private:
std::map <lay::ViewOp, unsigned int> m_fg_bitmap_table;
std::map <std::vector <lay::ViewOp>, unsigned int> m_fgv_bitmap_table;

View File

@ -138,7 +138,8 @@ DEFINES += MAKE_LAYBASIC_LIBRARY
layNetlistBrowserPage.cc \
layNetlistBrowserTreeModel.cc \
layNetlistCrossReferenceModel.cc \
layPixelBuffer.cc \
layPixelBuffer.cc \
layPixelBufferPainter.cc \
layPluginConfigPage.cc \
layProperties.cc \
layPropertiesDialog.cc \
@ -212,7 +213,8 @@ DEFINES += MAKE_LAYBASIC_LIBRARY
layNetlistBrowserPage.h \
layNetlistBrowserTreeModel.h \
layNetlistCrossReferenceModel.h \
layPixelBuffer.h \
layPixelBuffer.h \
layPixelBufferPainter.h \
layPluginConfigPage.h \
layProperties.h \
layPropertiesDialog.h \

View File

@ -20,23 +20,19 @@
*/
#if defined(HAVE_QT) // @@@
#include "layBitmapsToImage.h"
#include "layBitmap.h"
#include "layDitherPattern.h"
#include "layLineStyles.h"
#include "layPixelBuffer.h"
#include "tlUnitTest.h"
#include <QImage>
#include <QColor>
#include <QMutex>
std::string
to_string (const QImage &img, unsigned int mask)
to_string (const lay::PixelBuffer &img, unsigned int mask)
{
std::string s;
for (unsigned int i = 0; i < 32; ++i) {
const unsigned int *data = (const unsigned int *)img.scanLine (i);
const unsigned int *data = (const unsigned int *)img.scan_line (i);
for (unsigned int j = 0; j < 32; ++j) {
s += (data[j] & mask) ? "x" : ".";
}
@ -89,7 +85,7 @@ TEST(1)
view_ops.push_back (lay::ViewOp (0x000080, lay::ViewOp::Copy, 0, 0, 0, lay::ViewOp::Rect, 1));
view_ops.push_back (lay::ViewOp (0x0000c0, lay::ViewOp::Or, 0, 0, 0, lay::ViewOp::Rect, 3));
QImage img (QSize (32, 32), QImage::Format_RGB32);
lay::PixelBuffer img (32, 32);
img.fill (0);
lay::DitherPattern dp;
@ -939,5 +935,3 @@ TEST(1)
);
}
#endif