Skip to content

Commit

Permalink
Minor tweaks to size/resolution handling
Browse files Browse the repository at this point in the history
I think the original code was correct but I've clarified it and used a value of 1 pixel per mm for rendering to make it clear that that doesn't matter.
  • Loading branch information
Timmmm committed Jan 16, 2024
1 parent 0bd7c53 commit c1f6754
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 32 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)

# Set the CMAKE_PREFIX_PATH environment variable to (e.g) ~/Qt/5.8/clang_64 so it can find Qt.
# CoreTools is for win/macdeployqt
# Set the CMAKE_PREFIX_PATH environment variable to (e.g) ~/Qt/6.6.1/gcc_64/lib/cmake/
# so it can find Qt. CoreTools is for win/macdeployqt.
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Svg CoreTools)

qt_standard_project_setup()
Expand Down
15 changes: 10 additions & 5 deletions MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,16 @@ void MainWindow::loadFile(QString filename)

StateFileLoaded loadedState;

// See
// https://code.woboq.org/qt5/qtsvg/src/svg/qsvghandler.cpp.html#_ZL15convertToPixelsdbN11QSvgHandler10LengthTypeE
// The default size is derived from the width="" height="" svg attribute tags
// assuming 90 DPI.
// When Qt renders an SVG it sets its width and height based on the
// width="" height="" svg attributes. These can be given in physical units
// e.g. width="25mm". In that case Qt renders at 90 DPI. However that is
// incorrect. SVG/CSS use 96 DPI.
//
// See `convertToPixels()` here: https://codebrowser.dev/qt6/qtsvg/src/svg/qsvghandler.cpp.html#932
//

// This is the size of the entire document in mm, calculated from the
// width/height attributes, using the correct conversion from pixels (96 DPI).
QSizeF mediaSize(render.widthMm, render.heightMm);

loadedState.mediaSize = mediaSize;
Expand Down Expand Up @@ -903,4 +909,3 @@ void MainWindow::on_actionExport_HPGL_triggered()
return;
}
}

29 changes: 10 additions & 19 deletions PathPaintDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,13 @@ size_t qHash(const QPolygonF& key)
return qHash(repr);
}

PathPaintDevice::PathPaintDevice(double widthInMm, double heightInMm, double pixelsPerMm)
PathPaintDevice::PathPaintDevice(double width, double height)
: width(width), height(height)
{
engine = nullptr;
width = widthInMm;
height = heightInMm;
ppm = pixelsPerMm;
if (ppm == 0.0)
ppm = 1.0;
}

PathPaintDevice::~PathPaintDevice()
{
if (engine)
delete engine;
}

void PathPaintDevice::addPath(const QPolygonF& path)
Expand All @@ -45,8 +38,8 @@ void PathPaintDevice::addPath(const QPolygonF& path)
QPaintEngine* PathPaintDevice::paintEngine() const
{
if (!engine)
engine = new PathPaintEngine();
return engine;
engine = std::make_unique<PathPaintEngine>();
return engine.get();
}

QList<QPolygonF> PathPaintDevice::paths()
Expand All @@ -60,9 +53,9 @@ int PathPaintDevice::metric(PaintDeviceMetric metric) const
{
// Width in pixels.
case PdmWidth:
return static_cast<int>(width * ppm);
return static_cast<int>(width);
case PdmHeight:
return static_cast<int>(height * ppm);
return static_cast<int>(height);
case PdmWidthMM:
return static_cast<int>(width);
case PdmHeightMM:
Expand All @@ -72,19 +65,17 @@ int PathPaintDevice::metric(PaintDeviceMetric metric) const
case PdmDepth:
return 1;
case PdmDpiX:
return static_cast<int>(25.4 * ppm); // Convert to inches.
return static_cast<int>(25.4);
case PdmDpiY:
return static_cast<int>(25.4 * ppm);
return static_cast<int>(25.4);
case PdmPhysicalDpiX:
return static_cast<int>(25.4 * ppm);
return static_cast<int>(25.4);
case PdmPhysicalDpiY:
return static_cast<int>(25.4 * ppm);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
return static_cast<int>(25.4);
case PdmDevicePixelRatio:
return 1;
case PdmDevicePixelRatioScaled:
return 1;
#endif
}
return 0;
}
7 changes: 3 additions & 4 deletions PathPaintDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ size_t qHash(const QPolygonF& key);
class PathPaintDevice : public QPaintDevice
{
public:
PathPaintDevice(double widthInMm, double heightInMm, double pixelsPerMm = 90.0 / 25.4);
// Width/height in pixels.
PathPaintDevice(double width, double height);
~PathPaintDevice() override;

// Adds a path to the device.
Expand All @@ -31,7 +32,7 @@ class PathPaintDevice : public QPaintDevice
int metric(PaintDeviceMetric metric) const override;

private:
mutable PathPaintEngine* engine;
mutable std::unique_ptr<PathPaintEngine> engine;

// The paths added.
QList<QPolygonF> pagePaths;
Expand All @@ -40,6 +41,4 @@ class PathPaintDevice : public QPaintDevice

double width;
double height;

double ppm;
};
9 changes: 7 additions & 2 deletions SvgRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
namespace
{

// 1 px is 1/96th of an inch.
// If the user specifies width="96px" then we assume 96 DPI and return
// a size of 1 inch (this matches the latest versions of Inkscape).
// Note Qt assumes 90 DPI when rendering and SVG but we account for that so
// it has no effect.
const double MM_PER_CM = 10.0;
const double MM_PER_Q = 0.25;
const double MM_PER_IN = 25.4;
Expand Down Expand Up @@ -184,10 +187,12 @@ SResult<SvgRender> svgToPaths(const QString& filename, bool searchForTspans)

render.viewBox = renderer.viewBoxF();

// So here we pretend that the viewbox is in mm.
// Give the size of the canvas. We just use 1 user unit per pixel and
// then convert later.
PathPaintDevice pg(render.viewBox.width(), render.viewBox.height());
QPainter p(&pg);

// Render, this will assume 1 user unit = 1px.
renderer.render(&p, render.viewBox);

// These are the paths in user units.
Expand Down
1 change: 1 addition & 0 deletions SvgRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct SvgRender
// from the width= and height= attributes, if they have physical units. If they
// are in user units then it is assumed to be mm. If they are in % or are not present
// then the view box size is used and is assumed to be in mm.
// If they are in pixels then they are converted at 96 DPI per the SVG spec.
double widthMm;
double heightMm;

Expand Down

0 comments on commit c1f6754

Please sign in to comment.