Skip to main content

graphics - Rasterize: Resolution option not working properly



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 -> , ImageSize -> ()*(72/2.54)]

should give the same result as:


Rasterize[Test, "Image", RasterSize -> (/2.54)*(), ImageSize -> ()*(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.



Answer




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.


Comments

Popular posts from this blog

mathematical optimization - Minimizing using indices, error: Part::pkspec1: The expression cannot be used as a part specification

I want to use Minimize where the variables to minimize are indices pointing into an array. Here a MWE that hopefully shows what my problem is. vars = u@# & /@ Range[3]; cons = Flatten@ { Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; Minimize[{Total@((vec1[[#]] - vec2[[u[#]]])^2 & /@ Range[1, 3]), cons}, vars, Integers] The error I get: Part::pkspec1: The expression u[1] cannot be used as a part specification. >> Answer Ok, it seems that one can get around Mathematica trying to evaluate vec2[[u[1]]] too early by using the function Indexed[vec2,u[1]] . The working MWE would then look like the following: vars = u@# & /@ Range[3]; cons = Flatten@{ Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; NMinimize[ {Total@((vec1[[#]] - Indexed[vec2, u[#]])^2 & /@ R...

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

What is and isn't a valid variable specification for Manipulate?

I have an expression whose terms have arguments (representing subscripts), like this: myExpr = A[0] + V[1,T] I would like to put it inside a Manipulate to see its value as I move around the parameters. (The goal is eventually to plot it wrt one of the variables inside.) However, Mathematica complains when I set V[1,T] as a manipulated variable: Manipulate[Evaluate[myExpr], {A[0], 0, 1}, {V[1, T], 0, 1}] (*Manipulate::vsform: Manipulate argument {V[1,T],0,1} does not have the correct form for a variable specification. >> *) As a workaround, if I get rid of the symbol T inside the argument, it works fine: Manipulate[ Evaluate[myExpr /. T -> 15], {A[0], 0, 1}, {V[1, 15], 0, 1}] Why this behavior? Can anyone point me to the documentation that says what counts as a valid variable? And is there a way to get Manpiulate to accept an expression with a symbolic argument as a variable? Investigations I've done so far: I tried using variableQ from this answer , but it says V[1...