简体   繁体   中英

Very High Resolution Images in HTML5 Canvas

At the end of this question is an SSCCE to display a 24000x12000 Miller projection of satellite imagery on an HTML5 canvas. It has a couple problems:

  1. Rather than showing the entire image in one screen as I desire only a small section of the upper left corner is displayed.
  2. The image suffers from extreme pixellation that should not appear at the scale displayed because the image is very high resolution

在此处输入图片说明

  • The image used is available at Wikimedia . I renamed it "world.jpg".
  • This is not a normal web application and the large image will not be downloaded during application execution so any advice to not require downloading such a large image is moot.
  • The application will dynamically zoom into various map areas, thus the large image size.
  • In the real code I use an external stylesheet and javascript file. I integrated them into the html solely for the SSCCE.

This is the code.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>The Earth</title>
<script type="text/javascript">
function draw() {
   var canvas = document.getElementById("canvas");
   var ctx = canvas.getContext("2d");
   var map = new Image();
   map.src = "world.jpg";
   map.onload = function() {
      var width = window.innerWidth;
      var height = window.innerHeight;
      ctx.drawImage(map, 0, 0, width, height);
   };
}
</script>
<style>
html, body {
  width:  100%;
  height: 100%;
  margin: 0px;
}
#canvas {
   width: 100%;
   height: 100%;
   position: absolute;
   top: 0px;
   left: 0px;
   background-color: rgba(0, 0, 0, 0);
}
</style>
</head>
<body onload="draw();">
   <canvas id="canvas"></canvas>
</body>
</html>

Use the version of context.drawImage that clips and scales the original image:

context.drawImage(
    sourceImage,
    clipSourceAtX, clipSourceAtY, sourceClipWidth, sourceClipHeight,
    canvasX, canvasY, canvasDrawWidth, canvasDrawHeight
)

For example, assume that you are focusing on coordinate [x==1000,y==500] on the image.

To display the 640px x 512px portion of the image at [1000,500] you can use drawImage like this:

context.drawImage(

    // use "sourceImage" 
    sourceImage

    // clip a 640x512 portion of the source image at left-top = [1000,500]
    sourceImage,1000,500,640,512,

    // draw the 640x512 clipped subimage at 0,0 on the canvas
    0,0,640,512            
);

A demo: http://jsfiddle.net/m1erickson/MtAEY/

在此处输入图片说明

Here's the working javascript code, formatted nicely.

function draw() {
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");
  var map = new Image();
  map.src = "world.jpg";
  map.onload = function() {
    var width = window.innerWidth;
    var height = window.innerHeight;
    canvas.width=width;
    canvas.height=height;
    var mapWidth=map.width;
    var mapHeight=map.height;
    var scale=scalePreserveAspectRatio(mapWidth,mapHeight,width,height);
    ctx.mozImageSmoothingEnabled = false;
    ctx.imageSmoothingEnabled = false;
    ctx.webkitImageSmoothingEnabled = false;
    ctx.drawImage(map, 0, 0, mapWidth, mapHeight, 0, 0, mapWidth*scale, mapHeight*scale);
  };
}
function scalePreserveAspectRatio(imgW,imgH,maxW,maxH){
  return(Math.min((maxW/imgW),(maxH/imgH)));
}

The key is the two lines

canvas.width=width;
canvas.height=height;

Simply setting these to 100% in CSS doesn't work, the 100% is apparently not 100% of the inner dimensions of the window as I assumed. Since these dimensions are dynamic they must be set via JS not CSS.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM