क्या मैं HTML <कैनवास> तत्व पर एंटीअलियासिंग को बंद कर सकता हूं?


85

मैं <canvas>तत्व के साथ खेल रहा हूं , रेखाएं खींच रहा हूं और ऐसे।

मैंने देखा है कि मेरी विकर्ण रेखाएँ एंटीअलियास्ड हैं। मैं क्या कर रहा हूँ के लिए दांतेदार देखो पसंद करेंगे - क्या इस सुविधा को बंद करने का कोई तरीका है?


मुझे लगता है कि यह ब्राउज़र से संबंधित है। हो सकता है कि आपके द्वारा उपयोग किए जाने वाले सॉफ़्टवेयर के बारे में कुछ अतिरिक्त जानकारी उपयोगी हो।
तोमलक

मैं एक क्रॉस-ब्राउज़र विधि पसंद करूंगा, लेकिन एक विधि जो किसी भी एक ब्राउज़र पर काम करती है, वह अभी भी मेरे लिए दिलचस्प होगी
Blorgbeard

मैं सिर्फ यह देखना चाहता था कि क्या इस विषय पर अभी तक कोई बदलाव हुआ है?
शाश्वत 3


क्या इस पर कोई अपडेट है?
रोलैंड

जवाबों:


60

छवियों के लिए अब वहाँ है context.imageSmoothingEnabled= false

हालाँकि, ऐसा कुछ भी नहीं है जो स्पष्ट रूप से लाइन ड्राइंग को नियंत्रित करता है। आपको अपनी खुद की लाइनों ( कठिन तरीका ) का उपयोग करके getImageDataऔर आकर्षित करने की आवश्यकता हो सकती है putImageData


1
मैं एक जावास्क्रिप्ट लाइन एल्गोरिथ्म के प्रदर्शन के बारे में आश्चर्य करता हूं .. शायद कुछ बिंदु पर ब्रेसेनहैम को दे सकता हूं।
Blorgbeard

ब्राउज़र विक्रेता हाल ही में नए सुपर-फास्ट जेएस इंजनों का दोहन कर रहे हैं, इसलिए अंत में इसके लिए एक अच्छा उपयोग होगा।
कोर्नेल

1
क्या यह वास्तव में काम करता है? मैं एक लाइन का उपयोग कर रहा हूँ, putImageData लेकिन यह अभी भी पास के पिक्सल के aliasing करता है लानत है।
पचेरियर

अगर मैं एक छोटे कैनवस (कैश) की ओर आकर्षित होता हूं और फिर उस सेटिंग के साथ किसी अन्य कैनवस को आकर्षित करता हूं, तो क्या यह इरादा के अनुसार काम करेगा?
स्पार्क

69

1-pixelजैसे निर्देशांक पर अपनी रेखाएँ बनाएँ ctx.lineTo(10.5, 10.5)। बिंदु पर एक-पिक्सेल रेखा खींचने का (10, 10)अर्थ है, 1उस स्थिति में यह पिक्सेल से पहुंचता 9.5है10.5 खींचने का जिसके परिणामस्वरूप दो रेखाएँ होती हैं जो कैनवास पर आ जाती हैं।

एक अच्छा ट्रिक हमेशा 0.5उस वास्तविक समन्वय को जोड़ने की ज़रूरत नहीं है जिसे आप ड्रा करना चाहते हैं यदि आपको बहुत-सी एक-पिक्सेल लाइनें मिल गई हैं, ctx.translate(0.5, 0.5)तो शुरुआत में आपके पूरे कैनवास पर है।


हम्म, मुझे इस तकनीक के उपयोग से एंटी-अलियासिंग से छुटकारा पाने में परेशानी हो रही है। हो सकता है, मुझे कुछ समझने की याद आ रही हो? क्या आप एक उदाहरण पोस्ट करने के बारे में कुछ सोचेंगे?
ज़ावि

7
इससे एंटीएलियासिंग से छुटकारा नहीं मिलता है, लेकिन इससे एंटीएलियास लाइनें बहुत बेहतर दिखती हैं --- जैसे कि उन शर्मनाक क्षैतिज या ऊर्ध्वाधर लाइनों से छुटकारा पाना जो दो पिक्सेल मोटी होती हैं जब आप वास्तव में एक पिक्सेल चाहते थे।
डेविड

1
@ चोंच: नहीं, रेखाएँ पिक्सेल के कोनों के बीच खींची जाती हैं। जब आपकी लाइन 1 पिक्सेल चौड़ी होती है, जो किसी भी दिशा में आधे पिक्सेल का विस्तार करती है
एरिक

