Vô hiệu hóa Nội suy khi Thu nhỏ <canvas>


125

GHI CHÚ : Điều này có liên quan đến cách các phần tử canvas hiện có được hiển thị khi được tăng tỷ lệ , không liên quan đến cách hiển thị các đường hoặc đồ họa trên bề mặt vải . Nói cách khác, điều này có mọi thứ để làm với phép nội suy các phần tử tỷ lệ và không liên quan gì đến việc khử răng cưa của đồ họa được vẽ trên một khung vẽ. Tôi không quan tâm đến cách trình duyệt vẽ các dòng; Tôi quan tâm đến cách trình duyệt hiển thị chính phần tử canvaskhi nó được thu nhỏ.


Có thuộc tính canvas hoặc cài đặt trình duyệt nào tôi có thể thay đổi theo chương trình để tắt nội suy khi chia tỷ lệ <canvas>không? Một giải pháp đa trình duyệt là lý tưởng nhưng không cần thiết; Các trình duyệt dựa trên Webkit là mục tiêu chính của tôi. Hiệu suất là rất quan trọng.

Câu hỏi này là tương tự nhất nhưng không minh họa vấn đề đầy đủ. Đối với những gì nó có giá trị, tôi đã cố gắng image-rendering: -webkit-optimize-contrastvô ích.

Ứng dụng này sẽ là một trò chơi 8 bit theo phong cách "retro" được viết bằng HTML5 + JS để làm cho nó rõ ràng những gì tôi cần.


Để minh họa, đây là một ví dụ. ( phiên bản trực tiếp )

Giả sử tôi có một bức tranh 21x21 ...

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

... có css làm cho phần tử lớn hơn gấp 5 lần (105x105):

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

Tôi vẽ một chữ 'X' đơn giản trên khung vẽ như vậy:

$('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();
});

Hình ảnh bên trái là những gì Chromium (14.0) hiển thị. Hình ảnh bên phải là những gì tôi muốn (vẽ tay cho mục đích minh họa).

Chrome nội suy các phần tử canvas được chia tỷ lệ Một phiên bản không nội suy


1
Một số thứ liên quan, mặc dù không giống nhau: stackoverflow.com/questions/195262/ trên
HostileFork nói không tin tưởng SE

1
Tôi tin rằng câu hỏi đó đề cập đến các chức năng vẽ đường vẽ các đường chống răng cưa. Tôi đang đề cập đến cách các phần tử canvas được thay đổi kích thước được hiển thị với phép nội suy theo mặc định.
namuol

Vâng, xin lỗi ... Đầu tiên tôi nghĩ các câu hỏi giống nhau sau đó ngay lập tức nhận thấy sai lầm của mình. : - / Điều gì sẽ xảy ra nếu bạn thử sử dụng bộ lọc pixel của jsmanipulation? joelb.me/jsmanipulation
HostileFork nói không tin tưởng SE

1
Đó là nhiều hơn một bộ lọc hình ảnh có nghĩa là cho các bức ảnh.
namuol

Có, nhưng nếu nó biến đổi hình ảnh bên trái của bạn thành một phiên bản đủ tốt của hình ảnh bên phải của bạn để làm bạn hài lòng thì nó có thể cung cấp một giải pháp trình duyệt chéo (xem xét nó không quá hứa hẹn để tìm một lá cờ cho chế độ vẽ này, phổ quát hay nói cách khác , trong WebKit). Cho dù đó là một sự thay thế khả thi tùy thuộc vào vấn đề bạn đang cố gắng giải quyết ... nếu bạn thực sự cần bản vẽ pixel rời rạc hoặc nếu bạn chỉ cố gắng đảm bảo kết quả được pixel hóa với độ chi tiết nhất định.
HostileFork nói không tin tưởng SE

Câu trả lời:


125

Cập nhật lần cuối: 2014-09-12

Có thuộc tính canvas hoặc cài đặt trình duyệt nào tôi có thể thay đổi theo chương trình để tắt nội suy khi chia tỷ lệ không?

Câu trả lời có thểmột ngày nào đó . Hiện tại, bạn sẽ phải dùng đến các bản hack để có được thứ bạn muốn.


image-rendering

Bản thảo hoạt động của CSS3 phác thảo một thuộc tính mới,image-rendering sẽ làm những gì tôi muốn:

