2017-09-01 33 views
0

我已阅读了关于视网膜显示器上画布模糊问题的多个建议(例如,使用window.devicePixelRatio方法; here,herehere),但我还没有将建议的解决方案应用于我的特定问题。下面的脚本首先创建一个包含一些随机图像数据(显示模糊)的画布,然后将图像导出到SVG元素并重新调整它(当然仍然是模糊的)。 2016年末,我使用触摸屏和Safari浏览器使用MBP。有关如何避免模糊并实现清晰边缘的任何建议?请记住,初始imageData应该有固定的宽度和高度。视网膜显示(MPB)上的画布图像数据

<!DOCTYPE html> 
<meta charset="utf-8"> 

<script src="https://d3js.org/d3.v4.min.js"></script> 

<body></body> 

<script type="text/javascript"> 

    var width = 100; 
    var height = 100; 

    var canvas = d3.select("body").append("canvas"); 
    context = canvas.node().getContext("2d"), 

    canvas 
    .attr("width", width) 
    .attr("height", height) 
    .style("width", width + "px") 
    .style("height", height + "px") 

    //this is the part that should normally take care of blurriness 
    if (window.devicePixelRatio > 1) { 
     var devicePixelRatio = window.devicePixelRatio || 1; 
     var backingStoreRatio = context.webkitBackingStorePixelRatio || 
     context.backingStorePixelRatio || 1; 
     var ratio = devicePixelRatio/backingStoreRatio; 
     canvas 
     .attr('width', width * ratio) 
     .attr('height', height * ratio) 
     .style('width', width + 'px') 
     .style('height', height + 'px'); 
     context.scale(ratio, ratio); 
    } 

    var imageData = context.createImageData(width, height); 

    for (var i = 0, l = 0; i<height; ++i) { 
     for (j = 0; j<width; ++j, l += 4) { 
      imageData.data[l+0] = Math.round(Math.random() * 255); 
      imageData.data[l+1] = Math.round(Math.random() * 255); 
      imageData.data[l+2] = Math.round(Math.random() * 255); 
      imageData.data[l+3] = Math.round(Math.random() * 255); 
     } 

    } 

    context.putImageData(imageData, 0, 0); 
    var ImageD = canvas.node().toDataURL("img/png"); 

    var svg = d3.select('body').append('svg').attr('width', width*5).attr('height', height*5); 
    svg.append("svg:image").datum(ImageD).attr("xlink:href", function(d) {return d}) 
        .attr("height", height*5).attr("width", width*5) 

</script> 
+0

采取的背景下,为什么你没有能够应用针对您的具体问题提出解决方案 –

+0

好吧,上面的脚本实现这些解决方案并没有成功 – spyrostheodoridis

+0

视网膜有CSS像素设置为2个物理像素。画布分辨率设置为CSS像素。要修复,请将画布分辨率设置为画布大小的2倍。通过'const bounds = element.getBoundingClientRect();获取大小;'然后将画布大小设置为'canvas.width = bounds.width * 2'和'canvas.height = bounds.height * 2' – Blindman67

回答

0

我终于找到了解决办法。我用下面的组合:window.devicePixelRatio用于获取视网膜像素比例,关屏从here采取的帆布,然后扩大从here

<!DOCTYPE html> 
<meta charset="utf-8"> 

<script src="https://d3js.org/d3.v4.min.js"></script> 

<body></body> 

<script type="text/javascript"> 

    const width = 20; 
    const height = 20; 
    const scale = 10; // the higher the number the crisper the custom image 

    var canvas = d3.select("body").append("canvas"); 
    context = canvas.node().getContext("2d"); 

    const ratio = window.devicePixelRatio || 1; 
    canvas.attr('width', width * ratio * scale) 
     .attr('height', height * ratio * scale) 
     .style('width', width * scale + 'px') 
     .style('height', height * scale + 'px'); 

    var imageData = context.createImageData(width, height); 

    for (var i = 0, l = 0; i<height; ++i) { 
     for (j = 0; j<width; ++j, l += 4) { 
      imageData.data[l+0] = Math.round(Math.random() * 255); 
      imageData.data[l+1] = Math.round(Math.random() * 255); 
      imageData.data[l+2] = Math.round(Math.random() * 255); 
      imageData.data[l+3] = Math.round(Math.random() * 255); 
     } 
    } 

    const offCtx = canvas.node().cloneNode().getContext('2d'); // create an off screen canvas 
    offCtx.putImageData(imageData, 0,0); 
    context.scale(ratio * scale, ratio * scale); 
    context.mozImageSmoothingEnabled = false; 
    context.imageSmoothingEnabled = false; 
    context.drawImage(offCtx.canvas, 0,0); 

    //export image 
    var ImageD = canvas.node().toDataURL("img/png"); 
    //load image 
    d3.select('body').append('svg').attr("height", 500).attr("width", 500).append("svg:image").datum(ImageD).attr("xlink:href", function(d) {return d}) 
       .attr("height", 500).attr("width", 500); 

</script> 
1

图像数据不是情境感知的。

如果您使用上下文进行渲染,但您正在将像素直接写入图像缓冲区,则您的代码可能会有效。这不受二维上下文转换的影响,因此您的代码不会放大。

在你的代码能扩展画布渲染并不适用于图象 - 行

context.scale(ratio, ratio); 

简单的解决

一个简单的修复,如果你知道该设备是视网膜。它使画布分辨率加倍,然后设置随机像素。为了保持您的原始代码,我将2 x 2像素设置为相同的随机值。模糊将消失,但随机模式保持不变。

const width = 100; 
const height = 100; 
const w = width; // because I hate cluttered code 
const h = height; 

const canvas = document.createElement("canvas"); 
document.body.appendChild(canvas); 
const ctx = canvas.getContext("2d"); 

canvas.width = w * 2; 
canvas.height = h * 2; 
canvas.style.width = w + "px"; 
canvas.style.height = h + "px"; 

const imageData = ctx.createImageData(w * 2, h * 2); 
// get 32bit view of data 
const b32 = new Uint32Array(imageData.data.buffer); 
// this is the part that you need to change as the canvas resolution is double 

for (let i = 0, l = 0; i< h; i ++) { 
    for (let j = 0; j < w; j ++) { 
     const idx = i * w* 2 + j * 2; 
     b32[idx + w + 1] = b32[idx + w] = b32[idx + 1] = b32[idx] = (Math.random() * 0xFFFFFFFF) | 0; 
    } 
} 

ctx.putImageData(imageData, 0, 0); 
const ImageD = canvas.toDataURL("img/png"); 

const svg = d3.select('body').append('svg').attr('width', width*5).attr('height', height*5); 
svg.append("svg:image").datum(ImageD).attr("xlink:href", function(d) {return d}) 
       .attr("height", height*5).attr("width", width*5) 
+0

上面的脚本仍然会产生模糊的图像。而且它改变了图像尺寸的比例。 – spyrostheodoridis

+0

@spyrostheodoridis抱歉,我的坏应该有'ctx.createImageData(w,h); 'as'ctx.createImageData(w * 2,h * 2);'虽然这并不能解释方面。至于VGA,您将图像添加为5 *宽度和5 *高度,如果您的物理像素分辨率不匹配,它总是会模糊不清 – Blindman67