HTML5 Canvas and blurry rendering. devicePixelRatio is needed

Hi singmajesty,

I’m building an HTML5 web app for mobile and noticed that when I switched to the canvas rendering mode from dom, everything looked blurry, which was not the case with dom. And this is when using 0 for both the window width and height in my project.xml, so basically fullscreen. I did some digging and concluded that it’s because the element’s intrinsic width and height (not the style width/height properties) values are set to 320px and 568px, which is the CSS width and height of my iPhone as opposed to 640px x 1136px, which is the actual screen resolution.

According to what I’ve read online, the canvas width and height need to match the actual device’s screen resolution or else the browser would be upscaling the canvas’ contents and thus resulting the bluriness. And then the style width and height of the canvas element would need to be 320px and 568px so that it fills up the entire screen and doesn’t extend outside the screen bounds.

I modified the lime._backend.html5.HTML5Window class to incorporate the Browser.window.devicePixelRatio when calculating the intrinsic widths and heights for the canvas element. I had to also modify the CanvasRenderer (added a context.scale(devicePixelRatio, devicePixelRatio) line), CanvasShape, and CanvasBitmap (swapping out context.setTransform() with context.transform()) to get everything to render correctly, though I don’t know if something else will break b/c of those changes.

Question is, did I have to go through all this or was there an easier way to deal with this without having had to those 4 lime classes which I would have wanted to avoid.

2 Likes

I would recommend seeing if we could consider supporting window.scale

When we support “retina” resolution on iOS and OS X, the desktop returns coordinates in points instead of pixels. On the Lime side, we need to do mouse.x * window.scale in order to get the “real” coordinates of mouse events. Window resize events work similarly.

Perhaps we could support window.scale on HTML5, so on the Lime side, it behaves similarly, but the scale value becomes 2 and things become sharper.

No changes would be needed on the OpenFL side, it’s already designed to handle this.

I think the missing piece is that we will (in the future) support a way to disallow retina resolution, where performance is a concern. That’s why we don’t support it by default on HTML5

Just wondering if there’s been any followup regarding this issue. I’m getting blurry text on an ipad :frowning:

1 Like

Try to use use -Ddom renderer (if you can so).

Afraid I can’t use DOM. But I got it to work with the below (after a lot of fiddling!).

<script type="text/javascript">
	
  	var scale =  window.devicePixelRatio;
  
  	if(scale==1){
  		lime.embed("openfl-content", 0, 0, "FFFFFF");
  	}
    else{
     
      w = window.innerWidth;
      h = window.innerHeight;
 
      lime.embed("openfl-content", w*2, h*2, "FFFFFF");

      var canvas = document.getElementById ("openfl-content").firstChild;

      canvas.style.width = String(w)+"px";
      canvas.style.height =  String(h)+"px";
      context = canvas.context2d;
      context.translate(.5,.5);
    }
  	
  	
</script>
1 Like

I don’t know about openfl html5 target. But js script below helps me avoid blurry effect on retina displays when I work with canvas:
var
context = canvas.getContext(‘2d’),

    devicePixelRatio = window.devicePixelRatio || 1,
    backingStoreRatio = context.webkitBackingStorePixelRatio ||
                        context.mozBackingStorePixelRatio ||
                        context.msBackingStorePixelRatio ||
                        context.oBackingStorePixelRatio ||
                        context.backingStorePixelRatio || 1,

    ratio = devicePixelRatio / backingStoreRatio;

    if (devicePixelRatio !== backingStoreRatio)
    {
        var oldWidth = canvas.width;
        var oldHeight = canvas.height;

        canvas.width = oldWidth * ratio;
        canvas.height = oldHeight * ratio;

        canvas.style.width = oldWidth + 'px';
        canvas.style.height = oldHeight + 'px';

        context.scale(ratio, ratio);
    }