Let a PNG declare the resolution it was rendered at - #1118
Conversation
A PNG without a `pHYs` chunk carries no resolution, so a viewer or a word processor has to guess one, and most guess 96 DPI. An image rendered for print or for a high resolution display then appears at the wrong physical size, which matters all the more because the resolution also decides how large the text in it ends up. The pixel data is produced exactly as tiny-skia produces it, by demultiplying through its own pixel type rather than repeating the arithmetic, and a test compares the decoded result of both paths. The resolution is the one of the rendered image, which differs from `--dpi` as soon as `--zoom` or `--width` scale the output, so the CLI takes it as its own `--png-dpi` value rather than guessing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Hmm, sorry, but I think I would consider this out-of-scope. If you want to encode the PNG in a special way, you can just render into the pixmap yourself using the existing API and then encode the raw bytes yourself into a PNG with the specific settings. For the CLI, I think this is a bit too overkill. |
|
well, there are applications which do care for the dpi info and if the png carries non, then there is additional work for the user. but yes, I agree it can certainly be worked around. It becomes especially pertinent in connection with font rendering since the font designs care about the resolution. |
|
Honestly, I still have no idea how SVG suppose to handle DPI. And if SVGs DPI is the same as PNG one. Right now, SVG DPI is basically a hint for non-pixel coordinates resolving, not the actual "DPI". |
|
I'm not saying your use case is invalid! My point is: The task of resvg is to render an SVG into a pixmap. The fact that there already exists a way to convert to PNG is a "side-effect" of the fact that tiny-skia offers this API, and it's useful because many people do want to convert into PNG. However, I'd like to avoid adding more API to resvg for very specific image encoding requirements. Otherwise, people might start asking for other things like "add an API to convert to JPEG" or "add an API for another specific type of PNG", etc., I hope you get my point. 😄 If people want something more specific than just a generic PNG, I think that should be implemented on their side. |
|
Fair enough, closing. For the record on the question of a reference: Inkscape does write a |
Adds
resvg::encode_png_with_dpiandresvg::save_png_with_dpi, plus a--png-dpiflagon the CLI.
Why
A PNG without a
pHYschunk carries no resolution, so whatever opens it has to guess one,and most guess 96 DPI. An image rendered for print or for a high resolution display then
shows up at the wrong physical size. This matters particularly for SVG output, since the
resolution is also what decides how large the text in the image ends up: rendering a
document at 300 DPI and then having it displayed as if it were 96 undoes exactly the
sizing the document asked for.
tiny_skia::Pixmap::encode_pngwrites nopHYschunk and offers no way to add one, sothis cannot be done by the caller without re-encoding the image by hand.
Which resolution
The value is the resolution of the rendered image, which is only the same as
usvg::Options::dpiwhen the tree was rendered without scaling.--zoom,--widthand--heightall change it. Deriving it automatically would also have to take a position onwhat an SVG user unit means physically, which
--dpiand the CSS definition of an inchdisagree about for documents sized in
px. The CLI therefore takes the value explicitlyrather than guessing, and the docs state what it refers to.
Implementation
The pixel data is produced exactly as tiny-skia produces it, by demultiplying through its
PremultipliedColorU8::demultiplyrather than repeating the arithmetic, so the two pathscannot drift apart.
pngbecomes a regular dependency ofresvginstead of adev-dependency only; it is already in the tree through tiny-skia, and
png::EncodingErroris already part of resvg's public API surface through tiny-skia's own signatures.
Tests
Four tests: the chunk is written with the expected pixels-per-meter, a plain encoding
still declares nothing, the file-writing wrapper round-trips, and the decoded image is
byte for byte the same as the one from
Pixmap::encode_png, so adding the chunk cannotchange the picture.