+0.5 जोड़ना मेरे लिए काम करता है, लेकिन ctx.translate(0.5,0.5)नहीं। FF39.0 पर
पाउलो

आपका बहुत बहुत धन्यवाद! मुझे विश्वास नहीं हो रहा है कि मेरे पास बदलाव के लिए वास्तविक 1px लाइनें हैं!
चंकी चंक

24

यह मोज़िला फ़ायरफ़ॉक्स में किया जा सकता है। इसे अपने कोड में जोड़ें:

contextXYZ.mozImageSmoothingEnabled = false;

ओपेरा में यह वर्तमान में एक सुविधा अनुरोध है, लेकिन उम्मीद है कि इसे जल्द ही जोड़ा जाएगा।


ठंडा। आपके योगदान के लिए +1। मुझे आश्चर्य है कि अगर AA के लेएंड्राविंग में तेजी आती है
marcusklaas

7
ओपी अल-एंटी-उर्फ लाइनों को चाहता है, लेकिन यह केवल छवियों पर काम करता है। प्रति कल्पना है, यह निर्धारित करता है"whether pattern fills and the drawImage() method will attempt to smooth images if their pixels don't line up exactly with the display, when scaling images up"
rvighne

14

यह एंटीअलियास वेक्टर ग्राफिक्स होना चाहिए

सदिश ग्राफिक्स के सही प्लॉटिंग के लिए एंटीएलियासिंग की आवश्यकता होती है जिसमें गैर-पूर्णांक निर्देशांक (0.4, 0.4) शामिल होते हैं, जो सभी लेकिन बहुत कम ग्राहक करते हैं।

जब गैर-पूर्णांक निर्देशांक दिए जाते हैं, तो कैनवास में दो विकल्प होते हैं:

  • एंटीलियास - पूर्णांक को गैर-पूर्णांक एक (यानी, गोलाई त्रुटि) से कितनी दूर है, इसके आधार पर समन्वय के चारों ओर पिक्सल्स को पेंट करें।
  • दौर - गैर-पूर्णांक समन्वय के लिए कुछ राउंडिंग फ़ंक्शन लागू करें (इसलिए 1.4 1 हो जाएगा, उदाहरण के लिए)।

बाद की रणनीति स्थिर ग्राफिक्स के लिए काम करेगी, हालांकि छोटे ग्राफिक्स के लिए (2 के त्रिज्या के साथ एक चक्र) घटता एक चिकनी वक्र के बजाय स्पष्ट कदम दिखाएगा।

असली समस्या यह है कि जब ग्राफिक्स का अनुवाद किया जाता है (स्थानांतरित) - एक पिक्सेल और दूसरे (1.6 => 2, 1.4 => 1) के बीच कूदता है, तो इसका मतलब है कि आकार की उत्पत्ति मूल कंटेनर के संबंध में कूद सकती है (लगातार स्थानांतरण। 1 पिक्सेल ऊपर / नीचे और बाएं / दाएं)।

कुछ सुझाव

टिप # 1 : आप कैनवास को स्केल करके (या x कहकर) एंटीएलियाज़िंग को नरम (या कठोर) कर सकते हैं, फिर पारस्परिक पैमाने (1 / x) को ज्यामितीय रूप से स्वयं (कैनवास का उपयोग न करके) लागू करें।

तुलना करें (कोई स्केलिंग नहीं):

कुछ आयतें

(कैनवास स्केल: 0.75; मैनुअल स्केल: 1.33):

नरम किनारों के साथ एक ही आयत

और (कैनवास स्केल: 1.33; मैनुअल स्केल: 0.75):

गहरे किनारों के साथ एक ही आयत

टिप # 2 : अगर एक जगमगाता हुआ लुक वास्तव में आपके बाद का है, तो हर शेप को कुछ समय (बिना मिटाए) खींचने की कोशिश करें। प्रत्येक ड्रॉ के साथ, एंटीएलियासिंग पिक्सल्स गहरे रंग के हो जाते हैं।

की तुलना करें। एक बार ड्राइंग के बाद:

कुछ रास्ते

तीन बार ड्राइंग के बाद:

एक ही रास्ता लेकिन गहरा और कोई दिखाई देने वाला एंटीलियासिंग नहीं।


