View Issue Details

IDProjectCategoryView StatusLast Update
0014004ScribusCanvaspublic2016-05-16 22:21
Reporteruser5122Assigned Tocbradney  
PrioritynormalSeverityfeatureReproducibilityalways
Status closedResolutionfixed 
Product Version1.5.2.svn 
Target Version1.5.2Fixed in Version1.5.2.svn 
Summary0014004: Improve Canvas rendering on Hi-DPI screens
DescriptionThe attached patch improves the Canvas rendering on Hi-DPI screens making text and other vector drawings look sharp and not fuzzy. Namely:
* Set Qt::AA_UseHighDpiPixmaps to allow for Hi-DPI QPixmaps
* Multiply the size of the multitude of intermediate QImage’s and
  QPixmaps we create for the Canvas by its devicePixelFactor, and set
  their devicePixelFactor as well.
* Set the device scale of Cairo surface to that of the QPixmap we are
  drawing it into.
Steps To ReproduceRun Scrinus on a system with a Hi-DPI screen (one might need to set QT_AUTO_SCREEN_SCALE_FACTOR or QT_DEVICE_PIXEL_RATIO depending on Qt version to enable Hi-DPI mode), text and vectors on the Canvas look fuzzy compared to Scribus UI.
Tagsdiscussion, HiDPI
PatchYes

Relationships

related to 0013204 closedfschmid Unusably tiny tool icons on HiDPI screen on Ubuntu Unity desktop 
has duplicate 0014023 closed 1.5.2svn HiDPI GUI font too small 

Activities

user5122

2016-05-01 02:08

 

hidpi-before.png (289,263 bytes)   
hidpi-before.png (289,263 bytes)   

user5122

2016-05-01 02:08

 

hidpi-after.png (428,426 bytes)   
hidpi-after.png (428,426 bytes)   

user5122

2016-05-01 15:00

  ~0040679

I uploaded a new patch fixing few rendering glitches in the first one and less code duplication.

user5122

2016-05-01 15:18

 

0001-Improve-Canvas-drawing-on-Hi-DPI-screens.patch (7,740 bytes)   
From f9981df2939eadd18223bc5e20af99373db133f1 Mon Sep 17 00:00:00 2001
From: Khaled Hosny <khaledhosny@eglug.org>
Date: Sun, 1 May 2016 02:44:10 +0200
Subject: [PATCH] Improve Canvas drawing on Hi-DPI screens
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Set Qt::AA_UseHighDpiPixmaps to allow for Hi-DPI QPixmaps
* Multiply the size of the multitude of intermediate QImage’s and
  QPixmaps we create for the Canvas by its devicePixelFactor, and set
  their devicePixelFactor as well.
* Set the device scale of Cairo surface to that of the QPixmap we are
  drawing it into.
---
 scribus/canvas.cpp     | 46 ++++++++++++++++++++++++++--------------------
 scribus/canvas.h       |  5 +++++
 scribus/scpainter.cpp  |  1 +
 scribus/scribusapp.cpp |  2 +-
 4 files changed, 33 insertions(+), 21 deletions(-)

