From 6f80da66d5a7e7864f10ffcabf3749dc8fdbe604 Mon Sep 17 00:00:00 2001 From: Andre Rummler Date: Sun, 6 Sep 2026 10:50:41 +0200 Subject: [PATCH] Connected to previous image handling updates: images were not exported at all to dxf. In this update instead of the image a placeholder box is drawn and a warning is given during export. Current dxf version is extremely old and does not support any image embedding. Future possible update is the introduction of a newer dxf version export option which would allow to embed a link to an external image file. --- sources/dxfpaintdevice.cpp | 46 ++++++++++++++---- sources/dxfpaintdevice.h | 17 +++++-- sources/exportdialog.cpp | 55 ++++++++++++++++++++++ sources/qetgraphicsitem/diagramimageitem.h | 14 ++++++ 4 files changed, 119 insertions(+), 13 deletions(-) diff --git a/sources/dxfpaintdevice.cpp b/sources/dxfpaintdevice.cpp index e7f180a33..8264bdcb1 100644 --- a/sources/dxfpaintdevice.cpp +++ b/sources/dxfpaintdevice.cpp @@ -200,18 +200,35 @@ void DxfPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) /** @brief DxfPaintEngine::drawPixmap - Not implemented in v1 - out of scope per the design note in the - header (CrossRefItem, the only item exported through this engine so - far, never draws a pixmap). qWarning() rather than a hard failure, so - an item that does call this in the future degrades to "one entity - missing" instead of crashing the whole export. + No DXF dialect this old (AC1006, AutoCAD R10 from 1988) has any + raster image representation at all -- IMAGE/IMAGEDEF wasn't + introduced until R2000, over a decade later, and even there the + pixels are never embedded, only referenced by external file path. + Actually supporting images means upgrading the DXF version target + and managing a second file alongside the DXF; until then, this + draws a placeholder rectangle outline (the item's own destination + rect, mapped through m_world_transform exactly like drawRects() + does) instead of silently dropping the item -- so its position, + size, rotation, and skew all survive the export even though the + picture itself can't yet. A fixed, plain pen, not m_pen: an image + item has no meaningful pen of its own for this engine to have + picked up from a prior updateState(). */ void DxfPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) { - Q_UNUSED(r) Q_UNUSED(pm) Q_UNUSED(sr) - qWarning() << "DxfPaintEngine::drawPixmap: not supported, entity skipped"; + + QPolygonF corners; + corners << r.topLeft() << r.topRight() << r.bottomRight() << r.bottomLeft(); + + QPolygonF mapped; + mapped.reserve(corners.size() + 1); + for (const QPointF &p : corners) + mapped << toDxf(p); + mapped << mapped.first(); + + Createdxf::drawPolyline(m_filepath, mapped, Createdxf::dxfColor(QPen(Qt::black))); } /** @@ -261,8 +278,21 @@ int DxfPaintDevice::metric(PaintDeviceMetric metric) const case PdmDepth: return 24; case PdmDevicePixelRatio: - case PdmDevicePixelRatioScaled: return 1; + case PdmDevicePixelRatioScaled: + // Not just 1: Qt's own convention (see QPaintDevice's docs) + // is that this metric equals PdmDevicePixelRatio scaled by + // devicePixelRatioFScale() -- a large constant (65536) + // used internally for sub-integer precision. Returning the + // plain, unscaled ratio here (as this used to) meant + // QPainter's own transform bookkeeping divided by it + // expecting the scaled value, silently shrinking every + // drawPixmap() destination rect by a factor of 65536 -- + // this is what was actually behind the placeholder + // rectangle rendering at a barely-visible fraction of its + // real size instead of the size the item's own + // sceneTransform() correctly specified. + return int(1 * QPaintDevice::devicePixelRatioFScale()); default: return 0; } diff --git a/sources/dxfpaintdevice.h b/sources/dxfpaintdevice.h index 6b43472c5..0091cefb7 100644 --- a/sources/dxfpaintdevice.h +++ b/sources/dxfpaintdevice.h @@ -56,11 +56,18 @@ - fillPath -> same outline-only handling as drawRects; no HATCH support in v1 (see design note in the PR) - Anything outside this list (images, gradients, etc.) is intentionally - unimplemented and asserts in debug builds rather than silently - producing an incomplete drawing - callers should know immediately if - an item they're exporting uses something this engine doesn't cover - yet, rather than getting a DXF file quietly missing content. + - drawPixmap -> no raster image entity exists in this DXF + dialect at all (see drawPixmap()'s own + comment) -- draws a placeholder rectangle + outline instead, preserving the item's + position/size/rotation/skew even though the + picture itself can't be included yet + + Anything else outside this list (gradients, etc.) is intentionally + unimplemented and logs a warning rather than silently producing an + incomplete drawing - callers should know immediately if an item + they're exporting uses something this engine doesn't cover yet, + rather than getting a DXF file quietly missing content. */ class DxfPaintEngine : public QPaintEngine { diff --git a/sources/exportdialog.cpp b/sources/exportdialog.cpp index e0315048c..6eeaabfc3 100644 --- a/sources/exportdialog.cpp +++ b/sources/exportdialog.cpp @@ -744,6 +744,25 @@ void ExportDialog::generateDxf( painter.end(); } + //Draw images -- collected above (list_images) but never actually + //drawn until now, an existing gap this reuses the same paint() + //-replay approach to fix: DiagramImageItem::paint() has no + //viewport-dependent logic (unlike CrossRefItem, which needs its own + //paintForExport() for that reason), so it's called directly with a + //default QStyleOptionGraphicsItem rather than needing an export- + //specific variant of its own. DxfPaintEngine::drawPixmap() is what + //actually turns the drawPixmap() call inside paint() into a + //placeholder outline, since this DXF dialect has no raster image + //entity to draw instead. + for (DiagramImageItem *image : std::as_const(list_images)) + { + DxfPaintDevice dxf_device(file_path); + QPainter painter(&dxf_device); + painter.setWorldTransform(image->sceneTransform()); + image->paintForExport(&painter); + painter.end(); + } + Createdxf::dxfEnd(file_path); saveReloadDiagramParameters(diagram, false); @@ -818,6 +837,42 @@ void ExportDialog::slot_export() return; } + // Warn once, up front, rather than per-diagram: this DXF dialect + // (AC1006, AutoCAD R10) has no raster image representation at all + // (IMAGE/IMAGEDEF wasn't introduced until R2000, over a decade + // later, and even there the picture is never embedded, only + // referenced by external file path) -- so any image ends up as a + // placeholder rectangle outline instead (see DxfPaintEngine:: + // drawPixmap()), with its position/size/rotation/skew preserved but + // not its actual content. + if (epw -> exportProperties().format.compare(QLatin1String("dxf"), Qt::CaseInsensitive) == 0) + { + bool any_images = false; + for (ExportDiagramLine *diagram_line : std::as_const(diagrams_to_export)) + { + for (QGraphicsItem *item : diagram_line->diagram->items()) + { + if (qgraphicsitem_cast(item)) { + any_images = true; + break; + } + } + if (any_images) break; + } + + if (any_images) + { + QET::QetMessageBox::warning( + this, + tr("Images non incluses dans l'export DXF", "message box title"), + tr("Le format DXF utilisé ici (AC1006) ne permet pas d'inclure d'image. " + "Les images seront représentées uniquement par un rectangle de contour " + "(position, taille, rotation et inclinaison conservées), sans le contenu de l'image.", + "message box content") + ); + } + } + // exporte chaque schema a exporter foreach(ExportDiagramLine *diagram_line, diagrams_to_export) { exportDiagram(diagram_line); diff --git a/sources/qetgraphicsitem/diagramimageitem.h b/sources/qetgraphicsitem/diagramimageitem.h index 9c4352582..215e0b100 100644 --- a/sources/qetgraphicsitem/diagramimageitem.h +++ b/sources/qetgraphicsitem/diagramimageitem.h @@ -24,6 +24,7 @@ #include #include +#include #include class QDomElement; @@ -96,6 +97,19 @@ class DiagramImageItem : public QetGraphicsItem { QRectF boundingRect() const override; QString name() const override; + /// DXF export: replay this item's paint() on an arbitrary QPainter + /// (e.g. one targeting DxfPaintDevice). paint() itself stays + /// protected, as it should for the normal + /// QGraphicsScene/QGraphicsView paint contract - this is a + /// deliberate, narrow escape hatch for exporters, not a general + /// relaxation of that contract. Matches CrossRefItem::paintForExport() + /// exactly, for the identical reason. + void paintForExport(QPainter *painter) + { + QStyleOptionGraphicsItem option; + paint(painter, &option, nullptr); + } + qreal scaleFactorX() const { return m_transform.scaleX; } qreal scaleFactorY() const { return m_transform.scaleY; } void setScaleFactorX(qreal factor);