@vanowm क्लोन करने और खेलने के लिए स्वतंत्र महसूस करता है: github.com/Izhaki/gefri । सभी छवियां / डेमो फ़ोल्डर से स्क्रीनशॉट हैं (कोड # 2 के लिए थोड़ा संशोधित कोड के साथ)। मुझे यकीन है कि आपको पूर्णांक को खींचे गए आकृतियों से परिचित कराना आसान होगा (मुझे 4 मिनट लगते हैं) और फिर प्रभाव देखने के लिए बस खींचें।
इजाकी

9

मैं एक कस्टम लाइन एल्गोरिथ्म का उपयोग करके सब कुछ आकर्षित करूंगा जैसे कि ब्रेसेनहम का लाइन एल्गोरिदम। इस जावास्क्रिप्ट कार्यान्वयन की जाँच करें: http://members.chello.at/easyfilter/canvas.html

मुझे लगता है कि यह निश्चित रूप से आपकी समस्याओं को हल करेगा।


2
वास्तव में मुझे जो चाहिए था, केवल एक चीज जो मैं जोड़ूंगा वह यह है कि आपको लागू करने की आवश्यकता है setPixel(x, y); मैंने यहां स्वीकृत उत्तर का उपयोग किया: stackoverflow.com/questions/4899799/…
टीना वल

8

मैं जोड़ना चाहता हूं कि एक छवि को डाउन करते समय और कैनवास पर ड्राइंग करते समय मुझे परेशानी हुई थी, यह तब भी स्मूथिंग का उपयोग कर रहा था, भले ही यह अपस्कलिंग करते समय उपयोग नहीं कर रहा था।

मैंने इसका उपयोग करके हल किया:

function setpixelated(context){
    context['imageSmoothingEnabled'] = false;       /* standard */
    context['mozImageSmoothingEnabled'] = false;    /* Firefox */
    context['oImageSmoothingEnabled'] = false;      /* Opera */
    context['webkitImageSmoothingEnabled'] = false; /* Safari */
    context['msImageSmoothingEnabled'] = false;     /* IE */
}

आप इस फ़ंक्शन का उपयोग इस तरह कर सकते हैं:

var canvas = document.getElementById('mycanvas')
setpixelated(canvas.getContext('2d'))

हो सकता है कि यह किसी के लिए उपयोगी हो।


संदर्भ क्यों नहीं ।imageSmoothingEnabled = false?
मार्टिज़न शेफ़र

यह उस समय काम नहीं आया जब मैंने अपना उत्तर लिखा था। क्या अब यह काम करता है?
इरी ०१

1
यह किया, यह पूरी तरह से एक ही बात है, जावास्क्रिप्ट लेखन में obj ['नाम'] या obj.name हमेशा रहा है, और हमेशा एक ही रहेगा, एक वस्तु नामित मूल्यों (टुपल्स) का एक संग्रह है, कुछ का उपयोग करके जैसा दिखता है हैश टेबल, दोनों नोटेशन को एक ही तरह से माना जाएगा, ऐसा कोई कारण नहीं है कि आपके कोड से पहले काम नहीं किया जाएगा, सबसे खराब रूप से यह एक मूल्य प्रदान करता है जिसका कोई प्रभाव नहीं है (क्योंकि यह दूसरे ब्राउज़र के लिए अभिप्रेत है। एक सरल उदाहरण: लिखें। obj = {a: 123}; कंसोल.लॉग (obj ['a'] === obj.a? "हाँ इसका सही": "नहीं यह नहीं है")
Martijn Scheffer

मैंने सोचा था कि आपके पास अन्य सभी चीजें क्यों हैं, मेरी टिप्पणी से मेरा मतलब यह है कि उस समय ब्राउज़रों को विभिन्न गुणों की आवश्यकता थी।
इरी ०३

ठीक है हाँ :) मैं वाक्य रचना के बारे में बात कर रहा था, कोड की वैधता ही नहीं (यह काम करता है)
Martijn Scheffer

6
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5;

इस कॉम्बो के साथ मैं अच्छी 1px पतली रेखाएँ खींच सकता हूँ।


6
आपको .5 के लिए लाइन सेट करने की आवश्यकता नहीं है .5 ... यह (या चाहिए) केवल इसे आधा अपारदर्शिता बनाता है।
अयादन

4

एक बहुत ही सीमित ट्रिक नोटिस करें। यदि आप 2 रंगों की छवि बनाना चाहते हैं, तो आप रंग # 000000 के साथ पृष्ठभूमि पर रंग # 010101 के साथ अपनी मनचाही आकृति बना सकते हैं। एक बार यह हो जाने पर, आप प्रत्येक पिक्सेल को imageData.data [] में परीक्षण कर सकते हैं और 0xFF पर सेट कर सकते हैं जो कुछ भी नहीं है xxx:

imageData = context2d.getImageData (0, 0, g.width, g.height);
for (i = 0; i != imageData.data.length; i ++) {
    if (imageData.data[i] != 0x00)
        imageData.data[i] = 0xFF;
}
context2d.putImageData (imageData, 0, 0);

इसका नतीजा एक गैर-एंटिअलिसिड ब्लैक एंड व्हाइट तस्वीर होगी। यह बिल्कुल सही नहीं होगा, क्योंकि कुछ एंटीलियासिंग लगेंगे, लेकिन यह एंटीलियासिंग बहुत सीमित होगा, आकार का रंग पृष्ठभूमि के रंग की तरह बहुत अधिक होगा।


1

उन लोगों के लिए जो अभी भी उत्तर की तलाश कर रहे हैं। यहाँ मेरा समाधान है।

मान लें कि छवि 1 चैनल ग्रे है। मैंने अभी ctx.stroke () के बाद थ्रेसहोल्ड किया।

ctx.beginPath();
ctx.moveTo(some_x, some_y);
ctx.lineTo(some_x, some_y);
...
ctx.closePath();
ctx.fill();
ctx.stroke();

let image = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height)
for(let x=0; x < ctx.canvas.width; x++) {
  for(let y=0; y < ctx.canvas.height; y++) {
    if(image.data[x*image.height + y] < 128) {
      image.data[x*image.height + y] = 0;
    } else {
      image.data[x*image.height + y] = 255;
    }
  }
}

