View Issue Details

IDProjectCategoryView StatusLast Update
0017973ScribusUsabilitypublic2026-09-08 16:41
Reporterbuttar Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status newResolutionopen 
PlatformLinuxOSFedora WorkstationOS Version44
Product Version1.7.4.svn 
Summary0017973: [patch] Image Import preview quality and performance improvements
Description#Scope
  -- Depends on `canvas-hud-drag-fix-v1.08.patch` (from 0017870) which replaces Image Import’s QToolTip preview with the shared viewport-anchored HUD.
  -- Polishes the Image Import mouse-following preview without changing placement workflow or queue behaviour.

#Preview
  -- Increases the preview from 80×80 to 96×96 logical px.
  -- Uses equal 5 px padding for the pixmap preview.
  -- Keeps unused letterbox space neutral instead of filling the entire preview with checkerboard.
  -- Shows checkerboard only beneath actual transparent image content.

#Image loading
  -- Replaces the simple full-image load/downscale path with `QImageReader`.
  -- Requests a preview-sized decode where supported, reducing unnecessary work and temporary memory for large images.
  -- Uses smooth scaling for the final thumbnail.
  -- Enables automatic orientation handling from image metadata.
  -- Generates HiDPI-aware backing pixmaps while preserving the same logical preview size.

#Fallback
  -- Uses the proper basename when thumbnail generation fails.
  -- Falls back to the original path only if no basename can be derived.

#Result
  -- Cleaner and more balanced preview presentation.
  -- Better transparency semantics.
  -- Better thumbnail quality and large-image efficiency.
  -- Correct orientation and HiDPI rendering.
  -- Existing Image Import interaction, persistence, edge handling and shared HUD behaviour remain unchanged.
