मैं <canvas>
तत्व के साथ खेल रहा हूं , रेखाएं खींच रहा हूं और ऐसे।
मैंने देखा है कि मेरी विकर्ण रेखाएँ एंटीअलियास्ड हैं। मैं क्या कर रहा हूँ के लिए दांतेदार देखो पसंद करेंगे - क्या इस सुविधा को बंद करने का कोई तरीका है?
मैं <canvas>
तत्व के साथ खेल रहा हूं , रेखाएं खींच रहा हूं और ऐसे।
मैंने देखा है कि मेरी विकर्ण रेखाएँ एंटीअलियास्ड हैं। मैं क्या कर रहा हूँ के लिए दांतेदार देखो पसंद करेंगे - क्या इस सुविधा को बंद करने का कोई तरीका है?
जवाबों:
छवियों के लिए अब वहाँ है context.imageSmoothingEnabled
= false
।
हालाँकि, ऐसा कुछ भी नहीं है जो स्पष्ट रूप से लाइन ड्राइंग को नियंत्रित करता है। आपको अपनी खुद की लाइनों ( कठिन तरीका ) का उपयोग करके getImageData
और आकर्षित करने की आवश्यकता हो सकती है putImageData
।
putImageData
लेकिन यह अभी भी पास के पिक्सल के aliasing करता है लानत है।
1-pixel
जैसे निर्देशांक पर अपनी रेखाएँ बनाएँ ctx.lineTo(10.5, 10.5)
। बिंदु पर एक-पिक्सेल रेखा खींचने का (10, 10)
अर्थ है, 1
उस स्थिति में यह पिक्सेल से पहुंचता 9.5
है10.5
खींचने का जिसके परिणामस्वरूप दो रेखाएँ होती हैं जो कैनवास पर आ जाती हैं।
एक अच्छा ट्रिक हमेशा 0.5
उस वास्तविक समन्वय को जोड़ने की ज़रूरत नहीं है जिसे आप ड्रा करना चाहते हैं यदि आपको बहुत-सी एक-पिक्सेल लाइनें मिल गई हैं, ctx.translate(0.5, 0.5)
तो शुरुआत में आपके पूरे कैनवास पर है।
ctx.translate(0.5,0.5)
नहीं। FF39.0 पर
यह मोज़िला फ़ायरफ़ॉक्स में किया जा सकता है। इसे अपने कोड में जोड़ें:
contextXYZ.mozImageSmoothingEnabled = false;
ओपेरा में यह वर्तमान में एक सुविधा अनुरोध है, लेकिन उम्मीद है कि इसे जल्द ही जोड़ा जाएगा।
सदिश ग्राफिक्स के सही प्लॉटिंग के लिए एंटीएलियासिंग की आवश्यकता होती है जिसमें गैर-पूर्णांक निर्देशांक (0.4, 0.4) शामिल होते हैं, जो सभी लेकिन बहुत कम ग्राहक करते हैं।
जब गैर-पूर्णांक निर्देशांक दिए जाते हैं, तो कैनवास में दो विकल्प होते हैं:
बाद की रणनीति स्थिर ग्राफिक्स के लिए काम करेगी, हालांकि छोटे ग्राफिक्स के लिए (2 के त्रिज्या के साथ एक चक्र) घटता एक चिकनी वक्र के बजाय स्पष्ट कदम दिखाएगा।
असली समस्या यह है कि जब ग्राफिक्स का अनुवाद किया जाता है (स्थानांतरित) - एक पिक्सेल और दूसरे (1.6 => 2, 1.4 => 1) के बीच कूदता है, तो इसका मतलब है कि आकार की उत्पत्ति मूल कंटेनर के संबंध में कूद सकती है (लगातार स्थानांतरण। 1 पिक्सेल ऊपर / नीचे और बाएं / दाएं)।
टिप # 1 : आप कैनवास को स्केल करके (या x कहकर) एंटीएलियाज़िंग को नरम (या कठोर) कर सकते हैं, फिर पारस्परिक पैमाने (1 / x) को ज्यामितीय रूप से स्वयं (कैनवास का उपयोग न करके) लागू करें।
तुलना करें (कोई स्केलिंग नहीं):
(कैनवास स्केल: 0.75; मैनुअल स्केल: 1.33):
और (कैनवास स्केल: 1.33; मैनुअल स्केल: 0.75):
टिप # 2 : अगर एक जगमगाता हुआ लुक वास्तव में आपके बाद का है, तो हर शेप को कुछ समय (बिना मिटाए) खींचने की कोशिश करें। प्रत्येक ड्रॉ के साथ, एंटीएलियासिंग पिक्सल्स गहरे रंग के हो जाते हैं।
की तुलना करें। एक बार ड्राइंग के बाद:
तीन बार ड्राइंग के बाद:
मैं एक कस्टम लाइन एल्गोरिथ्म का उपयोग करके सब कुछ आकर्षित करूंगा जैसे कि ब्रेसेनहम का लाइन एल्गोरिदम। इस जावास्क्रिप्ट कार्यान्वयन की जाँच करें: http://members.chello.at/easyfilter/canvas.html
मुझे लगता है कि यह निश्चित रूप से आपकी समस्याओं को हल करेगा।
setPixel(x, y)
; मैंने यहां स्वीकृत उत्तर का उपयोग किया: stackoverflow.com/questions/4899799/…
मैं जोड़ना चाहता हूं कि एक छवि को डाउन करते समय और कैनवास पर ड्राइंग करते समय मुझे परेशानी हुई थी, यह तब भी स्मूथिंग का उपयोग कर रहा था, भले ही यह अपस्कलिंग करते समय उपयोग नहीं कर रहा था।
मैंने इसका उपयोग करके हल किया:
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'))
हो सकता है कि यह किसी के लिए उपयोगी हो।
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5;
इस कॉम्बो के साथ मैं अच्छी 1px पतली रेखाएँ खींच सकता हूँ।
एक बहुत ही सीमित ट्रिक नोटिस करें। यदि आप 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 चैनल ग्रे है। मैंने अभी 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
StashOfCode के जवाब पर सिर्फ दो नोट:
इसके बजाय ऐसा करना बेहतर है:
स्ट्रोक करें और भरें #FFFFFF
, फिर ऐसा करें:
imageData.data[i] = (imageData.data[i] >> 7) * 0xFF
जो इसे 1px चौड़ाई वाली लाइनों के लिए हल करता है।
इसके अलावा, StashOfCode का समाधान एकदम सही है क्योंकि इसमें आपको अपने स्वयं के रेखांकन कार्यों को लिखने की आवश्यकता नहीं है (न केवल लाइनें, बल्कि बेज़ियर, परिपत्र आर्क्स, छिद्रों के साथ बहुभुज, आदि ...)
यहां जावास्क्रिप्ट में ब्रेसेनहैम के एल्गोरिथ्म का एक बुनियादी कार्यान्वयन है। यह इस विकिपीडिया लेख में वर्णित पूर्णांक-अंकगणितीय संस्करण पर आधारित है: 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;
}