Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Using Inset to place an image inside a Graphics expression with Frame -> True provides a simple way to add a scale bar, or ruler, to the image. However, I cannot find a way to get the resulting graphics to display with a one-to-one correspondence between image pixels and screen pixels. For certain images this creates nasty artifacts.

Here's an example of an image which shouldn't be resampled:

i = Image[Array[Boole[OddQ[#1 + #2]] &, {200, 200}]]

enter image description here

Suppose this image represents a region of space 0.2 m wide. To show a "ruler" I can insert the image into a graphics frame like this:

With[{x = 0.2}, 
 Graphics[Inset[i, {0, 0}, Center, x], Frame -> True, PlotRange -> x/2]]

enter image description here

The problem is quite clear - that checkerboard effect is not present in the original image. By adding an ImageSize option or manually resizing the graphics I can change the unwanted pattern, but I can't get rid of it completely.

My question is whether there is a way to embed an image into graphics so that the image is displayed at its "natural" size, i.e. with one image pixel per screen pixel. Alternatively, is there a better way to display a scale bar or ruler alongside the image?

share|improve this question
    
Texture seems to be using some other resampling algorithm (that also is destructive) {Texture[i], Polygon[{{-x/2, -x/2}, {x/2, -x/2}, {x/2, x/2}, {-x/2, x/2}}, VertexTextureCoordinates -> {{0, 0}, {1, 0}, {1, 1}, {0, 1}}]} –  ssch Aug 8 '13 at 14:44

2 Answers 2

up vote 5 down vote accepted

Well I figured it out and now it seems blindingly obvious!

@ssch had the right idea - set the image size to ImageDimensions[i] plus a little bit extra. The question is how to choose exactly the right little bit extra...

If the image perfectly fills the plot range, then the extra is the part of the graphic outside the plot range, this is of course determined by the ImagePadding option. So the solution is simply to use both ImageSize and ImagePadding and make sure that the difference between the two is exactly the size of the embedded image.

For example with a 200 pixel image and 50 pixels of padding (40 on the left and bottom, 10 on the right and top):

i = Image[Array[Boole[OddQ[#1 + #2]] &, {200, 200}]];
With[{x = 0.2}, 
 Graphics[Inset[i, {0, 0}, Center, x], Frame -> True, PlotRange -> x/2, 
  ImageSize -> 200 + 50, ImagePadding -> {{40, 10}, {40, 10}}]]

enter image description here

share|improve this answer

Applying Rasterize to the image almost works right away:

With[{x = 0.2}, 
 Graphics[Inset[Rasterize@i, {0, 0}, Center, x], Frame -> True, 
  PlotRange -> x/2]]

initial

Manual re-sizing of the Graphics yield:

manual

The same thing can be achieved without Rasterize by giving explicit ImageSize when creating the Image:

i = Image[Array[Boole[OddQ[#1 + #2]] &, {200, 200}], ImageSize -> {200, 200}]
With[{x = 0.2}, 
 Graphics[Inset[i, {0, 0}, Center, x], Frame -> True, PlotRange -> x/2]
]

The manual resizing should be possible to avoid if there is a way to specifically set the Graphics content size to be equal that of the image.

Giving Graphics ImageSize -> ImageDimensions[i] + {45, 45} seems pretty good for this case.

share|improve this answer
    
This is useful, I didn't realise the ImageSize option had that effect. Unfortunately, as your first image shows, it's possible to manually resize the frame without changing the image, so a careless user might get the scale wrong. Ideally I'd like the image to be initially displayed at its natural size but allow it to scale up or down if the graphic is manually resized. –  Simon Woods Aug 8 '13 at 19:39
    
@SimonWoods I think allowing any resizing at all will be very difficult, image rescaling is often destructive in one way or another. Here's a toy you can try some built-in resampling algorithms with. I found none to be satisfactory for this image: Manipulate[ ImageResize[i, w, Resampling -> resampling] , {w, 10, 500} , {resampling, {"Nearest", "Bilinear", "Biquadratic", "Bicubic", "Gaussian", "Lanczos", "Cosine", "Hamming", "Hann", "Blackman", "Bartlett", "Connes", "Welch", "Parzen", "Kaiser"}}] –  ssch Aug 8 '13 at 19:46
    
Oh, any resizing of this image will surely ruin it. The aim is to display it initially at the right size - if someone later decides to manually resize it they will have to put up with the poor quality. –  Simon Woods Aug 8 '13 at 19:54

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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