ฉันกำลังเล่นกับ<canvas>
องค์ประกอบวาดเส้นและอื่น ๆ
ฉันสังเกตว่าเส้นทแยงมุมของฉันมีการต่อต้านการดัด ฉันชอบรูปลักษณ์ที่ดูหยาบสำหรับสิ่งที่ฉันกำลังทำ - มีวิธีใดในการปิดคุณสมบัตินี้หรือไม่?
ฉันกำลังเล่นกับ<canvas>
องค์ประกอบวาดเส้นและอื่น ๆ
ฉันสังเกตว่าเส้นทแยงมุมของฉันมีการต่อต้านการดัด ฉันชอบรูปลักษณ์ที่ดูหยาบสำหรับสิ่งที่ฉันกำลังทำ - มีวิธีใดในการปิดคุณสมบัตินี้หรือไม่?
คำตอบ:
สำหรับภาพตอนนี้ context.imageSmoothingEnabled
= false
สำหรับภาพที่มีในขณะนี้
อย่างไรก็ตามไม่มีสิ่งใดที่ควบคุมการวาดเส้นอย่างชัดเจน คุณอาจจำเป็นต้องวาดเส้นของคุณเอง ( วิธีที่ยาก ) โดยใช้และgetImageData
putImageData
putImageData
แต่มันยังคงใช้นามแฝงของพิกเซลที่อยู่ใกล้เคียง
วาดของคุณเส้นบนพิกัดเช่น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
สามารถทำได้ใน Mozilla Firefox เพิ่มสิ่งนี้ในรหัสของคุณ:
contextXYZ.mozImageSmoothingEnabled = false;
ใน Opera ปัจจุบันเป็นคำขอคุณสมบัติ แต่หวังว่าจะมีการเพิ่มเร็ว ๆ นี้
จำเป็นต้องมีการลบรอยหยักสำหรับการพล็อตกราฟิกเวกเตอร์ที่ถูกต้องซึ่งเกี่ยวข้องกับพิกัดที่ไม่ใช่จำนวนเต็ม (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 : หากรูปลักษณ์ที่ดูหยาบกร้านเป็นสิ่งที่คุณต้องการจริงๆลองวาดแต่ละรูปร่างสองสามครั้ง (โดยไม่ต้องลบ) เมื่อวาดแต่ละครั้งพิกเซลลดรอยหยักจะเข้มขึ้น
เปรียบเทียบ. หลังจากวาดครั้งเดียว:
หลังจากวาดสามครั้ง:
ฉันจะวาดทุกอย่างโดยใช้อัลกอริทึมเส้นที่กำหนดเองเช่นอัลกอริทึมเส้นของ Bresenham ตรวจสอบการใช้งานจาวาสคริปต์นี้: 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 สีคุณสามารถวาดรูปร่างใดก็ได้ที่คุณต้องการด้วยสี # 010101 บนพื้นหลังที่มีสี # 000000 เมื่อเสร็จแล้วคุณสามารถทดสอบแต่ละพิกเซลใน imageData.data [] และตั้งค่าเป็น 0xFF ว่าค่าใดที่ไม่ใช่ 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);
ผลลัพธ์จะเป็นภาพขาวดำที่ไม่ได้ลบรอยหยัก สิ่งนี้จะไม่สมบูรณ์แบบเนื่องจากการลบรอยหยักจะเกิดขึ้น แต่การลบรอยหยักนี้จะมีข้อ จำกัด มากสีของรูปทรงจะเหมือนกับสีของพื้นหลังมาก
สำหรับผู้ที่ยังคงมองหาคำตอบ นี่คือทางออกของฉัน
ภาพสมมติคือ 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 นั้นสมบูรณ์แบบเพราะไม่จำเป็นต้องเขียนฟังก์ชันแรสเตอร์ของคุณเอง (คิดว่าไม่ใช่แค่เส้น แต่เป็นเบซิเออร์, ส่วนโค้งวงกลม, รูปหลายเหลี่ยมที่เต็มไปด้วยรู ฯลฯ ... )
นี่คือการใช้อัลกอริทึมพื้นฐานของ Bresenham ใน JavaScript โดยอ้างอิงจากเวอร์ชันเลขคณิตจำนวนเต็มที่อธิบายไว้ในบทความวิกิพีเดียนี้: 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;
}
canvas { image-rendering: pixelated; }
ลองสิ่งที่ต้องการ
วิธีนี้อาจไม่ได้ผลหากคุณพยายามทำให้บรรทัดเดียวไม่ใช่การลบรอยหยัก
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>
ฉันยังไม่ได้ทดสอบสิ่งนี้กับเบราว์เซอร์จำนวนมาก