ปิดใช้งานการแก้ไขเมื่อปรับขนาด <canvas>


126

หมายเหตุ : นี้จะทำอย่างไรกับวิธีการที่องค์ประกอบผ้าใบที่มีอยู่จะแสดงผลเมื่อปรับขนาดขึ้น ,ไม่ได้จะทำอย่างไรกับสายหรือกราฟิกจะแสดงผลบนพื้นผิวผ้าใบ ในคำอื่น ๆ นี้มีทุกสิ่งที่จะทำอย่างไรกับการแก้ไขขององค์ประกอบที่ปรับขนาดได้และไม่มีอะไรจะทำอย่างไรกับการลดรอยหยักของกราฟิกถูกวาดบนผืนผ้าใบ ฉันไม่ได้กังวลว่าเบราว์เซอร์จะลากเส้นอย่างไร ฉันดูแลเกี่ยวกับวิธีการเบราว์เซอร์วาทกรรมองค์ประกอบผ้าใบตัวเองเมื่อมีการปรับขนาดขึ้น


มีคุณสมบัติผ้าใบหรือการตั้งค่าเบราว์เซอร์ที่ฉันสามารถเปลี่ยนโดยทางโปรแกรมเพื่อปิดใช้งานการแก้ไขเมื่อปรับขนาด<canvas>องค์ประกอบได้หรือไม่ โซลูชันข้ามเบราว์เซอร์เหมาะอย่างยิ่ง แต่ไม่จำเป็น เบราว์เซอร์ที่ใช้ Webkit เป็นเป้าหมายหลักของฉัน ประสิทธิภาพเป็นสิ่งสำคัญมาก

คำถามนี้คล้ายกันมากที่สุด แต่ไม่ได้อธิบายถึงปัญหาอย่างเพียงพอ สำหรับสิ่งที่คุ้มค่าฉันพยายามimage-rendering: -webkit-optimize-contrastแล้ว

แอปพลิเคชันนี้จะเป็นเกม 8 บิตสไตล์ "ย้อนยุค" ที่เขียนด้วย HTML5 + JS เพื่อให้ชัดเจนว่าฉันต้องการอะไร


เพื่อเป็นตัวอย่างนี่คือตัวอย่าง ( เวอร์ชันสด )

สมมติว่าฉันมีผ้าใบขนาด 21x21 ...

<canvas id='b' width='21' height='21'></canvas>

... ซึ่งมี css ที่ทำให้องค์ประกอบใหญ่ขึ้น 5 เท่า (105x105):