Additional InformationScreenshots included.
Tags#please_test
Attached Files
has-transperancy-PROPOSED.png (123,855 bytes)   
has-transperancy-PROPOSED.png (123,855 bytes)   
image-import-preview-v1.03.patch (4,096 bytes)   
Index: scribus/canvas.cpp
===================================================================
--- scribus/canvas.cpp	(base: canvas-hud-drag-fix-v1.08.patch)
+++ scribus/canvas.cpp	(working copy)
@@ -2282,6 +2282,7 @@
 
 void Canvas::displayHUD(QPointF globalPos, const QString& text, bool autoHide)
 {
+	m_hudLabel->setContentsMargins(6, 4, 6, 4);
 	m_hudLabel->setPixmap(QPixmap());
 	m_hudLabel->setText(text);
 	positionHUD(globalPos, autoHide);
@@ -2289,6 +2290,7 @@
 
 void Canvas::displayHUD(QPointF globalPos, const QPixmap& pixmap, bool autoHide)
 {
+	m_hudLabel->setContentsMargins(5, 5, 5, 5);
 	m_hudLabel->clear();
 	m_hudLabel->setPixmap(pixmap);
 	positionHUD(globalPos, autoHide);
Index: scribus/canvasmode_imageimport.cpp
===================================================================
--- scribus/canvasmode_imageimport.cpp	(base: canvas-hud-drag-fix-v1.08.patch)
+++ scribus/canvasmode_imageimport.cpp	(working copy)
@@ -18,6 +18,8 @@
 #include <QApplication>
 #include <QCursor>
 #include <QEvent>
+#include <QFileInfo>
+#include <QImageReader>
 #include <QMouseEvent>
 #include <QPainterPath>
 #include <QPixmap>
@@ -34,6 +36,29 @@
 #include "scribusview.h"
 #include "selection.h"
 
+namespace
+{
+constexpr int ImagePreviewSize = 96;
+
+bool hasTransparentPixels(const QImage& image)
+{
+	if (!image.hasAlphaChannel())
+		return false;
+
+	const QImage argbImage = image.convertToFormat(QImage::Format_ARGB32);
+	for (int y = 0; y < argbImage.height(); ++y)
+	{
+		const QRgb* scanLine = reinterpret_cast<const QRgb*>(argbImage.constScanLine(y));
+		for (int x = 0; x < argbImage.width(); ++x)
+		{
+			if (qAlpha(scanLine[x]) < 255)
+				return true;
+		}
+	}
+	return false;
+}
+}
+
 CanvasMode_ImageImport::CanvasMode_ImageImport(ScribusView *view) : CanvasMode(view), m_ScMW(view->m_ScMW)
 {
 	const QPoint cursorPos = QCursor::pos();
@@ -70,29 +95,49 @@
 
 void CanvasMode_ImageImport::updatePreview(const QString& name)
 {
-	QPixmap preview(80, 80);
-	QBrush background(QColor(205, 205, 205), IconManager::instance().loadPixmap("testfill"));
-	QImage thumb;
-	const bool hasThumbnail = thumb.load(name);
+	const qreal devicePixelRatio = qMax<qreal>(1.0, m_canvas->devicePixelRatioF());
+	const int previewPixelSize = qMax(1, qRound(ImagePreviewSize * devicePixelRatio));
+	const QSize previewSize(previewPixelSize, previewPixelSize);
+
+	QImageReader reader(name);
+	reader.setAutoTransform(true);
+	const QSize sourceSize = reader.size();
+	if (sourceSize.isValid() && (sourceSize.width() > previewPixelSize || sourceSize.height() > previewPixelSize))
+	{
+		const QSize scaledSize = sourceSize.scaled(previewSize, Qt::KeepAspectRatio);
+		if (scaledSize.isValid())
+			reader.setScaledSize(scaledSize);
+	}
+
+	QImage thumb = reader.read();
+	if (!thumb.isNull())
 	{
+		thumb = thumb.scaled(previewSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+
+		QPixmap preview(previewPixelSize, previewPixelSize);
+		preview.fill(Qt::transparent);
 		QPainter painter(&preview);
-		painter.fillRect(QRectF(0, 0, 80, 80), background);
-		if (hasThumbnail)
+		const QRect imageRect((previewPixelSize - thumb.width()) / 2,
+		                      (previewPixelSize - thumb.height()) / 2,
+		                      thumb.width(), thumb.height());
+		if (hasTransparentPixels(thumb))
 		{
-			thumb = thumb.scaled(80, 80, Qt::KeepAspectRatio);
-			painter.drawImage((80 - thumb.width()) / 2, (80 - thumb.height()) / 2, thumb);
+			const QBrush transparencyBackground(QColor(205, 205, 205), IconManager::instance().loadPixmap("testfill"));
+			painter.fillRect(imageRect, transparencyBackground);
 		}
-	}
+		painter.drawImage(imageRect.topLeft(), thumb);
+		painter.end();
+		preview.setDevicePixelRatio(devicePixelRatio);
 
-	if (hasThumbnail)
-	{
 		m_previewPixmap = preview;
 		m_previewText.clear();
 	}
 	else
 	{
 		m_previewPixmap = QPixmap();
-		m_previewText = name.right(name.lastIndexOf("/"));
+		m_previewText = QFileInfo(name).fileName();
+		if (m_previewText.isEmpty())
+			m_previewText = name;
 	}
 
 	displayPreview(QPointF(m_Mx, m_My));
no-transperancy-CURRENT.png (124,631 bytes)   
no-transperancy-CURRENT.png (124,631 bytes)   
no-transperancy-PROPOSED.png (123,602 bytes)   
no-transperancy-PROPOSED.png (123,602 bytes)   
PatchYes

Activities

Issue History

Date Modified Username Field Change
2026-09-08 16:41 buttar New Issue
2026-09-08 16:41 buttar Tag Attached: #please_test
2026-09-08 16:41 buttar File Added: has-transperancy-PROPOSED.png
2026-09-08 16:41 buttar File Added: image-import-preview-v1.03.patch
2026-09-08 16:41 buttar File Added: no-transperancy-CURRENT.png
2026-09-08 16:41 buttar File Added: no-transperancy-PROPOSED.png