Bawię się <canvas>
elementem, rysuję linie i tym podobne.
Zauważyłem, że moje ukośne linie są wygładzone. Wolałbym postrzępiony wygląd tego, co robię - czy jest jakiś sposób na wyłączenie tej funkcji?
javascript
html
canvas
antialiasing
Blorgbeard wyszedł
źródło
źródło
Odpowiedzi:
W przypadku obrazów jest teraz .
context.imageSmoothingEnabled
= false
Jednak nie ma nic, co bezpośrednio kontroluje rysowanie linii. Być może będziesz musiał narysować własne linie ( trudna droga ) za pomocą
getImageData
iputImageData
.źródło
putImageData
ale nadal działa aliasing pobliskich pikseli.Narysuj swoje
1-pixel
linie na współrzędnych takich jakctx.lineTo(10.5, 10.5)
. Narysowanie jednopikselowej linii nad punktem(10, 10)
oznacza, że ten1
piksel w tym miejscu sięga od9.5
do,10.5
co powoduje powstanie dwóch linii, które zostaną narysowane na płótnie.Fajną sztuczką, która nie zawsze musi być dodawana
0.5
do rzeczywistej współrzędnej, którą chcesz narysować, jeśli masz dużo jednopikselowych linii, jestctx.translate(0.5, 0.5)
na początku całe płótno.źródło
ctx.translate(0.5,0.5)
nie. na FF39.0Można to zrobić w przeglądarce Mozilla Firefox. Dodaj to do swojego kodu:
contextXYZ.mozImageSmoothingEnabled = false;
W Operze jest to obecnie propozycja funkcji, ale miejmy nadzieję, że zostanie wkrótce dodana.
źródło
"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"
Musi antialias grafiki wektorowej
Antyaliasing jest wymagany do prawidłowego kreślenia grafiki wektorowej z wykorzystaniem współrzędnych innych niż całkowite (0,4, 0,4), co robi wszyscy oprócz bardzo niewielu klientów.
Gdy podane współrzędne nie są liczbami całkowitymi, płótno ma dwie opcje:
Późniejsza strategia będzie działać w przypadku grafik statycznych, chociaż w przypadku małych grafik (okrąg o promieniu 2) krzywe będą zawierały wyraźne kroki, a nie gładką krzywą.
Prawdziwym problemem jest to, gdy grafika jest tłumaczona (przenoszona) - skoki między jednym pikselem a drugim (1,6 => 2, 1,4 => 1), oznaczają, że pochodzenie kształtu może przeskakiwać w stosunku do kontenera nadrzędnego (ciągle przesuwa się 1 piksel w górę / w dół i w lewo / w prawo).
Kilka porad
Wskazówka 1 : Możesz zmiękczyć (lub utwardzić) antyaliasing, skalując płótno (powiedzmy przez x), a następnie zastosuj skalę odwrotności (1 / x) do geometrii samodzielnie (nie używając płótna).
Porównaj (bez skalowania):
z (skala płótna: 0,75; skala ręczna: 1,33):
oraz (skala płótna: 1,33; skala ręczna: 0,75):
Wskazówka 2 : Jeśli naprawdę szukasz postrzępionego wyglądu, spróbuj narysować każdy kształt kilka razy (bez wymazywania). Z każdym rysowaniem piksele antyaliasingu stają się ciemniejsze.
Porównać. Po jednorazowym narysowaniu:
Po trzykrotnym losowaniu:
źródło
Narysowałbym wszystko za pomocą niestandardowego algorytmu liniowego, takiego jak algorytm liniowy Bresenham. Sprawdź tę implementację javascript: http://members.chello.at/easyfilter/canvas.html
Myślę, że to z pewnością rozwiąże Twoje problemy.
źródło
setPixel(x, y)
; Użyłem zaakceptowanej odpowiedzi tutaj: stackoverflow.com/questions/4899799/…Chcę dodać, że miałem problem podczas zmniejszania rozmiaru obrazu i rysowania na płótnie, nadal korzystałem z wygładzania, mimo że nie było używane podczas skalowania.
Rozwiązałem za pomocą tego:
function setpixelated(context){ context['imageSmoothingEnabled'] = false; /* standard */ context['mozImageSmoothingEnabled'] = false; /* Firefox */ context['oImageSmoothingEnabled'] = false; /* Opera */ context['webkitImageSmoothingEnabled'] = false; /* Safari */ context['msImageSmoothingEnabled'] = false; /* IE */ }
Możesz użyć tej funkcji w następujący sposób:
var canvas = document.getElementById('mycanvas') setpixelated(canvas.getContext('2d'))
Może to się komuś przyda.
źródło
ctx.translate(0.5, 0.5); ctx.lineWidth = .5;
Dzięki tej kombinacji mogę narysować ładne cienkie linie 1px.
źródło
Zwróć uwagę na bardzo ograniczoną sztuczkę. Jeśli chcesz stworzyć obraz w dwóch kolorach, możesz narysować dowolny kształt kolorem # 010101 na tle w kolorze # 000000. Gdy to zrobisz, możesz przetestować każdy piksel w imageData.data [] i ustawić na 0xFF dowolną wartość inną niż 0x00:
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);
Rezultatem będzie czarno-biały obraz bez antyaliasingu. Nie będzie to idealne, ponieważ będzie miał miejsce jakiś antyaliasing, ale ten antyaliasing będzie bardzo ograniczony, a kolor kształtu będzie bardzo podobny do koloru tła.
źródło
Dla tych, którzy wciąż szukają odpowiedzi. oto moje rozwiązanie.
Zakładając, że obraz jest 1-kanałowy szary. Właśnie przekroczyłem próg po 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; } } }
jeśli twój kanał obrazu to 3 lub 4. musisz zmodyfikować indeks tablicy, np
źródło
Tylko dwie uwagi na temat odpowiedzi StashOfCode:
Zamiast tego lepiej to zrobić:
Obrysuj i wypełnij
#FFFFFF
, a następnie zrób to:imageData.data[i] = (imageData.data[i] >> 7) * 0xFF
To rozwiązuje problem dla linii o szerokości 1 piksela.
Poza tym rozwiązanie StashOfCode jest idealne, ponieważ nie wymaga pisania własnych funkcji rasteryzacji (pomyśl nie tylko o liniach, ale także bezierach, łukach kołowych, wypełnionych wielokątach z dziurami itp.)
źródło
Oto podstawowa implementacja algorytmu Bresenham w JavaScript. Opiera się na wersji integer-arytmetycznej opisanej w tym artykule na Wikipedii: 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; }
źródło