2017-09-01 19 views
0

網膜ディスプレイ(例えば、window.devicePixelRatioアプローチを使用して、herehere、またhereを使用して)のキャンバスぼやけの問題に関する複数の提案を読んだが、私はできなかった私の特定の問題に提案された解決策を適用する。次のスクリプトは、まず不透明な画像データを含むキャンバスを作成し、その画像をSVG要素に書き出して再スケーリングします(まだぼやけています)。私は2016年後半にタッチバーとサファリを使用して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

から取られたコンテキストをスケールアップするためwindow.devicePixelRatio:私は、次の組み合わせを使用しますあなたの特定の問題に対する解決策を提案しますか? –

+0

よく、上記のスクリプトは、これらのソリューションを成功させないで実装します。 – spyrostheodoridis

+0

RetinaはCSSピクセルを2物理ピクセルに設定しています。キャンバス解像度はCSSピクセルに設定されます。修正するには、キャンバス解像度をキャンバスサイズの2倍に設定します。 'const bounds = element.getBoundingClientRect();でサイズを取得すると、' canvas.width = bounds.width * 2'と 'canvas.height = bounds.height * 2'にキャンバスサイズを設定します。 – Blindman67

答えて

0

私は最終的に解決策を見つけました。網膜画素率、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

画像データはコンテキスト認識されません。

レンダリングにコンテキストを使用していても、画像バッファに直接ピクセルを書き込んでいる場合は、使用していたコードは機能します。これは2Dコンテキスト変換によって影響を受けないため、コードは拡大されません。あなたが画像データには適用されませんキャンバスのレンダリングをスケールアップライン

context.scale(ratio, ratio); 

をコード内で

シンプルな修正

デバイスが網膜であることがわかっている場合は簡単な修正です。それはキャンバス解像度を2倍にし、ランダムピクセルを設定します。元のコードを維持するために、2ピクセルを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); 'ctx.createImageData(w * 2、h * 2);'として説明していますが、それはその側面を説明するものではありません。 VGAの場合、5×幅と5×高さの画像を追加していますが、実際のピクセル解像度と一致しない場合は常にぼやけてしまいます – Blindman67

関連する問題