20
$\begingroup$

Bug introduced in 7 or earlier and persisting through 12.0
Bug isn't present in version 5.2


Something about Rasterize which doesn't seem to work as intended.

Recipe:

  1. Make some simple vector graphics:

    Test = Graphics[Circle[{0, 0} 1]]
    
  2. Try to rasterize it having defined ImageSize and ImageResolution:

    TestNew = Rasterize[Test, "Image", ImageResolution -> 300, ImageSize -> 72]
    

    ImageSize set to 72 means that the resulting image should have exactly 1 inch in size on the screen, since screen resolution is 72 pixels per inch. This is okay.

    ImageResolution set 300 means that this image should have dimensions 300 over 300, since ImageResolution is defined in printer dots per inch and the image has the size of one inch.

  3. However, check image dimensions:

    ImageDimensions[TestNew]
    

    To discover that it is 72.

Moreover: the result does not depend at all on ImageResolution option. From documentation: "RasterSize and ImageResolution determine the coarseness of rasterization; ImageSize determines the size at which the final image will be displayed." If I vary RasterSize, the coarseness indeed changes. If I vary ImageResolution, the coarseness stays the same.

My system: Ubuntu 14, MMA10.0.1

Questions:

  1. Can anyone reproduce the behaviour? (done; yes)

  2. If it's not a bug, what is the reason? (mostly done: technical reason wonderfully explained by Alexey Popkov; this will be updated after the answer from WRI support is available)

  3. Could someone try this on older MMA versions? (done: See Alexey's comment to his answer: ImageResoltution is overriden by ImageSize in V7, but not in V5)

Edit: The result I would want to obtain in the above example can be obtained by calling:

TestNew = Rasterize[Test, "Image", RasterSize -> 300, ImageSize -> 72]

Or, for general image sizes:

Rasterize[Test, "Image", ImageResolution -> <DESIRED RESOLUTION IN DPI>, ImageSize -> (<DESIRED SIZE IN CENTIMETERS>)*(72/2.54)]

should give the same result as:

Rasterize[Test, "Image", RasterSize -> (<DESIRED SIZE IN CENTIMETERS>/2.54)*(<DESIRED RESOLUTION IN DPI>), ImageSize -> (<DESIRED SIZE IN CENTIMETERS>)*(72/2.54)]

In other words, ImageResolution and RasterSize seem to serve the same purpose, but the former one doesn't seem to work as it should.

Status update: According to the feedback from WRI: The question has been acknowledged as an issue. However it is not decided yet, how exactly it is to be resolved.

$\endgroup$
  • $\begingroup$ Don't know much about Rasterize, but TestNew = Rasterize[Test, "Image", ImageResolution -> 300, ImageSize -> 300] returns a 300 by 300 image. So perhaps Rasterize uses whichever of ImageSize and ImageResolution is smaller? If so, then I agree that doesn't make much sense. As a more extreme example, Rasterize[Test, "Image", ImageResolution -> 0, ImageSize -> 600] gives a 600x600 image. So it almost looks like ImageSize overrides ImageResolution. Can anyone confirm this? The documentation says RasterSize overrides ImageResolution, but doesn't say anything about ImageSize. $\endgroup$ – DumpsterDoofus Nov 3 '14 at 15:00
  • $\begingroup$ @DumpsterDoofus: Yes, exactly, overrides. In fact, for any fixed ImageSize varying the value of resolution does take no effect. RasterSize is also an option which is responsible for "resolution" of the image (number of pixel dots in it). ImageSize is rather the size of the image on the screen, or equivalent physical size of the image on the paper. Therefore, one would expect ImageResolution option to behave similarly to RasterSize option. $\endgroup$ – Alexey Bobrick Nov 3 '14 at 15:20
  • $\begingroup$ Related: (5442) $\endgroup$ – Mr.Wizard Nov 4 '14 at 6:22
  • $\begingroup$ And also very useful notes on exporting graphics I found in Szabolics answer [here][1]. However, in both above links the focus on how to export graphics properly. Whilst this question is on why does Rasterize not function quite as properly as it supposedly should. [1]: mathematica.stackexchange.com/questions/736/… $\endgroup$ – Alexey Bobrick Nov 4 '14 at 11:13
15
$\begingroup$

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.

$\endgroup$
  • $\begingroup$ Thanks for an amazing answer and a wonderful spelunking tour! It might be a bug, it seems. Would probably be useful if someone could check for this in older versions. Will forward to WRI, for starters. $\endgroup$ – Alexey Bobrick Nov 3 '14 at 16:44
  • 1
    $\begingroup$ I have checked it in versions 5.2 and 7.0.1. In version 5.2 the code Export["test.tiff",Graphics[{Circle[{0,0},{2,1}],Text["x^2+y^2<1",{0,0}]}],ImageSize->72,ImageResolution->300] exports correct TIFF with resolution 300 dpi and width 1 inch, while in version 7.0.1 it exports with resolution 72 dpi. Considering also this comment we can conclude that the bug was introduced in v.6 or 7. $\endgroup$ – Alexey Popkov Nov 4 '14 at 11:47
  • $\begingroup$ Thanks greatly for checking this! Yes, one would indeed think it useful to use ImageSize and ImageResolution in combination. Even more importantly, it is not so hard to overlook that Resolution setting does not work. $\endgroup$ – Alexey Bobrick Nov 4 '14 at 11:52
6
$\begingroup$

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}}]

enter image description here


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:

enter image description here

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}

enter image description here

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.

$\endgroup$
  • $\begingroup$ Yes, thank you! I am aware that ImageResolution works on its own. However, ImageSize is not supposed to override ImageResolution. For example, it does not override RasterSize, which serves the same function roughly, as ImageResolution. $\endgroup$ – Alexey Bobrick Nov 3 '14 at 15:17
  • $\begingroup$ I have added more information on this in the question edit. $\endgroup$ – Alexey Bobrick Nov 3 '14 at 15:42
  • 1
    $\begingroup$ @Mr.Wizard You have not specified the second argument of Rasterize as "Image" and you get Graphics object instead. This is the reason why you get roughly equal ImageDimensions in all cases: all of them are equal to ImageSize and do not reflect actual resolution of the Raster object inside of Graphics. Use Dimensions /@ r[[All, 1, 1]] for obtaining actual information. $\endgroup$ – Alexey Popkov Nov 3 '14 at 15:43
  • $\begingroup$ @Alexey that is what I was alluding to with "There is more than one kind of image size in play here." $\endgroup$ – Mr.Wizard Nov 4 '14 at 1:53
  • 1
    $\begingroup$ I did not mean that it is reasonable to define ImageSize ambiguously. I mean that it is reasonable to set higher priority for Export-related functionality as compared to on-screen rendering while the latter works satisfactory well. In this perspective the ambiguous ImageSize case is just gedanken functionality and is semi-bug because the necessary ScreenResolution functionality is still under-implemented. $\endgroup$ – Alexey Popkov Nov 4 '14 at 8:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.