Details
-
Suggestion
-
Resolution: Unresolved
-
P3: Somewhat important
-
4.4.0
-
None
Description
So, first off an example of the problem: the header of a .svg
generated by svggenerator.
<?xml version="1.0" standalone="no"?>
<svg width="104.648mm" height="104.648mm"
viewBox="0 0 103 103"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2"
baseProfile="tiny">
<title>Qt Svg Document</title>
The size there is supposed to be the actual size of the bounding box
of the items in my scene, which is passed in correctly though due to
some integer casts looses precision.
In scene coordinates it should be 103.33x103.33, which gets rounded in
the viewbox tag, and is even further off in the actual mm size. The
abstract 103.33x103.33 units in my scene should correspond to
103.33mmx103.33mm in the real world.
My code I use to generate the scene:
// Dump to SVG
QSvgGenerator *gen = new QSvgGenerator();
gen->setFileName(fileName);
// Final size not accurate even though translation from mm to inch should
// be correct. Implies resizing svg to correct dimensions before printing.
// This limitation is caused by qsvg generator using integer sizes,
instead of more
// logical floats.
float sizex = scene->itemsBoundingRect().width();
float sizey = scene->itemsBoundingRect().height();
//The final toSize() call casts our nice floats to ints.
gen->setSize(QSizeF(sizex, sizey).toSize());
// c++ is kind enough to convert this float to an int too
gen->setResolution(25.4);
QPainter *svgPainter = new QPainter(gen);
scene->render(svgPainter);
svgPainter->end();
Not very complicated so I think it's quite clear what the intention
was here when setting the resolution to 25.4.
I only have qt4.3's source, but I'm guessing this bit hasn't changed too much.
From qsvggenerator.cpp, QSvgPaintEngine::begin(QPaintDevice *)
d->stream = new QTextStream(&d->header);
// rounds 103.33 to 103
int w = d->size.width();
int h = d->size.height();
// ends up being 25.4 / 25
qreal wmm = w * 25.4 / d->resolution;
qreal hmm = h * 25.4 / d->resolution;
// stream out the header...
*d->stream << "<?xml version=\"1.0\" standalone=\"no\"?>" << endl;
*d->stream << "<svg width=\"" << wmm << "mm\" height=\"" << hmm <<
"mm\"" << endl;
*d->stream << " viewBox=\"0 0 " << w << " " << h << "\"" << endl;
The actual culprit here is the underlying QSvgPaintEngine. I don't
know qt well enough though to be able to say that one only has to
change the int types to float types. Do the actual devices that get
printed (rendered) to expect discrete units, ie. bitmaps? At least for
the svg file specification that's certainly not required, but maybe
it's required for compatibility for other devices.
In my personal opinion though the whole concept of resolution is
obsolete when dealing with vector graphics, the underlying data is
represented in a dimensionless manner only relative to the coordinate
system. Which I believe is exactly the way it's done in
QGraphicsScene. So instead of specifying resolution in dpi, simply
specify the real world units (if any) the data is modeled on before
outputting it to a real world device, eg. printers, screens, pdfs etc.
Using implicit conversion where needed, and allowing for explicit
conversion too. So when I set my units to mm and I've got a 50mm x
50mm square svg item, it could get implicitly converted to 50mm x 50mm
on my screen instead of 50 x 50 pixels. Same goes for when printing it
out, whether the printer dpi is 300 or 100, it should get converted to
50mm x 50mm. (Of course this would assume the information required
for unit conversion is known for the devices we're dealing with. )
As per svg specification:
***
Lengths in SVG can be specified as:
- (if no unit identifier is provided) values in user space – for
example, "15" - (if a unit identifier is provided) a length expressed as an
absolute or relative unit measure – for example, "15mm" or "5em"
The supported length unit identifiers are: em, ex, px, pt, pc, cm, mm,
in, and percentages.
***
I believe the 'default' unit for svg is usually assumed to be pixels
seeing as we're working on monitors most of the time.