यदि आपका इमेज चैनल 3 या 4 है, तो आपको सरणी इंडेक्स को संशोधित करने की आवश्यकता है

x*image.height*number_channel + y*number_channel + channel

0

StashOfCode के जवाब पर सिर्फ दो नोट:

  1. यह केवल एक ग्रेस्केल, अपारदर्शी कैनवस के लिए काम करता है (सफेद के साथ fillRect तो काले, या इसके साथ आकर्षित)
  2. यह तब विफल हो सकता है जब लाइनें पतली होती हैं (~ 1px लाइन चौड़ाई)

इसके बजाय ऐसा करना बेहतर है:

स्ट्रोक करें और भरें #FFFFFF, फिर ऐसा करें:

imageData.data[i] = (imageData.data[i] >> 7) * 0xFF

जो इसे 1px चौड़ाई वाली लाइनों के लिए हल करता है।

इसके अलावा, StashOfCode का समाधान एकदम सही है क्योंकि इसमें आपको अपने स्वयं के रेखांकन कार्यों को लिखने की आवश्यकता नहीं है (न केवल लाइनें, बल्कि बेज़ियर, परिपत्र आर्क्स, छिद्रों के साथ बहुभुज, आदि ...)


0

यहां जावास्क्रिप्ट में ब्रेसेनहैम के एल्गोरिथ्म का एक बुनियादी कार्यान्वयन है। यह इस विकिपीडिया लेख में वर्णित पूर्णांक-अंकगणितीय संस्करण पर आधारित है: https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm

    function range(f=0, l) {
        var list = [];
        const lower = Math.min(f, l);
        const higher = Math.max(f, l);
        for (var i = lower; i <= higher; i++) {
            list.push(i);
        }
        return list;
    }

    //Don't ask me.
    //https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
    function bresenhamLinePoints(start, end) {

        let points = [];

        if(start.x === end.x) {
            return range(f=start.y, l=end.y)
                        .map(yIdx => {
                            return {x: start.x, y: yIdx};
                        });
        } else if (start.y === end.y) {
            return range(f=start.x, l=end.x)
                        .map(xIdx => {
                            return {x: xIdx, y: start.y};
                        });
        }

        let dx = Math.abs(end.x - start.x);
        let sx = start.x < end.x ? 1 : -1;
        let dy = -1*Math.abs(end.y - start.y);
        let sy = start.y < end.y ? 1 : - 1;
        let err = dx + dy;

        let currX = start.x;
        let currY = start.y;

        while(true) {
            points.push({x: currX, y: currY});
            if(currX === end.x && currY === end.y) break;
            let e2 = 2*err;
            if (e2 >= dy) {
                err += dy;
                currX += sx;
            }
            if(e2 <= dx) {
                err += dx;
                currY += sy;
            }
        }

        return points;

    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.