canvas { border: 5px solid #ddd; }
canvas#b { width: 105px; height: 105px; } /* 5 * 21 = 105 */

ฉันวาด 'X' ง่ายๆบนผืนผ้าใบดังนี้:

$('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

ภาพด้านซ้ายคือสิ่งที่ Chromium (14.0) แสดงผล ภาพด้านขวาคือสิ่งที่ฉันต้องการ (วาดด้วยมือเพื่อวัตถุประสงค์ในการอธิบาย)

Chrome สอดแทรกองค์ประกอบแคนวาสที่ปรับขนาด เวอร์ชันที่ไม่มีการแก้ไข


1
เกี่ยวข้องกันบ้าง แต่ไม่เหมือนกัน: stackoverflow.com/questions/195262/…
HostileFork บอกว่าอย่าไว้วางใจ SE

1
ฉันเชื่อว่าคำถามนั้นอ้างถึงฟังก์ชันการวาดเส้นที่วาดเส้นต่อต้านนามแฝง ฉันกำลังอ้างถึงวิธีการแสดงผลองค์ประกอบผ้าใบที่ปรับขนาดด้วยการแก้ไขโดยค่าเริ่มต้น
namuol

ใช่ขอโทษ ... ก่อนอื่นฉันคิดว่าคำถามเดียวกันจากนั้นก็สังเกตเห็นความผิดพลาดของฉันทันที : - / จะเกิดอะไรขึ้นถ้าคุณจะลองใช้ตัวกรองพิกเซลของ jsmanipulate? joelb.me/jsmanipulate
HostileFork บอกว่าอย่าไว้วางใจ SE

1
นั่นคือฟิลเตอร์ภาพที่มีไว้สำหรับภาพถ่ายมากกว่า
namuol

ใช่ แต่ถ้ามันเปลี่ยนภาพด้านซ้ายของคุณให้เป็นภาพที่ดีพอที่จะทำให้คุณมีความสุขมันก็สามารถให้โซลูชันข้ามเบราว์เซอร์ได้ (เนื่องจากมันไม่ได้ดูมีแนวโน้มเกินไปที่จะหาแฟล็กสำหรับโหมดการวาดภาพนี้สากลหรืออย่างอื่น , ใน WebKit) การทดแทนที่ใช้งานได้นั้นขึ้นอยู่กับปัญหาที่คุณกำลังพยายามแก้ไข ... หากคุณต้องการการวาดพิกเซลแบบไม่ต่อเนื่องจริง ๆ หรือหากคุณเพียงแค่พยายามตรวจสอบให้แน่ใจว่าผลลัพธ์เป็นพิกเซลที่มีความละเอียดบางอย่าง
HostileFork บอกว่าอย่าไว้วางใจใน

คำตอบ:


126

ปรับปรุงล่าสุด: 2014-09-12

มีคุณสมบัติผ้าใบหรือการตั้งค่าเบราว์เซอร์ที่ฉันสามารถเปลี่ยนโดยทางโปรแกรมเพื่อปิดใช้งานการแก้ไขเมื่อปรับขนาดองค์ประกอบได้หรือไม่

คำตอบคือบางทีบางวัน ในตอนนี้คุณจะต้องหันไปใช้แฮ็คเพื่อให้ได้สิ่งที่คุณต้องการ


image-rendering

ร่างการทำงานของ CSS3 สรุปคุณสมบัติใหม่image-renderingที่ควรทำในสิ่งที่ฉันต้องการ:

คุณสมบัติการเรนเดอร์ภาพให้คำแนะนำแก่ตัวแทนผู้ใช้เกี่ยวกับลักษณะของภาพที่สำคัญที่สุดในการรักษาเมื่อภาพถูกปรับขนาดเพื่อช่วย User-agent ในการเลือกอัลกอริทึมการปรับขนาดที่เหมาะสม

ข้อกำหนดแสดงค่าที่สามได้รับการยอมรับ: auto, และcrisp-edgespixelated

pixelated:

เมื่อขยายภาพขึ้นต้องใช้ "เพื่อนบ้านที่ใกล้ที่สุด" หรืออัลกอริทึมที่คล้ายกันเพื่อให้ภาพดูเหมือนประกอบด้วยพิกเซลขนาดใหญ่มาก เมื่อย่อขนาดลงจะเหมือนกับอัตโนมัติ

มาตรฐาน? เบราว์เซอร์?

เนื่องจากนี่เป็นเพียงร่างที่ใช้งานได้จึงไม่มีการรับประกันว่าสิ่งนี้จะกลายเป็นมาตรฐาน ขณะนี้การสนับสนุนเบราว์เซอร์ไม่แน่นอนและดีที่สุด

Mozilla Developer Network มีหน้าเว็บที่ละเอียดถี่ถ้วนซึ่งอุทิศให้กับสถานะปัจจุบันซึ่งฉันขอแนะนำให้อ่าน

ในตอนแรกนักพัฒนา Webkit เลือกที่จะใช้สิ่งนี้อย่างไม่แน่นอน-webkit-optimize-contrastแต่ดูเหมือนว่า Chromium / Chrome จะไม่ใช้ Webkit เวอร์ชันที่ดำเนินการนี้

ปรับปรุง: 2014-09-12

Chrome 38 รองรับแล้วimage-rendering: pixelated !

Firefox มีรายงานข้อบกพร่องที่เปิดให้image-rendering: pixelatedใช้งานได้แต่-moz-crisp-edgesตอนนี้ใช้งานได้

สารละลาย?

วิธีแก้ปัญหาข้ามแพลตฟอร์มที่มีเฉพาะ CSS เท่านั้น:

canvas {
  image-rendering: optimizeSpeed;             /* Older versions of FF          */
  image-rendering: -moz-crisp-edges;          /* FF 6.0+                       */
  image-rendering: -webkit-optimize-contrast; /* Safari                        */
  image-rendering: -o-crisp-edges;            /* OS X & Windows Opera (12.02+) */
  image-rendering: pixelated;                 /* Awesome future-browsers       */
  -ms-interpolation-mode: nearest-neighbor;   /* IE                            */
}

น่าเสียดายที่สิ่งนี้ยังใช้ไม่ได้กับแพลตฟอร์ม HTML5 หลัก ๆ ทั้งหมด (โดยเฉพาะ Chrome)

แน่นอนว่าเราสามารถปรับขนาดภาพด้วยตนเองโดยใช้การแก้ไขเพื่อนบ้านที่ใกล้ที่สุดบนพื้นผิวผ้าใบที่มีความละเอียดสูงในจาวาสคริปต์หรือแม้กระทั่งภาพขนาดล่วงหน้าฝั่งเซิร์ฟเวอร์ แต่ในกรณีของฉันสิ่งนี้จะต้องห้ามในราคาแพงดังนั้นจึงไม่ใช่ตัวเลือกที่ทำงานได้

ImpactJSใช้เทคนิคการปรับขนาดพื้นผิวล่วงหน้าเพื่อหลีกเลี่ยง FUD ทั้งหมดนี้ Dominic Szablewski นักพัฒนาของ Impact ได้เขียนบทความเชิงลึกเกี่ยวกับเรื่องนี้ (เขายังลงเอยด้วยการอ้างถึงคำถามนี้ในงานวิจัยของเขา)

ดูคำตอบของ Simonสำหรับโซลูชันแบบผ้าใบที่อาศัยimageSmoothingEnabledคุณสมบัติ (ไม่มีในเบราว์เซอร์รุ่นเก่า แต่ง่ายกว่าการปรับขนาดล่วงหน้าและรองรับค่อนข้างมาก)

การสาธิตสด

หากคุณต้องการทดสอบคุณสมบัติ CSS ที่กล่าวถึงในบทความ MDN เกี่ยวกับcanvasองค์ประกอบฉันได้ทำซอนี้ขึ้นมาซึ่งควรแสดงสิ่งนี้ไม่ชัดหรือไม่ขึ้นอยู่กับเบราว์เซอร์ของคุณ: ภาพ 4: 1 (64x64 ถึง 256x256) ของทีวีสไตล์ศิลปะพิกเซลสามมิติ


การเรนเดอร์รูปภาพดูเหมือนจะทำงานที่อื่น แต่เบราว์เซอร์ webkit ฉันหวังเป็นอย่างยิ่งว่าเจ้าหน้าที่ Chrome / Chromium / Safari จะอ่านความหมายของ "เปลี่ยนไปใช้การแก้ไข EPX ในสถานการณ์ที่มีโหลดน้อย" เมื่อฉันอ่านประโยคครั้งแรกฉันคิดว่าการปรับความคมชัดให้เหมาะสมช่วยให้เกิดสีใหม่ที่สร้างขึ้นในโหลดต่ำ แต่ไม่: en.wikipedia.org/wiki/…
Timo Kähkönen

2
Opera 12.02 บน Mac และ Windows รองรับการแสดงภาพ: -o-crisp-edge ( jsfiddle.net/VAXrL/21 ) ดังนั้นคุณสามารถเพิ่มลงในคำตอบของคุณได้
Timo Kähkönen

ควรจะใช้งานได้หรือไม่เมื่อฉันเพิ่มการซูมเบราว์เซอร์ ฉันได้ทดสอบการวาดด้วย FF 22, Chrome 27 และ IE 10 บน Windows 7 เมื่อเบราว์เซอร์ซูม 150% และผลที่ได้คือเบลอในทุกเบราว์เซอร์ เมื่อฉันเพิ่มความกว้างและความสูงของผ้าใบเป็นสองเท่าและตั้งค่ากลับเป็นความกว้างและความสูงเดิมด้วย CSS มันจะวาดเส้นที่คมชัด
pablo

นั่นเป็นคำถามที่ดี ฉันไม่แน่ใจว่ามีข้อกำหนดสำหรับพฤติกรรมการปรับขนาดที่ผู้ใช้ระบุหรือไม่
namuol

1
ฉัน (จากอนาคตปัจจุบัน!) บน Chrome 78 ฉันเห็น "การแสดงภาพ: pixelated;" การทำงาน ดูเหมือนว่าสิ่งนี้จะถูกเพิ่มใน Chrome 41 ในปี 2015: developers.google.com/web/updates/2015/01/pixelated
MrColes

61

คำตอบใหม่ 31/7/2012

ในที่สุดนี่ก็เป็นข้อมูลจำเพาะของผ้าใบ!

ข้อมูลจำเพาะเพิ่งเพิ่มคุณสมบัติที่เรียกว่าimageSmoothingEnabledซึ่งเป็นค่าเริ่มต้นtrueและกำหนดว่ารูปภาพที่วาดโดยใช้พิกัดที่ไม่ใช่จำนวนเต็มหรือการกำหนดมาตราส่วนจะใช้อัลกอริทึมที่ราบรื่นขึ้น หากตั้งค่าเป็นfalseเพื่อนบ้านที่ใกล้ที่สุดจะทำให้ได้ภาพที่เรียบน้อยลงและแทนที่จะสร้างพิกเซลที่ดูใหญ่ขึ้น

เมื่อเร็ว ๆ นี้มีการเพิ่มการปรับภาพให้เรียบลงในข้อกำหนดผ้าใบและไม่ได้รับการสนับสนุนในเบราว์เซอร์ทั้งหมด แต่บางเบราว์เซอร์ได้ใช้คุณสมบัตินี้ในเวอร์ชันที่นำเสนอโดยผู้ขาย ตามบริบทนั้นมีอยู่mozImageSmoothingEnabledใน Firefox และwebkitImageSmoothingEnabledใน Chrome และ Safari และการตั้งค่าเป็นเท็จจะหยุดการต่อต้านนามแฝงไม่ให้เกิดขึ้น น่าเสียดายที่ในขณะที่เขียน IE9 และ Opera ยังไม่ได้ใช้คุณสมบัตินี้คำนำหน้าผู้ขายหรืออย่างอื่น


ดูตัวอย่าง: JSFiddle

ผลลัพธ์:

ใส่คำอธิบายภาพที่นี่


1
น่าเสียดายที่ดูเหมือนว่าจะยังใช้ไม่ได้เช่นกัน บางทีฉันอาจจะขาดอะไรไป? นี่คือการทดสอบ: jsfiddle.net/VAXrL/187
namuol

12
คุณต้องปรับขนาดโดยใช้ canvas API เพื่อให้ใช้งานได้คุณไม่สามารถปรับขนาดด้วย CSS ได้เลยและส่งผลต่อ canvas API! อย่างนี้: jsfiddle.net/VAXrL/190
Simon Sarris

1
แต่ลักษณะของปัญหานี้ไม่ได้เกี่ยวกับผ้าใบจริงๆ มันเกี่ยวกับวิธีที่เบราว์เซอร์แสดงภาพขนาดรวมถึงองค์ประกอบ <canvas>
namuol

4
หากคุณปรับขนาดโดยใช้ CSS โซลูชันของ namuol จะใช้งานได้ หากคุณปรับขนาดภาพลงใน Canvas ด้วยตนเองโซลูชันของ Simon ก็ใช้ได้ เป็นที่เรียบร้อยว่ามีวิธีแก้ไขสำหรับทั้งสองกรณีดังนั้นขอขอบคุณทั้งสองท่าน!
Shaun Lebron

สำหรับ IE 11: msImageSmoothingEnabled ใช้ได้กับฉัน! msdn.microsoft.com/en-us/library/dn265062(v=vs.85).aspx
สตีฟ

11

แก้ไข 31 ก.ค. 2555 - ขณะนี้ฟังก์ชันนี้อยู่ในข้อกำหนดผ้าใบแล้ว! ดูคำตอบแยกต่างหากที่นี่:

https://stackoverflow.com/a/11751817/154112

คำตอบเก่าอยู่ด้านล่างสำหรับลูกหลาน


ขึ้นอยู่กับเอฟเฟกต์ที่คุณต้องการคุณมีสิ่งนี้เป็นตัวเลือกหนึ่ง:

var can = document.getElementById('b');
var ctx = can.getContext('2d');
ctx.scale(5,5);
$('canvas').each(function () {
    var ctx = this.getContext("2d");
    ctx.moveTo(0,0);
    ctx.lineTo(21,21);
    ctx.moveTo(0,21);
    ctx.lineTo(21,0);
    ctx.stroke();
});

http://jsfiddle.net/wa95p/

ซึ่งสร้างสิ่งนี้:

ใส่คำอธิบายภาพที่นี่

อาจไม่ใช่สิ่งที่คุณต้องการ แต่ถ้าคุณแค่มองว่าไม่มีภาพเบลอนั่นคงเป็นตั๋วดังนั้นฉันจะเสนอให้

ตัวเลือกที่ยากกว่าคือใช้การจัดการพิกเซลและเขียนอัลกอริทึมด้วยตัวคุณเองสำหรับงาน แต่ละพิกเซลของภาพแรกจะกลายเป็นพิกเซลขนาด 5x5 บล็อกในภาพใหม่ มันคงไม่ยากเกินไปที่จะทำกับ imagedata

แต่ Canvas และ CSS เพียงอย่างเดียวไม่สามารถช่วยคุณได้ที่นี่ในการปรับขนาดให้ได้ผลตามที่คุณต้องการ


ใช่นั่นคือสิ่งที่ฉันกลัว เห็นได้ชัดว่าimage-rendering: -webkit-optimize-contrastควรทำเคล็ดลับ แต่ดูเหมือนจะไม่ทำอะไรเลย ฉันอาจลองใช้ฟังก์ชันเพื่อขยายขนาดเนื้อหาของผ้าใบโดยใช้การแก้ไขเพื่อนบ้านที่ใกล้ที่สุด
namuol

เดิมฉันยอมรับคำตอบของคุณ ตอนนี้ฉันเพิกถอนเพราะดูเหมือนจะมีความสับสนว่ารายการนี้ซ้ำหรือไม่
namuol

ฉันมีคำตอบที่สมบูรณ์มากขึ้นหลังจากทำการค้นคว้าและต้องการเปิดคำถามอีกครั้งเพื่อให้คำตอบของฉัน
namuol

3

ใน Google Chrome รูปแบบภาพแคนวาสจะไม่ถูกสอดแทรก

นี่คือตัวอย่างการทำงานที่แก้ไขจากคำตอบของ namuol http://jsfiddle.net/pGs4f/

ctx.scale(4, 4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fillRect(0, 0, 64, 64);

นี่เป็นวิธีแก้ปัญหาที่น่าสนใจที่สุดที่ฉันเคยเห็นมา ยังไม่แน่ใจเกี่ยวกับประสิทธิภาพ แต่ก็คุ้มค่าที่จะพิจารณา ฉันจะลองดู
namuol

การใช้การทำซ้ำแทนการไม่ทำซ้ำนั้นเร็วกว่า ไม่รู้ทำไม. มันค่อนข้างเร็วสาม js ใช้สิ่งนี้ใน CanvasRenderer
saviski

6
อัปเดต: ไม่สามารถใช้งานกับ chrome 21 ได้อีกต่อไป (เนื่องจากเพิ่มการรองรับการแสดงผลเรตินา) เวอร์ชันใหม่jsfiddle.net/saviski/pGs4f/12โดยใช้ imageSmoothingEnabled ที่ Simon ชี้
saviski

เมื่อความละเอียดของ Retina เกิดขึ้นโดยทั่วไปสิ่งต่างๆจะเปลี่ยนแปลงไปอย่างมาก เมื่อ iPhone4-5 สไตล์ 326dpi (128dpcm) จอภาพ Retina มาถึงจอภาพขนาด 24 นิ้ว (52x32 ซม.) ขนาดหน้าจอจะเป็น 6656 x 4096 พิกเซล การลบรอยหยักนั้นไม่ดีและผู้จำหน่ายเบราว์เซอร์ทั้งหมด (แม้แต่ตาม Webkit) จะถูกบังคับให้ปิดใช้งานการลบรอยหยัก การลบรอยหยักเป็นการดำเนินการที่ต้องใช้ซีพียูเป็นอย่างมากและการลบรอยหยักขนาด 6656 x 4096 พิกเซลจะช้าเกินไป แต่โชคดีที่ไม่จำเป็นในการแสดงผลดังกล่าว
Timo Kähkönen

1
โปรดทราบว่านี่คือรูปแบบมาตรฐานเทียบกับภาพเปรียบเทียบที่ดี: jsperf.com/drawimage-vs-canvaspattern/9
yckart

1

วิธีแก้ปัญหาของ Saviski ที่อธิบายไว้ที่นี่มีแนวโน้มดีเพราะทำงานบน:

  • Chrome 22.0.1229.79 Mac OS X 10.6.8
  • Chrome 22.0.1229.79 ม. Windows 7
  • Chromium 18.0.1025.168 (นักพัฒนา Build 134367 Linux) Ubuntu 11.10
  • Firefox 3.6.25 Windows 7

แต่ใช้งานไม่ได้ในสิ่งต่อไปนี้ แต่สามารถทำได้ผลเช่นเดียวกันโดยใช้ CSS image-rendering:

  • Firefox 15.0.1 Mac OS X 10.6.8 (การแสดงภาพ: -moz-crisp-edge ใช้งานได้ในสิ่งนี้ )
  • Opera 12.02 Mac OS X 10.6.8 (การแสดงภาพ: -o-crisp-edge ใช้งานได้ในสิ่งนี้ )
  • Opera 12.02 Windows 7 (การแสดงภาพ: -o-crisp-edge ใช้งานได้ในสิ่งนี้ )

ปัญหาคือสิ่งเหล่านี้เนื่องจาก ctx.XXXImageSmoothingEnabled ไม่ทำงานและการเรนเดอร์ภาพไม่ทำงาน:

  • Safari 5.1.7 Mac OS X 10.6.8 (การแสดงภาพ: -webkit-optimize-contrast ไม่ทำงาน)
  • Safari 5.1.7 Windows 7 (การแสดงภาพ: -webkit-optimize-contrast ไม่ทำงาน)
  • IE 9 Windows 7 (-ms-interpolation-mode: เพื่อนบ้านที่ใกล้ที่สุดไม่ทำงาน)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.