Rasterize: Resolution option not working properly
With a bit of spelunking I extracted the following from
g = Graphics[{Circle[], FontSize -> 20, Text["x^2+y^2<1", {0, 0}]}, ImageSize -> 72];
Trace[Rasterize[g, ImageSize -> 72, ImageResolution -> 100]]
in v.10.0.1.
An excerpt from the Trace
output
1) At first, the value of RasterSize
is extracted from the Rasterize
command using OptionValue
:
System`ConvertersDump`rs$ =
OptionValue[Rasterize, {ImageSize -> 72, ImageResolution -> 100}, RasterSize]
Automatic
2) In our case RasterSize
is Automatic
(the default value) and hence on the following line the value of ImageSize
option (which has dimensionality of printer's points, i.e. the base unit is inch) is incorrectly taken as RasterSize
(which has dimensionality of pixels) without taking into consideration ImageResolution
:
If[System`ConvertersDump`rs$ === Automatic,
System`ConvertersDump`rs$ =
OptionValue[Rasterize, {ImageSize -> 72, ImageResolution -> 100},
ImageSize]]
72
3) Now the new value for RasterSize
is converted into the form {width, heigh}
:
If[! ListQ[System`ConvertersDump`rs$] || Length[System`ConvertersDump`rs$] != 2,
System`ConvertersDump`rs$ = {System`ConvertersDump`rs$, Automatic}]
{72, Automatic}
4) At the next step final image resolution is calculated from the new RasterSize
(note that the original ImageResolution
is present but ignored!):
{System`ConvertersDump`w$, System`ConvertersDump`h$} = System`ConvertersDump`rs$;
System`ConvertersDump`ir$ =
System`ConvertersDump`GetIR[
Graphics[{Circle[{0, 0}], FontSize -> 20, Text["x^2+y^2<1", {0, 0}]}, ImageSize -> 72],
{System`ConvertersDump`w$, System`ConvertersDump`h$},
ImageSize -> 72, ImageResolution -> 100]
72
5) And finally the packet is constructed using the obtained value for ImageResolution
:
System`ConvertersDump`rdpdata$ =
System`ConvertersDump`ToRasterDataPacket[
Graphics[{Circle[{0, 0}], FontSize -> 20, Text["x^2+y^2<1", {0, 0}]}, ImageSize -> 72],
{"Rasterize", "BoundingBox"},
ImageResolution -> System`ConvertersDump`ir$, Background -> System`ConvertersDump`bg$,
ColorSpace -> System`ConvertersDump`cs$,
Sequence @@
FilterRules[{ImageSize -> 72, ImageResolution -> 100},
Except[{ImageResolution, Background, ColorSpace}]]]
What happens when ImageSize
is not specified
When ImageSize
is not specified, everything is the same up to the step 4):
System`ConvertersDump`ir$ =
System`ConvertersDump`GetIR[
Graphics[{Circle[{0, 0}], FontSize -> 20, Text["x^2+y^2<1", {0, 0}]}, ImageSize -> 72],
{System`ConvertersDump`w$, System`ConvertersDump`h$},
ImageResolution -> 100]
100
We see that when the new value of RasterSize
is {Automatic, Automatic}
the original value of ImageResolution
is taken as the final value for image resolution at this step.
Conclusion
From the above it is clear that the key option which currently determines the image resolution in Rasterize
is not ImageResolution
but RasterSize
.
The mechanism of the inconsistent behavior described in the question is as follows: when non-Automatic
ImageSize
is specified without RasterSize
it is taken as ImageResolution
. This contradicts to the documented meaning of these options: ImageSize
specifies the size of the image in printer's points where inch is the base unit while ImageResolution
has dimensionality of dots per inch.
At the same time the combination RasterSize
+ ImageSize
works as expected in accord with the Documentation. So the workaround is to use RasterSize
and do not rely on ImageResolution
.
I don't have time for a complete answer at the moment but hopefully this helps. I believe that ImageSize
, if specified directly inside Rasterize
, overrides the ImageResolution
. Observe this behavior when ImageSize
is used in Graphics
instead:
g = Graphics[{Circle[], FontSize -> 20, Text["x^2+y^2<1", {0, 0}]}, ImageSize -> 130];
r = Table[Rasterize[g, "Image", ImageResolution -> r], {r, {20, 40, 100}}]
An examination of ImageSize
Since my original post Alexey Popkov provided a much deeper analysis but pragmatically the conclusion is the same: when ImageSize
is given as an option of Rasterize
it overrides ImageResolution
, but when ImageSize
is given as part of a Graphics
expression ImageResolution
has effect.
A question remains as to the intended (or desired) behavior in this case. Alexey correctly notes that ImageSize
is ostensibly defined in printer's points:
d d printer's points (before magnification)
However I find this to be practically false. If you specify an ImageSize
of 100
you get an image that is 100 pixels wide. This equivalence requires a resolution of 72 pixels per inch (assuming PostScript printer's points). This resolution is highly outdated as modern displays different resolutions that are often much higher.
Mathematica is aware of the OS-specified resolution. For example under Windows 7 I have "Medium" selected which sets the OS to 120ppi and Mathematica knows this:
CurrentValue["ScreenResolution"]
{120, 120}
Nevertheless the Front End ignores this resolution and renders my ImageSize -> 100
graphic as 100 pixels wide rather than 167 pixels wide as it would if ImageSize
really meant printer's point and not pixels. Further there is a System Option for screen resolution and it too is ignored:
This setting has no effect that I have observed on ImageSize
rendering.
There is the setting "ScreenResolution"
under "FontProperties"
that does have effect but only on font size. Observe this example where FontSize -> 20
is correctly rendered at different specified resolutions:
Graphics[{"FontProperties" -> {"ScreenResolution" -> #}, Circle[], FontSize -> 20,
Text["x^2+y^2<1", {0, 0}]}, ImageSize -> 130] & /@ {30, 60, 100}
I must conclude that by convention and the documentation notwithstanding ImageSize
is in actuality specified in pixel dimension, not printer's points, as far as the Front End is concerned.
Therefore it is entirely reasonable that if an absolute ImageSize
is given to Rasterize
it will use this value rather than one derived from ImageResolution
. I therefore further conclude that this behavior is not a bug. However the entire disregarding of screen resolution by the Front End and the effective specification of ImageSize
in pixels might be.