diff --git a/scribus/canvas.cpp b/scribus/canvas.cpp
index ab19ccc..2af8452 100644
--- a/scribus/canvas.cpp
+++ b/scribus/canvas.cpp
@@ -663,7 +663,7 @@ bool Canvas::adjustBuffer()
 	{
 //		qDebug() << "adjust buffer: invalid buffer, viewport" << viewport;
 		m_bufferRect = viewport;
-		m_buffer = QPixmap(m_bufferRect.width(), m_bufferRect.height());
+		m_buffer = createPixmap(m_bufferRect.width(), m_bufferRect.height());
 		fillBuffer(&m_buffer, m_bufferRect.topLeft(), m_bufferRect);
 		ret = true;
 #if DRAW_DEBUG_LINES
@@ -691,8 +691,7 @@ bool Canvas::adjustBuffer()
 		{
 //			qDebug() << "adjust buffer: fresh buffer" << m_bufferRect << "-->" << newRect;
 			m_bufferRect = newRect;
-// 			m_buffer = QImage(m_bufferRect.width(), m_bufferRect.height(), QImage::Format_ARGB32);
-			m_buffer = QPixmap(m_bufferRect.width(), m_bufferRect.height());
+			m_buffer = createPixmap(m_bufferRect.width(), m_bufferRect.height());
 			fillBuffer(&m_buffer, m_bufferRect.topLeft(), m_bufferRect);
 			ret = true;
 #if DRAW_DEBUG_LINES
@@ -706,8 +705,7 @@ bool Canvas::adjustBuffer()
 		else
 		{
 			// copy buffer:
-// 			QImage newBuffer(newRect.width(), newRect.height(), QImage::Format_ARGB32);
-			QPixmap newBuffer(newRect.width(), newRect.height());
+			QPixmap newBuffer = createPixmap(newRect.width(), newRect.height());
 			QPainter p(&newBuffer);
 			int xpos = m_bufferRect.x() - newRect.x();
 			int ypos = m_bufferRect.y() - newRect.y();
@@ -735,8 +733,8 @@ bool Canvas::adjustBuffer()
 			{
 				height = newRect.height() - ypos;
 			}
-// 			p.drawImage(xpos, ypos, m_buffer, x, y,  width + 1, height + 1); // FIXME: == params drawPixmap?
-			p.drawPixmap(xpos, ypos, m_buffer, x, y,  width + 1, height + 1);
+
+			drawPixmap(p, xpos, ypos, m_buffer, x, y, width + 1, height + 1);
 #if DRAW_DEBUG_LINES
 			p.setPen(Qt::blue);
 			p.drawLine(xpos, ypos+height/2, xpos+width/2, ypos);
@@ -818,11 +816,7 @@ void Canvas::paintEvent ( QPaintEvent * p )
 #endif
 	// fill buffer if necessary
 	bool bufferFilled = adjustBuffer();
-	// It is ugly, but until we figure out why drawing directly on the 
-	// widget is so slow, it saves us a Cray! - pm
-	QPixmap tmpImg(p->rect().size());
-	QPainter qp(&tmpImg);
-	qp.translate(-p->rect().x(), -p->rect().y());
+	QPainter qp(this);
 	switch (m_renderMode)
 	{
 		case RENDER_NORMAL:
@@ -850,8 +844,7 @@ void Canvas::paintEvent ( QPaintEvent * p )
 			int hV = p->rect().height();
 			if (hV > 0 && wV > 0)
 			{
-// 				qp.drawImage(p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
-				qp.drawPixmap(p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
+				drawPixmap(qp, p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
 #if DRAW_DEBUG_LINES
 //				qDebug() << "normal rendering" << xV << yV << wV << hV << "at" << p->rect().x() << p->rect().y();
 				qp.setPen(Qt::blue);
@@ -904,9 +897,7 @@ void Canvas::paintEvent ( QPaintEvent * p )
 #endif
 				if (hV > 0 && wV > 0)
 				{
-// 					qp.drawImage(p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
-					
-					qp.drawPixmap(p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
+					drawPixmap(qp, p->rect().x(), p->rect().y(), m_buffer, xV, yV,  wV, hV);
 	#if DRAW_DEBUG_LINES
 //					qDebug() << "buffered rendering" << xV << yV << wV << hV << "at" << p->rect().x() << p->rect().y();
 					qp.setPen(Qt::green);
@@ -948,8 +939,6 @@ void Canvas::paintEvent ( QPaintEvent * p )
 	// does mode specific rendering, currently selection in legacymode and nodes in nodeedit
 	m_view->m_canvasMode->drawControls(&qp);
 	m_view->m_canvasMode->drawSnapLine(&qp);
-	QPainter tp(this);
-	tp.drawPixmap(p->rect(), tmpImg, tmpImg.rect());
 #ifdef SHOW_ME_WHAT_YOU_GET_IN_D_CANVA
 	t6 = t.elapsed();
 	qDebug()<<dmode<<t1<<t2<<t3<<t4<<t5<<t6<<"-" <<t1+t2+t3+t4+t5+t6;
@@ -969,7 +958,8 @@ void Canvas::drawContents(QPainter *psx, int clipx, int clipy, int clipw, int cl
 // 	qDebug() << "Canvas::drawContents" << clipx << clipy << clipw << cliph<<m_viewMode.forceRedraw<<m_viewMode.operItemSelecting;
 	uint docPagesCount=m_doc->Pages->count();
 	ScPainter *painter=0;
-	QImage img = QImage(clipw, cliph, QImage::Format_ARGB32_Premultiplied);
+	QImage img = QImage(clipw * devicePixelRatio(), cliph * devicePixelRatio(), QImage::Format_ARGB32_Premultiplied);
+	img.setDevicePixelRatio(devicePixelRatio());
 	painter = new ScPainter(&img, img.width(), img.height(), 1.0, 0);
 	painter->clear(palette().color(QPalette::Window));
 	painter->newPath();
@@ -2411,6 +2401,22 @@ void Canvas::calculateFrameLinkPoints(PageItem *pi1, PageItem *pi2, FPoint & sta
 	end.transform(pi2->xPos(), pi2->yPos(), pi2->rotation(), 1, 1, false);
 }
 
+QPixmap Canvas::createPixmap(double w, double h)
+{
+	QPixmap p(w * devicePixelRatio(), h * devicePixelRatio());
+	p.setDevicePixelRatio(devicePixelRatio());
+	return p;
+}
+
+void Canvas::drawPixmap(QPainter& painter, double x, double y, const QPixmap& pixmap, double sx, double sy, double sw, double sh)
+{
+	sx *= devicePixelRatio();
+	sy *= devicePixelRatio();
+	sw *= devicePixelRatio();
+	sh *= devicePixelRatio();
+	painter.drawPixmap(x, y, pixmap, sx, sy, sw, sh);
+}
+
 void Canvas::displayXYHUD(QPoint m)
 {
 	if (!PrefsManager::instance()->appPrefs.displayPrefs.showMouseCoordinates)
diff --git a/scribus/canvas.h b/scribus/canvas.h
index 1501532..5aeaf7a 100644
--- a/scribus/canvas.h
+++ b/scribus/canvas.h
@@ -260,6 +260,11 @@ private:
 	void getLinkedFrames(PageItem* currItem);
 	void getClipPathForPages(FPointArray* PoLine);
 	void calculateFrameLinkPoints(PageItem* pi1, PageItem* pi2, FPoint& start, FPoint& end);
+
+	// create a potentially hidpi pixmap
+	QPixmap createPixmap(double w, double h);
+	// draw a potentially hidpi pixmap
+	void drawPixmap(QPainter &painter, double x, double y, const QPixmap &pixmap, double sx, double sy, double sw, double sh);
 		
 private:
 	ScribusDoc* m_doc;
diff --git a/scribus/scpainter.cpp b/scribus/scpainter.cpp
index 7b36813..19cdf15 100644
--- a/scribus/scpainter.cpp
+++ b/scribus/scpainter.cpp
@@ -52,6 +52,7 @@ ScPainter::ScPainter( QImage *target, unsigned int w, unsigned int h, double tra
 	m_matrix = QTransform();
 	m_zoomStack.clear();
 	cairo_surface_t *img = cairo_image_surface_create_for_data(m_image->bits(), CAIRO_FORMAT_ARGB32, w, h, w*4);
+	cairo_surface_set_device_scale(img, m_image->devicePixelRatio(), m_image->devicePixelRatio());
 	m_cr = cairo_create(img);
 	cairo_save( m_cr );
 	cairo_set_fill_rule (m_cr, CAIRO_FILL_RULE_EVEN_ODD);
diff --git a/scribus/scribusapp.cpp b/scribus/scribusapp.cpp
index 486f478..800e1cb 100644
--- a/scribus/scribusapp.cpp
+++ b/scribus/scribusapp.cpp
@@ -110,7 +110,7 @@ ScribusQApp::ScribusQApp( int & argc, char ** argv ) : QApplication(argc, argv),
 	m_scDLMgr = 0;
 	m_ScCore = NULL;
 	initDLMgr();
-
+	setAttribute(Qt::AA_UseHighDpiPixmaps, true);
 }
 
 ScribusQApp::~ScribusQApp()
-- 
2.8.2

Kunda

2016-05-01 17:26

updater   ~0040688

Thanks Khaled!

jghali

2016-05-01 19:34

administrator   ~0040691

Looks good, unfortunately I have no HiDPI screen at my disposal, so I'm totally unable to do any test.

user5122

2016-05-01 22:06

  ~0040692

On non-Hi-DPI screens nothing should change since deviceScaleFactor() will be 1 then, so I think this is low risk for most of Scribus users. I’d say we apply this and deal with any bugs later, I’m using a Hi-DPI screen myself and should be able to catch any obvious issue.

andreasn1

2016-05-14 22:10

reporter  

andreasn1

2016-05-14 22:11

reporter   ~0041060

Works well on my 3200x1800 13" screen.
The objects on the canvas renders blurry before the patch, and sharp after applying it. One issue is that the Scribus logo in the left corner get a lot more padding with this patch for some reason.

user5122

2016-05-14 22:40

  ~0041062

I see the padding as well, need to find out how the logo is drawn and investigate.

user5122

2016-05-14 22:58

  ~0041063

Seems that the icon is set with QApplication::setWindowIcon(), so that is probably a Qt issue. However I just realised that Scribus is the only application I have that has such an icon, may be it is time to retire this outdated Window icon stuff (but it is a minor issue nevertheless).

jghali

2016-05-15 06:01

administrator   ~0041069

Nah, if you don't call QApplication::setWindowIcon(), scribus icon in the taskbar will be incorrect on Windows for eg.

user5122

2016-05-15 07:48

  ~0041072

But Scribus is the only Qt application I see having that icon in the toolbar.

Kunda

2016-05-15 13:10

updater   ~0041081

andreasn1, can you test Khaled's patch on the latest scribus trunk ?

Issue History

Date Modified Username Field Change
2016-05-01 02:00 user5122 New Issue
2016-05-01 02:00 user5122 File Added: 0001-Improve-Canvas-drawing-on-Hi-DPI-screens.patch
2016-05-01 02:08 user5122 File Added: hidpi-before.png
2016-05-01 02:08 user5122 File Added: hidpi-after.png
2016-05-01 14:59 user5122 File Deleted: 0001-Improve-Canvas-drawing-on-Hi-DPI-screens.patch
2016-05-01 14:59 user5122 File Added: 0001-Improve-Canvas-drawing-on-Hi-DPI-screens.patch
2016-05-01 15:00 user5122 Note Added: 0040679
2016-05-01 15:02 user5122 File Deleted: 0001-Improve-Canvas-drawing-on-Hi-DPI-screens.patch
2016-05-01 15:02 user5122 File Added: 0001-Improve-Canvas-drawing-on-Hi-DPI-screens.patch
2016-05-01 15:18 user5122 File Deleted: 0001-Improve-Canvas-drawing-on-Hi-DPI-screens.patch
2016-05-01 15:18 user5122 File Added: 0001-Improve-Canvas-drawing-on-Hi-DPI-screens.patch
2016-05-01 17:26 Kunda Note Added: 0040688
2016-05-01 17:31 Kunda Tag Attached: HiDPI
2016-05-01 19:34 jghali Note Added: 0040691
2016-05-01 22:06 user5122 Note Added: 0040692
2016-05-02 14:03 Kunda Relationship added related to 0013204
2016-05-04 07:00 Kunda Tag Attached: discussion
2016-05-04 07:00 Kunda Tag Attached: #pending
2016-05-14 22:10 andreasn1 File Added: Screenshot from 2016-05-14 23-36-19.png
2016-05-14 22:11 andreasn1 Note Added: 0041060
2016-05-14 22:40 user5122 Note Added: 0041062
2016-05-14 22:58 user5122 Note Added: 0041063
2016-05-15 06:01 jghali Note Added: 0041069
2016-05-15 07:48 user5122 Note Added: 0041072
2016-05-15 13:10 Kunda Note Added: 0041081
2016-05-15 13:10 Kunda Status new => acknowledged
2016-05-15 13:21 Kunda Tag Attached: #please_test
2016-05-15 23:59 Kunda Target Version => 1.5.3
2016-05-16 13:39 cbradney Status acknowledged => resolved
2016-05-16 13:39 cbradney Fixed in Version => 1.5.2.svn
2016-05-16 13:39 cbradney Resolution open => fixed
2016-05-16 13:39 cbradney Assigned To => cbradney
2016-05-16 13:40 cbradney Target Version 1.5.3 => 1.5.2
2016-05-16 13:41 cbradney Status resolved => closed
2016-05-16 16:42 Kunda Relationship added related to 0014023
2016-05-16 16:44 Kunda Relationship replaced has duplicate 0014023
2016-05-16 17:11 Kunda Tag Detached: #pending
2016-05-16 17:11 Kunda Tag Detached: #please_test