Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-2427

SVG discrete resolution limitation

    XMLWordPrintable

Details

    • Suggestion
    • Resolution: Unresolved
    • P3: Somewhat important
    • Some future release
    • 4.4.0
    • SVG Support
    • 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.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            Unassigned Unassigned
            admin Administrator
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes