0

I'm drawing an image uploaded by the user on an HTML5 canvas of fixed height and width which can be dragged and resized via mouse.Now I am preserving the aspect ratio of the image with the help of the following draw function.

if(image){
        const scaleX = CANVAS_WIDTH / image?.width;
        const scaleY = CANVAS_HEIGHT / image?.height;
        const scale = Math.min(scaleX, scaleY);
    
        // Calculate the new dimensions of the image
        const newWidth = image?.width * scale;
        const newHeight = image?.height * scale;
    
        // Clear the canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);
    
        // Draw the image on the canvas
        setImageRight((CANVAS_WIDTH + newWidth) / 2);
        setImageBottom((CANVAS_HEIGHT + newHeight) / 2);
        ctx.drawImage(image, (CANVAS_WIDTH - newWidth) / 2, (CANVAS_HEIGHT - newHeight) / 2, newWidth, newHeight);
}

Here image is a part of a useState hook which I'm setting with the following code

  useEffect(() => {
  // Load the image onto the canvas
  const image = new Image();
  image.src = URL.createObjectURL(props.imageFile);
  image.onload = () => {
    setImage(image);
    setImageWidth(image.width);
    setImageHeight(image.height);
  };
}, [props.imageFile]);

useEffect(() => {
if(image)
drawImage(true,false);  
}, [image])

Now even though the aspect ratio of the initial image rendered on the canvas is preserved, the image quality is seriously affected. What can I do to preserve the image quality or reduce the degree to which the image quality is degrading? I am new to HTML5 Canvas methods. So any help would be appreciated greatly

Edit: This is how an uploaded image looks like when I draw it on the HTML canvas.

This is how an uploaded image looks like when Photoroom draws it onto the HTML canvas. You can notice the difference in quality between the two even though both are using similar dimensions of canvas as well as image.

The first one is the image I am drawing on the canvas. The second one is the image Photoroom is drawing onto their canvas. You can notice the difference in quality even though both the images, as well as the canvas, are of similar dimensions.

Sounav Saha
  • 75
  • 1
  • 7
  • Scaling an image down will lose quality, scaling up will add artifacts (blur depending on settings). You can not avoid quality loss when resizing an image. For best results ensure that the canva's resolution matches it's display size – Blindman67 Jan 06 '23 at 16:34
  • Yes, I understand that but then there are other services like [Photoroom](https://www.photoroom.com/) which use a canvas to render the resized picture on Canvas without much loss in quality. I wonder how they can do so – Sounav Saha Jan 06 '23 at 16:43
  • Without knowing what the quality loss (you ask about) looks like we can only guess the cause and if there is a solution. – Blindman67 Jan 06 '23 at 19:28
  • Added illustrations to further explain my issue @Blindman67 – Sounav Saha Jan 07 '23 at 04:06
  • The quality loss is due to upscaling. My guess is that your canvas resolution is too low (set by its `canvas.width` and `canvas.height` properties) and does not match the display size (set by the `canvas.style.width` and `canvas.style.height`). To test null canvas style size eg `canvas.style.width = null` `canvas.style.height = null` the canvas will then be displayed at its actual resolution and you will know if you need to change the resolution to match the wanted display size. Also retina displays need special attention, and page zoom will have an effect (make sure it is set to 100%) – Blindman67 Jan 07 '23 at 05:14

2 Answers2

1

It's because you’re just doing it all wrong!

Here’s how to properly load images into canvas in top quality and with the aspect ratio preserved.

I'll also demonstrate proper image scaling further down.

var Cx=C.getContext('2d'); 

Cx.imageSmoothingEnabled=true; Cx.imageSmoothingQuality='high';  // <-- these two are important for image quality


var I=new Image(); I.crossOrigin='anonymous'; I.src=ImgPath;

I.onload=function(){

 C.width=this.naturalWidth; C.height=this.naturalHeight;   // <-- these two are important for preserving the aspct ratio

 Cx.drawImage(this,0,0,C.width,C.height);

};

How to properly scale images as you load them into canvas... (replace the relevant line above with this)

 C.width=Math.round(this.naturalWidth*Scale); // it's important to round potential fractions off

 C.height=Math.round(this.naturalHeight*Scale);

NB: Typical Scale values are... 0.5, 0.25, 0.75, 1.25 etc

0

Its depend on you HTML5 canvas resolution [width x height] and also depend on ctx.drawImage() functions width x height.

Just increase width x height resolution of ctx.drawImage() function and see results.

  • But then users can upload images with dimensions possibly much larger, so I need to have a fixed dimension of my canvas and still be able to resize the image without much quality loss. You could see the illustrations in my edit to get a better idea of what I am talking about – Sounav Saha Jan 07 '23 at 04:27