<canvas>
Öğe, çizgi çizme ve benzeri şeylerle oynuyorum .
Çapraz çizgilerimin yumuşatıldığını fark ettim. Yaptığım şey için pürüzlü görünümü tercih ederim - bu özelliği kapatmanın bir yolu var mı?
<canvas>
Öğe, çizgi çizme ve benzeri şeylerle oynuyorum .
Çapraz çizgilerimin yumuşatıldığını fark ettim. Yaptığım şey için pürüzlü görünümü tercih ederim - bu özelliği kapatmanın bir yolu var mı?
Yanıtlar:
Görüntüler için şimdi var .context.imageSmoothingEnabled
= false
Ancak, çizgi çizmeyi açıkça kontrol eden hiçbir şey yoktur. Ve kullanarak kendi çizgilerinizi ( zor yoldan ) çizmeniz gerekebilir .getImageData
putImageData
putImageData
ama yine de yakındaki piksellerin örtüşmesini yapıyor lanet
1-pixel
Çizgilerinizi koordinatlara çizin ctx.lineTo(10.5, 10.5)
. Noktası üzerinde bir piksel çizgisinin (10, 10)
, bu demektir ki, 1
o pozisyon ulaşır piksel 9.5
için 10.5
olan tuval üzerinde de çizilebilir iki hat ile sonuçlanır.
0.5
Çok sayıda tek piksel çizginiz varsa, çizmek istediğiniz gerçek koordinata her zaman eklemeniz gerekmeyen güzel bir numara ctx.translate(0.5, 0.5)
, başlangıçta tüm tuvalinize.
ctx.translate(0.5,0.5)
yaradı ama yaramadı. FF39.0
Mozilla Firefox'ta yapılabilir. Bunu kodunuza ekleyin:
contextXYZ.mozImageSmoothingEnabled = false;
Opera'da şu anda bir özellik isteği, ancak umarım yakında eklenecektir.
Tamsayı olmayan koordinatları (0.4, 0.4) içeren vektör grafiklerinin doğru şekilde çizilmesi için, çok az sayıda istemcinin yaptığı gibi kenar yumuşatma gereklidir .
Tamsayı olmayan koordinatlar verildiğinde, tuvalin iki seçeneği vardır:
Daha sonraki strateji statik grafikler için işe yarayacaktır, ancak küçük grafikler için (2 yarıçaplı bir daire) eğriler düzgün bir eğri yerine net adımlar gösterecektir.
Asıl sorun, grafikler çevrildiğinde (taşındığında) - bir piksel ile diğeri arasındaki atlamalar (1.6 => 2, 1.4 => 1), şeklin başlangıç noktasının üst kapsayıcıya göre atlayabileceği anlamına gelir (sürekli değişen 1 piksel yukarı / aşağı ve sol / sağ).
İpucu 1 : Tuvali ölçeklendirerek (örneğin x ile) kenar yumuşatmayı yumuşatabilir (veya sertleştirebilirsiniz) ve ardından karşılıklı ölçeği (1 / x) geometrilere kendiniz uygulayabilirsiniz (tuvali kullanmadan).
Karşılaştır (ölçeklendirme yok):
(tuval ölçeği: 0.75; manuel ölçek: 1.33):
ve (tuval ölçeği: 1.33; manuel ölçek: 0.75):
İpucu # 2 : Bir jaggy göz ne sonra konum gerçekten ise (silmeden) her şeklin bir kaç kez çıkartmayı dene. Her çizimde, kenar yumuşatma pikselleri koyulaşır.
Karşılaştırmak. Bir kez çizdikten sonra:
Üç kez çizdikten sonra:
Her şeyi Bresenham'ın çizgi algoritması gibi özel bir çizgi algoritması kullanarak çizerdim. Bu javascript uygulamasına göz atın: http://members.chello.at/easyfilter/canvas.html
Bunun kesinlikle sorunlarınızı çözeceğini düşünüyorum.
setPixel(x, y)
; Kabul edilen yanıtı burada kullandım: stackoverflow.com/questions/4899799/…
Bir görüntünün boyutunu küçültürken ve tuval üzerine çizim yaparken sorun yaşadığımı eklemek istiyorum, ölçek büyütme sırasında kullanılmamasına rağmen hala düzgünleştirmeyi kullanıyordu.
Bunu kullanarak çözdüm:
function setpixelated(context){
context['imageSmoothingEnabled'] = false; /* standard */
context['mozImageSmoothingEnabled'] = false; /* Firefox */
context['oImageSmoothingEnabled'] = false; /* Opera */
context['webkitImageSmoothingEnabled'] = false; /* Safari */
context['msImageSmoothingEnabled'] = false; /* IE */
}
Bu işlevi şu şekilde kullanabilirsiniz:
var canvas = document.getElementById('mycanvas')
setpixelated(canvas.getContext('2d'))
Belki bu birisi için yararlıdır.
ctx.translate(0.5, 0.5);
ctx.lineWidth = .5;
Bu combo ile güzel 1px ince çizgiler çizebilirim.
Çok sınırlı bir numaraya dikkat edin. 2 renkli bir resim oluşturmak istiyorsanız, # 000000 rengi olan bir arka plan üzerine # 010101 rengiyle istediğiniz şekli çizebilirsiniz. Bu yapıldıktan sonra, imageData.data [] içindeki her pikseli test edebilir ve 0x00 değilse 0xFF olarak ayarlayabilirsiniz:
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);
Sonuç, kenar yumuşatılmamış siyah beyaz bir resim olacaktır. Bu mükemmel olmayacak, çünkü bazı kenar yumuşatma gerçekleşecek, ancak bu kenar yumuşatma çok sınırlı olacak, şeklin rengi arka plan rengine çok benziyor.
Hala cevap arayanlar için. İşte benim çözümüm.
Görüntünün 1 kanal gri olduğu varsayılır. Ctx.stroke () 'dan sonra eşik belirledim.
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;
}
}
}
görüntü kanalınız 3 veya 4 ise dizi indeksini aşağıdaki gibi değiştirmeniz gerekir
x*image.height*number_channel + y*number_channel + channel
StashOfCode'un cevabına sadece iki not:
Bunun yerine bunu yapmak daha iyidir:
Vurun ve doldurun #FFFFFF
, sonra şunu yapın:
imageData.data[i] = (imageData.data[i] >> 7) * 0xFF
Bu, 1px genişliğindeki çizgiler için çözer.
Bunun dışında StashOfCode'un çözümü mükemmeldir çünkü kendi rasterleştirme işlevlerinizi yazmanıza gerek yoktur (sadece çizgileri değil beziers, dairesel yaylar, delikli dolu çokgenler vb.)
İşte Bresenham algoritmasının JavaScript'te temel bir uygulaması. Bu wikipedia makalesinde açıklanan tamsayı-aritmetik versiyona dayanmaktadır: 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;
}
Gibi bir şey dene canvas { image-rendering: pixelated; }
.
Yalnızca bir satırı kenar yumuşatmasız yapmaya çalışıyorsanız, bu işe yaramayabilir.
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillRect(4, 4, 2, 2);
canvas {
image-rendering: pixelated;
width: 100px;
height: 100px; /* Scale 10x */
}
<html>
<head></head>
<body>
<canvas width="10" height="10">Canvas unsupported</canvas>
</body>
</html>
Yine de bunu birçok tarayıcıda test etmedim.