Thuộc tính kết xuất hình ảnh cung cấp một gợi ý cho tác nhân người dùng về các khía cạnh của hình ảnh là quan trọng nhất để bảo tồn khi hình ảnh được thu nhỏ, để hỗ trợ tác nhân người dùng lựa chọn thuật toán chia tỷ lệ phù hợp.

Các đặc điểm kỹ thuật vạch ra ba giá trị được chấp nhận: auto, crisp-edges, và pixelated.

pixelated:

Khi nhân rộng hình ảnh lên, phải sử dụng "hàng xóm gần nhất" hoặc thuật toán tương tự, để hình ảnh có vẻ đơn giản chỉ gồm các pixel rất lớn. Khi thu nhỏ lại, điều này giống như tự động.

Tiêu chuẩn? Qua trình duyệt?

Vì đây chỉ là một dự thảo làm việc , không có gì đảm bảo rằng điều này sẽ trở thành tiêu chuẩn. Hỗ trợ trình duyệt hiện đang được chú ý, tốt nhất.

Mạng lưới nhà phát triển Mozilla có một trang khá kỹ lưỡng dành riêng cho tình trạng hiện tại mà tôi khuyên bạn nên đọc.

Các nhà phát triển Webkit ban đầu đã chọn triển khai thực hiện điều này như-webkit-optimize-contrast , nhưng Chromium / Chrome dường như không sử dụng phiên bản Webkit thực hiện việc này.

Cập nhật: 2014-09-12

Chrome 38 hiện hỗ trợimage-rendering: pixelated !

Firefox có một báo cáo lỗi mở để được image-rendering: pixelatedtriển khai, nhưng -moz-crisp-edgeshiện tại vẫn hoạt động.

Giải pháp?

Do đó, giải pháp đa nền tảng, chỉ dành cho CSS là:

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                            */
}

Đáng buồn là điều này chưa hoạt động trên tất cả các nền tảng HTML5 chính (cụ thể là Chrome).

Tất nhiên, người ta có thể tự điều chỉnh tỷ lệ hình ảnh bằng cách sử dụng phép nội suy lân cận gần nhất trên các bề mặt canvas có độ phân giải cao trong javascript hoặc thậm chí ở phía máy chủ hình ảnh tỷ lệ trước, nhưng trong trường hợp của tôi, điều này sẽ gây tốn kém vì vậy nó không phải là một lựa chọn khả thi.

ImpactJS sử dụng một kỹ thuật mở rộng kết cấu để có được xung quanh tất cả FUD này. Nhà phát triển của Impact, Dominic Szablewski, đã viết một bài viết rất chuyên sâu về vấn đề này (thậm chí cuối cùng ông đã trích dẫn câu hỏi này trong nghiên cứu của mình).

Xem câu trả lời của Simon cho một giải pháp dựa trên canvas dựa trên thuộc imageSmoothingEnabledtính (không có sẵn trong các trình duyệt cũ hơn, nhưng đơn giản hơn so với tỷ lệ trước và được hỗ trợ khá rộng rãi).

Bản thử trực tiếp

Nếu bạn muốn kiểm tra các thuộc tính CSS được thảo luận trong bài viết MDN về canvascác yếu tố, tôi đã tạo ra câu đố này sẽ hiển thị một cái gì đó như thế này, mờ hay không, tùy thuộc vào trình duyệt của bạn: hình ảnh 4: 1 (64x64 đến 256x256) của TV kiểu nghệ thuật pixel isometric


Kết xuất hình ảnh dường như hoạt động ở nơi khác, nhưng trình duyệt webkit. Tôi thực sự hy vọng rằng nhân viên Chrome / Chromium / Safari đọc tốt "chuyển sang nội suy EPX trong các tình huống tải thấp" nghĩa là gì. Khi tôi lần đầu tiên đọc câu tôi đã nghĩ rằng tối ưu hóa độ tương phản cho phép các màu mới được tạo ở mức tải thấp, nhưng NO: en.wikipedia.org/wiki/iêu
Timo Kähkönen

2
Opera 12.02 trên Mac và Windows hỗ trợ kết xuất hình ảnh: -o-crisp-edge ( jsfiddle.net/VAXrL/21 ), vì vậy bạn có thể thêm nó vào câu trả lời của mình.
Timo Kähkönen

