मैं एचटीएमएल 5 कैनवास पर आकर्षित करने के लिए निम्नलिखित कोड का उपयोग कर रहा हूं:

  const context = canvas.getContext('2d');
  context.beginPath();
  context.arc(x, y, radius, 0, 2 * Math.PI, false);
  context.fillStyle = color;
  context.fill();
  context.closePath();

हालांकि, अगर मैं अद्वितीय मान मुद्रित करता हूं:

console.log(new Set(context.getImageData(0, 0, canvas.width, canvas.height).data))

मैं देख सकता हूं कि मैं जिस रंग का उपयोग fillStyle में करता हूं, वह प्रक्षेपित हो जाता है।

मैंने निम्नलिखित झंडे जोड़कर प्रक्षेप/चिकनाई को अक्षम करने का प्रयास किया:

  context.imageSmoothingEnabled = false;
  context.webkitImageSmoothingEnabled = false;
  context.mozImageSmoothingEnabled = false;

हालाँकि, यह मदद नहीं करता है। अगर आप मुझे सलाह दे सकते हैं कि इस मुद्दे को कैसे ठीक किया जाए तो मैं बहुत आभारी रहूंगा।

0
desa 22 सितंबर 2020, 15:47

2 जवाब

सबसे बढ़िया उत्तर

पिक्सेलेटेड मंडलियों को आकर्षित करने का कोई मूल तरीका नहीं है। ऐसा करने के लिए आपको प्रत्येक पिक्सेल को मैन्युअल रूप से प्रस्तुत करना होगा।

ऐसा करने के लिए आप कई तरीके अपना सकते हैं। सबसे आम में कुछ अतिरिक्त कलाकृतियां होती हैं (जैसे असंगत रेखा चौड़ाई) जिनसे बचना मुश्किल होता है।

निम्न फ़ंक्शन Berzingham लाइन एल्गोरिथम के संशोधन का उपयोग करके एक वृत्त बनाते हैं (इसके लिए भी अच्छा है) पिक्सलेटेड लाइन्स को रेंडर करना) जिसे मिडपॉइंट सर्कल एल्गोरिथम कहा जाता है।

दुर्भाग्य से अधिकांश विधियाँ जो मनमानी रेखाएँ और वृत्त खींच सकती हैं, धीमी हैं। ऊपर बताए गए दो सबसे तेज़ मानक तरीके हैं जिनके बारे में मुझे पता है।

उदाहरण

उदाहरण पिक्सलेटेड सर्कल बनाने के लिए 3 कार्यों को परिभाषित करता है

  • pixelPixelatedCircle (लाल बाहरी वृत्त और उदाहरण में एकल नीला) वर्तमान भरण शैली का उपयोग करके एकल पिक्सेल चौड़ा वृत्त बनाता है
  • fillPixelatedCircle (उदाहरण के लिए लाल आंतरिक वृत्त) वर्तमान भरण शैली का उपयोग करके एक ठोस वृत्त बनाता है
  • strokePixelatedCircle (उदाहरण के लिए काले घेरे) एक चौड़ाई के साथ एक वृत्त रेखा खींचते हैं। चौड़ाई केवल तभी काम करती है जब यह> = 2 हो। यदि आप एक पिक्सेल चौड़ाई चाहते हैं तो पहले फ़ंक्शन का उपयोग करें। यह भी नहीं है कि यह फ़ंक्शन सर्कल को प्रस्तुत करने के लिए दूसरे कैनवास का उपयोग करता है

उदाहरण सभी तीन प्रकार खींचता है

pixelPixelatedCircle का उपयोग करके तैयार किया गया बाहरी लाल वृत्त यह प्रदर्शित करने के लिए है कि मंडलियों की गुणवत्ता सुसंगत है। बारी-बारी से 1 पिक्सेल चौड़ाई वाले वृत्त, लाल और गहरे लाल रंग के होने चाहिए। और एक बाहरी नीला बस कैनवास किनारे के घेरे को छू रहा है।

