6
$\begingroup$

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?

$\endgroup$
1
  • $\begingroup$ 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}}]} $\endgroup$
    – ssch
    Aug 8, 2013 at 14:44

2 Answers 2

6
$\begingroup$

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

$\endgroup$
2
$\begingroup$

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.

$\endgroup$
3
  • $\begingroup$ 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. $\endgroup$ Aug 8, 2013 at 19:39
  • $\begingroup$ @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"}}] $\endgroup$
    – ssch
    Aug 8, 2013 at 19:46
  • $\begingroup$ 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. $\endgroup$ Aug 8, 2013 at 19:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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