Nó có hoạt động khi tôi tăng thu phóng trình duyệt không? Tôi đã thử bản vẽ với FF 22, Chrome 27 và IE 10 trên Windows 7 khi thu phóng trình duyệt là 150% và kết quả bị mờ trên tất cả các trình duyệt. Khi tôi nhân đôi chiều rộng và chiều cao của khung vẽ và đặt nó trở lại chiều rộng và chiều cao ban đầu bằng CSS, nó sẽ vẽ các đường sắc nét.
pablo

Đó là một câu hỏi hay. Tôi không chắc chắn nếu có một thông số kỹ thuật cho hành vi mở rộng do người dùng chỉ định.
namuol

1
Tôi (từ tương lai hiện tại!) Trên Chrome 78. Tôi đang xem kết xuất hình ảnh của chế độ hình ảnh: pixelated; đang làm việc. Có vẻ như điều này đã được thêm vào năm 2015 vào Chrome 41: developers.google.com/web/updates/2015/01/pixelated
MrColes

61

Câu trả lời mới 31/07/2012

Điều này cuối cùng là trong thông số kỹ thuật vải!

Đặc tả gần đây đã thêm một thuộc tính được gọi imageSmoothingEnabled, mặc định truevà xác định xem hình ảnh được vẽ trên tọa độ không nguyên hoặc được vẽ tỷ lệ sẽ sử dụng thuật toán mượt mà hơn. Nếu nó được đặt thành falsethì hàng xóm gần nhất được sử dụng, tạo ra hình ảnh kém mịn hơn và thay vào đó chỉ tạo các pixel trông lớn hơn.

Làm mịn hình ảnh gần đây chỉ được thêm vào đặc tả canvas và không được tất cả các trình duyệt hỗ trợ, nhưng một số trình duyệt đã triển khai các phiên bản tiền tố của nhà cung cấp thuộc tính này. Trên bối cảnh tồn tạimozImageSmoothingEnabled trong Firefox và webkitImageSmoothingEnabledtrong Chrome và Safari và việc đặt những thứ này thành false sẽ ngăn việc khử răng cưa xảy ra. Thật không may, tại thời điểm viết bài, IE9 và Opera đã không triển khai thuộc tính này, nhà cung cấp có tiền tố hoặc mặt khác.


Xem trước: JSFiddle

Kết quả:

nhập mô tả hình ảnh ở đây


1
Thật không may, có vẻ như điều này cũng không hoạt động. Có lẽ tôi đang thiếu một cái gì đó? Đây là một bài kiểm tra: jsfiddle.net/VAXrL/187
namuol

12
bạn phải mở rộng quy mô bằng cách sử dụng API canvas để nó hoạt động, bạn không thể mở rộng quy mô với CSS bao giờ và để API canvas ảnh hưởng đến nó! Vì vậy, một cái gì đó như thế này: jsfiddle.net/VAXrL/190
Simon Sarris

1
Nhưng bản chất của vấn đề này không thực sự là về vải. Đó là về cách trình duyệt hiển thị hình ảnh được chia tỷ lệ, bao gồm các phần tử <canvas>.
namuol

4
Nếu bạn mở rộng quy mô bằng CSS, giải pháp của namuol sẽ hoạt động. Nếu bạn chia tỷ lệ hình ảnh theo cách thủ công lên Canvas, giải pháp của Simon sẽ hoạt động. Thật gọn gàng khi có giải pháp cho cả hai trường hợp, vì vậy cảm ơn cả hai bạn!
Shaun Lebron

Đối với IE 11: msImageSmoothingEnables hoạt động với tôi! msdn.microsoft.com/en-us/l Library / dn265062 (v = vs85) .aspx
steve

11

Chỉnh sửa 31/07/2012 - Chức năng này hiện có trong thông số kỹ thuật canvas! Xem câu trả lời riêng ở đây:

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

Câu trả lời cũ là dưới đây cho hậu thế.


Tùy thuộc vào hiệu ứng mong muốn của bạn, bạn có tùy chọn này như một tùy chọn:

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/

Điều này tạo ra điều này:

nhập mô tả hình ảnh ở đây

Có lẽ không phải là những gì bạn muốn. Nhưng nếu bạn chỉ đơn thuần là muốn có độ mờ bằng 0 thì đó sẽ là vé vì vậy tôi sẽ cung cấp nó trong trường hợp này.

Một lựa chọn khó khăn hơn là sử dụng thao tác pixel và tự viết một thuật toán cho công việc. Mỗi pixel của hình ảnh đầu tiên trở thành một khối pixel 5x5 trên hình ảnh mới. Nó sẽ không quá khó để làm với imagedata.