2 त्रिज्या से कम के वृत्तों के लिए ctx.rect का प्रयोग करें क्योंकि परिणाम समान होगा।

  • ध्यान दें वृत्त त्रिज्या एक पूर्णांक है इस प्रकार एक वृत्त त्रिज्या 1000 वृत्त त्रिज्या 1000.9 के समान होगा नमूना वृत्त केंद्र पर लागू होता है। उप-पिक्सेल पोजिशनिंग और त्रिज्या में सक्षम होने के लिए एक और एल्गोरिदम की आवश्यकता होगी जो धीमी हो और जिसमें निम्न गुणवत्ता वाली रेखाएं हों।

  • नोट मैंने एक साधारण ज़ूम कैनवास जोड़ा है ताकि मैं परिणाम बेहतर देख सकूं, मैं इसे हटाने जा रहा था लेकिन इसे केवल रुचि रखने वाले लोगों के लिए छोड़ दिया। यह उत्तर के लिए महत्वपूर्ण नहीं है।

const ctx = canvas.getContext("2d");
const w = canvas.width;
const h = canvas.height;
const size = Math.min(w, h);
const circleWorkCanvas = document.createElement("canvas");
const cCtx = circleWorkCanvas.getContext("2d");
function resizeCircleCanvas(ctx) {
    if (circleWorkCanvas.width !== ctx.canvas.width || circleWorkCanvas.height !== ctx.canvas.height) {
        circleWorkCanvas.width = ctx.canvas.width;
        circleWorkCanvas.height = ctx.canvas.height;
    }
}

strokePixelatedCircle(ctx, w / 2 | 0, h / 2 | 0, size * 0.35, 5);
strokePixelatedCircle(ctx, w / 2 | 0, h / 2 | 0, size * 0.3, 4);
strokePixelatedCircle(ctx, w / 2 | 0, h / 2 | 0, size * 0.25, 3);
strokePixelatedCircle(ctx, w / 2 | 0, h / 2 | 0, size * 0.2, 2);


ctx.fillStyle = "red";
fillPixelatedCircle(ctx, w / 2, h / 2, size * 0.15);
ctx.fillStyle = "blue";
pixelPixelatedCircle(ctx, w / 2, h / 2, size * 0.38);
ctx.fillStyle = "blue";
pixelPixelatedCircle(ctx, w / 2, h / 2, size * 0.5);

ctx.fillStyle = "red";
for(let v = 0.40; v < 0.49; v += 1 / size) {
    ctx.fillStyle = "#600"
    pixelPixelatedCircle(ctx, w / 2, h / 2, size * v);
    ctx.fillStyle = "#F00"
    v += 1 / size;
    pixelPixelatedCircle(ctx, w / 2, h / 2, size * v );
}


function strokePixelatedCircle(ctx, cx, cy, r, lineWidth) {
    resizeCircleCanvas(ctx);
    cCtx.clearRect(0, 0, cCtx.canvas.width, cCtx.canvas.height);
    cCtx.globalCompositeOperation = "source-over";    
    cCtx.fillStyle = ctx.strokeStyle;
    fillPixelatedCircle(cCtx, cx, cy, r + lineWidth / 2);
    cCtx.globalCompositeOperation = "destination-out";    
    fillPixelatedCircle(cCtx, cx, cy, r - lineWidth / 2);
    cCtx.globalCompositeOperation = "source-over";   
    ctx.drawImage(cCtx.canvas, 0, 0);
}
    

