diff --git a/src/img/img/imgService.cc b/src/img/img/imgService.cc index 627c03967..68fcb1a9f 100644 --- a/src/img/img/imgService.cc +++ b/src/img/img/imgService.cc @@ -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 (&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 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 ()); } } diff --git a/src/laybasic/laybasic/layBitmapsToImage.cc b/src/laybasic/laybasic/layBitmapsToImage.cc index 13403920b..cb1666fb7 100644 --- a/src/laybasic/laybasic/layBitmapsToImage.cc +++ b/src/laybasic/laybasic/layBitmapsToImage.cc @@ -25,11 +25,10 @@ #include "layBitmap.h" #include "layDitherPattern.h" #include "layLineStyles.h" +#include "layPixelBuffer.h" #include "tlTimer.h" #include "tlAssert.h" - -#include -#include +#include "tlThreads.h" namespace lay { @@ -422,16 +421,17 @@ static void create_precursor_bitmaps (const std::vector &view_ops_i } } -static void -bitmaps_to_image_rgb (const std::vector &view_ops_in, - const std::vector &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 &view_ops_in, + const std::vector &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 bm_map; std::vector vo_map; @@ -588,7 +588,7 @@ bitmaps_to_image_rgb (const std::vector &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 &view_ops_in, delete [] buffer; } -static void -bitmaps_to_image_mono (const std::vector &view_ops_in, - const std::vector &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 &view_ops_in, + const std::vector &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 bm_map; std::vector vo_map; @@ -825,7 +825,7 @@ bitmaps_to_image_mono (const std::vector &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 &view_ops_in, delete [] buffer; } -void -bitmaps_to_image (const std::vector &view_ops_in, - const std::vector &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, diff --git a/src/laybasic/laybasic/layBitmapsToImage.h b/src/laybasic/laybasic/layBitmapsToImage.h index 411369705..3520fdaf5 100644 --- a/src/laybasic/laybasic/layBitmapsToImage.h +++ b/src/laybasic/laybasic/layBitmapsToImage.h @@ -29,17 +29,17 @@ #include -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 &view_ops, const std::vector &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 &view_ops, + const std::vector &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 diff --git a/src/laybasic/laybasic/layGridNet.cc b/src/laybasic/laybasic/layGridNet.cc index d006ca58c..612f58fc9 100644 --- a/src/laybasic/laybasic/layGridNet.cc +++ b/src/laybasic/laybasic/layGridNet.cc @@ -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 (&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 } } diff --git a/src/laybasic/laybasic/layLayerTreeModel.cc b/src/laybasic/laybasic/layLayerTreeModel.cc index 5a3c09eea..e88941da6 100644 --- a/src/laybasic/laybasic/layLayerTreeModel.cc +++ b/src/laybasic/laybasic/layLayerTreeModel.cc @@ -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 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); } diff --git a/src/laybasic/laybasic/layLayoutCanvas.cc b/src/laybasic/laybasic/layLayoutCanvas.cc index e13a125fb..7b4be5838 100644 --- a/src/laybasic/laybasic/layLayoutCanvas.cc +++ b/src/laybasic/laybasic/layLayoutCanvas.cc @@ -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 view_ops (m_view_ops); + if (linewidth > 1) { + for (std::vector::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 (); diff --git a/src/laybasic/laybasic/layLayoutCanvas.h b/src/laybasic/laybasic/layLayoutCanvas.h index c4a8fb8c4..2ce31f095 100644 --- a/src/laybasic/laybasic/layLayoutCanvas.h +++ b/src/laybasic/laybasic/layLayoutCanvas.h @@ -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; diff --git a/src/laybasic/laybasic/layLayoutViewBase.cc b/src/laybasic/laybasic/layLayoutViewBase.cc index 413204547..05b8a89e6 100644 --- a/src/laybasic/laybasic/layLayoutViewBase.cc +++ b/src/laybasic/laybasic/layLayoutViewBase.cc @@ -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 diff --git a/src/laybasic/laybasic/layPixelBufferPainter.cc b/src/laybasic/laybasic/layPixelBufferPainter.cc new file mode 100644 index 000000000..068c2968e --- /dev/null +++ b/src/laybasic/laybasic/layPixelBufferPainter.cc @@ -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 (); + + } + +} + +} diff --git a/src/laybasic/laybasic/layPixelBufferPainter.h b/src/laybasic/laybasic/layPixelBufferPainter.h new file mode 100644 index 000000000..45da9d309 --- /dev/null +++ b/src/laybasic/laybasic/layPixelBufferPainter.h @@ -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 + diff --git a/src/laybasic/laybasic/layRedrawThreadCanvas.cc b/src/laybasic/laybasic/layRedrawThreadCanvas.cc index e47eb19ab..9b72833b7 100644 --- a/src/laybasic/laybasic/layRedrawThreadCanvas.cc +++ b/src/laybasic/laybasic/layRedrawThreadCanvas.cc @@ -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 -#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 &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 &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 &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 &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 >::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 ()); + } } +} diff --git a/src/laybasic/laybasic/layRedrawThreadCanvas.h b/src/laybasic/laybasic/layRedrawThreadCanvas.h index b231aa557..77614c628 100644 --- a/src/laybasic/laybasic/layRedrawThreadCanvas.h +++ b/src/laybasic/laybasic/layRedrawThreadCanvas.h @@ -29,6 +29,7 @@ #include "dbTrans.h" #include "layViewOp.h" #include "layBitmapRenderer.h" +#include "layPixelBuffer.h" #include "tlThreads.h" #include @@ -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 &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 &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 &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 diff --git a/src/laybasic/laybasic/layViewObject.cc b/src/laybasic/laybasic/layViewObject.cc index 564353267..528b3e689 100644 --- a/src/laybasic/laybasic/layViewObject.cc +++ b/src/laybasic/laybasic/layViewObject.cc @@ -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; +} + + } diff --git a/src/laybasic/laybasic/layViewObject.h b/src/laybasic/laybasic/layViewObject.h index 38e84f5c1..bd1350dff 100644 --- a/src/laybasic/laybasic/layViewObject.h +++ b/src/laybasic/laybasic/layViewObject.h @@ -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 m_fg_bitmap_table; std::map , unsigned int> m_fgv_bitmap_table; diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index bae8ac5e4..c542dca47 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -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 \ diff --git a/src/laybasic/unit_tests/layBitmapsToImage.cc b/src/laybasic/unit_tests/layBitmapsToImage.cc index 299d2c81d..47d61206f 100644 --- a/src/laybasic/unit_tests/layBitmapsToImage.cc +++ b/src/laybasic/unit_tests/layBitmapsToImage.cc @@ -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 -#include -#include - 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