scale an image according to the (adaptive) canvas size

I asked this question the other day but clicked on "answered" too early.

I have an image that shoud adapt to the window size, scaling down when the window is smaller then the image. It should stop scaling up when the image is 100%. The problem is that the resize command discards the resolution of the image, so that when you scale down, then up again, the image is completely blurry. How to fix this?

function setup() {
  moon = loadImage("assets/moonwalk.jpg");
  createCanvas(windowWidth, windowHeight);
}

function draw() {
    background(255);
    image(moon,0,0);
    moon.resize(windowWidth,0)
}

Answers

  • image(moon,0,0, windowWidth, windowHeight); is not the right answer, because that will distort the image ratio.

  • I think that's the way to do it, you just have to ensure that the new width and height maintain the original aspect ratio.

  • xnaxna
    Answer ✓

    I think I solved it. It could be prettier and there is some resizing issue, but in principle, it works:

    function preload() {
      moon = loadImage('assets/moonwalk.jpg');
    }
     var realWidth;
    
    function setup() {
      createCanvas(windowWidth, windowHeight);
    imageRatio = moon.height/moon.width;
    print(imageRatio);
      realWidth=windowWidth
    }
    
    function draw() {
      background(225);
        var moonWidth;
      var moonHeight;
      moonWidth = moon.width;
      moonHeight= moon.height;
    
      if (windowWidth < realWidth) {
            moonWidth = windowWidth;
        moonHeight= moonWidth*imageRatio;
            //print("w: "+moonWidth+", h: "+moonHeight);
      }
      image(moon,0,0,moonWidth,moonHeight);
    }
    

    https://alpha.editor.p5js.org/mxa/sketches/Hy9CEZj5-

  • edited September 2017 Answer ✓

    @xna -- if resizing is rare then you can increase performance by:

    1. in setup() load the original image and copy it to a separate display image
    2. in draw() when the if triggers, copy and resize the original to the display
    3. at the end of draw(), call image() with only two coordinates -- now you aren't scaling the image every single frame.

    This should give you better performance while still avoiding the scaling compression problems you mentioned here: https://forum.processing.org/two/discussion/24139/resizing-an-image-without-losing-resolution

  • xnaxna
    edited September 2017

    @jeremydouglass -- cool. I've implemented that. I think that's as optimized as it gets:

    var moon,       //image 
        moonCopy,        //resized image of the image (visible)
        imageRatio;     //ratio of the image h/w    
    
    function preload() {
        moon=loadImage("assets/moonwalk.jpg", img => moonCopy = img.get());
    }
    
    function setup()   {
        createCanvas(windowWidth, windowHeight);
        imageRatio = moon.height/moon.width;
        print("imageRatio: "+imageRatio);
    }
    
    function draw() {
        background(255);
        image(moonCopy,0,0);
    }
    
    function windowResized() {
        resizeCanvas(windowWidth, windowHeight);
        print("resizing to: "+windowWidth+" "+windowHeight);
        if (windowWidth < moon.width){
            moonCopy = moon.get();
            moonCopy.resize(windowWidth,0);
        }
    }
    
  • @xna -- looking good! :-bd

  • Tiny caveat: When resizing the browser window very fast, it is possible to end up with a smaller image in a big window, I guess there is a limit from the Browser in how often the windowResized is called

  • This might fix that (untested):

    function draw() {
        background(255);
        image(moonCopy,0,0);
        if (windowWidth < moon.width){
            moonCopy = moon.get();
            moonCopy.resize(windowWidth,0);
        }
    }
    
    function windowResized() {
        resizeCanvas(windowWidth, windowHeight);
        print("resizing to: "+windowWidth+" "+windowHeight);
    }
    
Sign In or Register to comment.