function fillPixelatedCircle(ctx, cx, cy, r){
    r |= 0; // floor radius
    ctx.setTransform(1,0,0,1,0,0); // ensure default transform
    var x = r, y = 0, dx = 1, dy = 1;
    var err = dx - (r << 1);
    var x0 = cx - 1| 0, y0 = cy | 0;
    var lx = x,ly = y;
    ctx.beginPath();
    while (x >= y) {
        ctx.rect(x0 - x, y0 + y, x * 2 + 2, 1);
        ctx.rect(x0 - x, y0 - y, x * 2 + 2, 1);
        if (x !== lx){
            ctx.rect(x0 - ly, y0 - lx, ly * 2 + 2, 1);
            ctx.rect(x0 - ly, y0 + lx, ly * 2 + 2, 1);
        }
        lx = x;
        ly = y;
        y++;
        err += dy;
        dy += 2;
        if (err > 0) {
            x--;
            dx += 2;
            err += (-r << 1) + dx;
        }
    }
    if (x !== lx) {
        ctx.rect(x0 - ly, y0 - lx, ly * 2 + 1, 1);
        ctx.rect(x0 - ly, y0 + lx, ly * 2 + 1, 1);
    }    
    ctx.fill();
}
function pixelPixelatedCircle(ctx, cx, cy, r){
    r |= 0;
    ctx.setTransform(1,0,0,1,0,0); // ensure default transform
    var x = r, y = 0, dx = 1, dy = 1;
    var err = dx - (r << 1);
    var x0 = cx | 0, y0 = cy  | 0;
    var lx = x,ly = y;
    var w = 1, px = x0;
    ctx.beginPath();
    var rendering = 2;
    while (rendering) {
        const yy = y0 - y;
        const yy1 = y0 + y - 1;
        const xx = x0 - x;
        const xx1 = x0 + x - 1;
        ctx.rect(xx, yy1, 1, 1);    
        ctx.rect(xx, yy, 1, 1); 
        ctx.rect(xx1, yy1, 1, 1);    
        ctx.rect(xx1, yy, 1, 1);
        if (x !== lx){
            const yy = y0 - lx;
            const yy1 = y0 + lx - 1;
            const xx = x0 - ly;
            w = px - xx;
            const xx1 = x0 + ly - w;
            ctx.rect(xx, yy, w, 1);
            ctx.rect(xx, yy1, w, 1); 
            ctx.rect(xx1, yy, w, 1); 
            ctx.rect(xx1, yy1, w, 1);
            px = xx;
        }
        lx = x;
        ly = y;
        y++;
        err += dy;
        dy += 2;
        if (err > 0) {
            x--;
            dx += 2;
            err += (-r << 1) + dx;
        }
        if (x < y) { rendering -- }
    }
    ctx.fill();
}
const ctxZ = canvasZoom.getContext("2d");
canvas.addEventListener("mousemove",(event) => {
    ctxZ.clearRect(0,0,30,30);
    ctxZ.drawImage(canvas, -(event.pageX-10), -(event.pageY-10));

});
canvas {border: 1px solid black}
#canvasZoom {
    width: 300px;
    height: 300px;
    image-rendering: pixelated;
}
<canvas id="canvas" width="300" height="300"></canvas>
<canvas id="canvasZoom" width="30" height="30"></canvas>
1
Blindman67 22 सितंबर 2020, 18:35

ऐसा प्रतीत नहीं होता है कि एक अंतर्निहित सेटिंग है जो मुझे मिल सकती है, लेकिन आप छवि डेटा के माध्यम से लूप कर सकते हैं और व्यक्तिगत पिक्सेल सेट कर सकते हैं यदि वे आपकी इच्छित सीमा के भीतर हैं।

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');

context.beginPath();
context.arc(250, 250, 250, 0, 2 * Math.PI, false);
context.fillStyle = 'rgb(255, 0, 0)';
context.fill();
context.closePath();

console.log(getDistinctColors(context).length + " distinct colors before filter");

solidifyColor(context, 255, 0, 0);

console.log(getDistinctColors(context).length + " distinct colors aftrer filter");

function solidifyColor(context, r, g, b, threshold = 3) {
  const imageData = context.getImageData(0, 0, context.canvas.width, context.canvas.height);
  for (let i = 0; i < imageData.data.length; i += 4) {
    var rDif = Math.abs(imageData.data[i + 0] - r);
    var bDif = Math.abs(imageData.data[i + 1] - b);
    var gDif = Math.abs(imageData.data[i + 2] - g);
    if (rDif <= threshold && bDif <= threshold && gDif <= threshold) {
      imageData.data[i + 0] = r;
      imageData.data[i + 1] = g;
      imageData.data[i + 2] = b;
      imageData.data[i + 3] = 255; // remove alpha
    }
  }
  context.putImageData(imageData, 0, 0);
}

function getDistinctColors(context) {
  var colors = [];
  const imageData = context.getImageData(0, 0, context.canvas.width, context.canvas.height);
  for (let i = 0; i < imageData.data.length; i += 4) {
    colors.push([
      imageData.data[i + 0], // R value
      imageData.data[i + 1], // G value
      imageData.data[i + 2], // B value
      imageData.data[i + 3] // A value
    ]);
  }
  return [...new Set(colors.map(a => JSON.stringify(a)))].map(a => JSON.parse(a));
}
<canvas id=canvas width=500 height=500></canvas>
0
I wrestled a bear once. 22 सितंबर 2020, 16:45