Nhưng một mình Canvas và CSS sẽ không giúp bạn ở đây để nhân rộng cái này sang cái khác với hiệu quả chính xác mà bạn mong muốn.


Vâng, đó là những gì tôi sợ. Rõ ràng, image-rendering: -webkit-optimize-contrastnên thực hiện các mẹo nhưng dường như không làm gì cả. Tôi có thể xem xét việc cuộn một hàm để mở rộng nội dung của khung vẽ bằng cách sử dụng phép nội suy lân cận gần nhất.
namuol

Ban đầu tôi chấp nhận câu trả lời của bạn; Tôi đã thu hồi nó ngay bây giờ vì dường như có sự nhầm lẫn về việc liệu đây có phải là một bản sao hay không.
namuol

Tôi có một câu trả lời đầy đủ hơn sau khi thực hiện một số nghiên cứu và muốn mở lại câu hỏi để cung cấp câu trả lời của tôi.
namuol

3

Trong google chrome, các mẫu hình ảnh canvas không được nội suy.

Dưới đây là một ví dụ hoạt động được chỉnh sửa từ câu trả lời namuol http://jsfiddle.net/pGs4f/

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

Đây là cách giải quyết hấp dẫn nhất tôi từng thấy cho đến nay. Không chắc chắn về hiệu suất, nhưng nó hoàn toàn đáng để xem xét. Tôi se thử no.
namuol

sử dụng lặp lại thay vì không lặp lại là nhanh hơn. Không biết tại sao. Nó cũng khá nhanh, ba.js sử dụng điều này trong CanvasRenderer
saviski

6
cập nhật: không còn hoạt động với chrome 21 (do hỗ trợ hiển thị võng mạc được thêm vào?) phiên bản mới jsfiddle.net/saviski/pGs4f/12 bằng cách sử dụng imageSmoothingEnatted được chỉ định bởi Simon
saviski

Khi độ phân giải Retina trở nên chung chung, mọi thứ thay đổi rất lớn. Khi màn hình Retina của iPhone4-5 kiểu 326dpi (128dpcm) đến màn hình 24 inch (52x32cm), kích thước màn hình sẽ là 6656 x 4096 px. Sau đó, khử răng cưa là xấu và tất cả các nhà cung cấp trình duyệt (thậm chí dựa trên Webkit) buộc phải cho phép vô hiệu hóa khử răng cưa. Khử răng cưa là hoạt động chuyên sâu cpu và khử răng cưa hình ảnh 6656 x 4096 px sẽ quá chậm, nhưng may mắn là không cần thiết trong màn hình như vậy.
Timo Kähkönen

1
Chỉ là một ghi chú bên lề, đây là một mẫu aboout chuẩn so với hình ảnh: jsperf.com/drawimage-vs-canvaspotype/9
yckart

1

Cách giải quyết của Saviski được giải thích ở đây rất hứa hẹn, bởi vì nó hoạt động trên:

  • Chrome 22.0.1229.79 Mac OS X 10.6.8
  • Chrome 22.0.1229.79 m Windows 7
  • Chromium 18.0.1025.168 (Nhà phát triển Xây dựng 134367 Linux) Ubuntu 11.10
  • Firefox 3.6.25 Windows 7

Nhưng không hoạt động như sau, nhưng hiệu quả tương tự có thể đạt được bằng cách sử dụng kết xuất hình ảnh CSS:

  • Firefox 15.0.1 Mac OS X 10.6.8 (kết xuất hình ảnh: -moz-crisp-edge hoạt động trong việc này )
  • Opera 12.02 Mac OS X 10.6.8 (kết xuất hình ảnh: -o-sắc nét cạnh hoạt động trong này )
  • Opera 12.02 Windows 7 (kết xuất hình ảnh: -o-sắc nét cạnh hoạt động trong này )

Vấn đề là ở đây, bởi vì ctx.XXXImageSmoothingEnables không hoạt động và kết xuất hình ảnh không hoạt động:

  • Safari 5.1.7 Mac OS X 10.6.8. (kết xuất hình ảnh: -webkit-tối ưu hóa độ tương phản KHÔNG hoạt động)
  • Safari 5.1.7 Windows 7 (kết xuất hình ảnh: -webkit-tối ưu hóa độ tương phản KHÔNG hoạt động)
  • IE 9 Windows 7 (-ms-interpolation-mode: lân cận gần nhất KHÔNG hoạt động)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.