此文章為譯文古程,作者:Paul Lewis 寫于:2012-8-25
原文地址:http://www.html5rocks.com/en/tutorials/canvas/hidpi/?redirect_from_locale=zh
由于原文編寫時間已經(jīng)比較久遠(yuǎn)鳄虱,BackingStorePixelRatio屬性已經(jīng)被棄用了捉偏,所以本文做一些修改折欠。
感謝 @玄魂 的提醒叠萍。
序
HIDPI屏幕是一個非常棒的東西造壮,他讓一切變得清晰渡讼。這也讓我們開發(fā)者遇到了一些新的挑戰(zhàn)。在本文中耳璧,我們將研究在如何在HIDPI的屏幕上使用canvas繪制高清的圖片成箫。
設(shè)備像素比(window.devicePixelRatio)
讓我們開始吧!回到之前談到的旨枯,HIDPI的屏幕上的像素(邏輯像素)蹬昌,我們可以當(dāng)做是正常的像素(css中設(shè)置的像素),你可以正常使用它攀隔。如果你畫一個100px的東西皂贩,他也就是一個100px的東西栖榨。但是,在出現(xiàn)了一些高分辨率屏幕的手機(jī)之后明刷,一個屬性devicePixelRatio就一起出現(xiàn)了治泥。它允許我們?nèi)ゲ樵冊O(shè)備像素比。在這里我們需要拋出一個名詞邏輯像素遮精,也就是在css設(shè)置的100px時居夹,在iphone4S(devicePixelRatio為2)上,實(shí)際渲染的是200px的物理像素本冲。
這個屬性是非常有意思的准脂。但是這對于我們開發(fā)者的影響是什么呢?早些時候檬洞,我們注意到當(dāng)我們向這種高分辨率的屏幕添加img的時候狸膏,我們的圖形受到devicePixelRatio的影響變得非常模糊。
如何解決這個問題呢添怔?我發(fā)現(xiàn)如果我把img的寬和高分別與devicePixelRatio相乘湾戳,得到的大小畫進(jìn)屏幕中,在對齊進(jìn)行縮放devicePixelRatio的大小广料。Img就會以一種高清的方式呈現(xiàn)砾脑。
BackingStorePixelRatio(此屬性已被棄用,詳情查閱)
那么在canvas中是怎么樣的呢艾杏?在桌面版chrmoe與safari6會有不同的表現(xiàn)韧衣。并且在這里又需要拋出一個新的名詞webkitBackingStorePixelRatio。目前只在webkit上出現(xiàn)(2012年购桑。2016年5月27測試畅铭,只有Safari有這個屬性。勃蜘。硕噩。。)缭贡,火狐與微軟可能在未來支持炉擅。坑资。
簡單的說BackingStorePixelRatio就告訴瀏覽器canvas背后的緩存區(qū)的像素比。如果我們說一張圖片的寬度為200px但是webkitBackingStorPixelRatio為2匀归。在canvas緩存區(qū)中真的數(shù)據(jù)九尾400px
#具體差異
在擁有高清屏幕的Macbook Pro上,Safari與chrome的表現(xiàn)并不相同穆端。Safari上webkitBackingStorePixelRatio的值是2,devicePoxelRatio的值也是2仿便,但是在chrome上webkitBackingStorePixelRatio的值是1体啰,devicePoxelRatio的值是2攒巍。也就是說在Safari上我們的圖形會自動以一種清晰的方式呈現(xiàn),而在chrome上他是被模糊的荒勇。
所以我們會發(fā)問柒莉,為什么chrome不能與Safari一樣自動適應(yīng)高清的圖形輸出呢?
實(shí)現(xiàn)
所以我們只能自己去適應(yīng)沽翔。解決的辦法也想到簡單
upsize your canvas width and height by devicePixelRatio / webkitBackingStorePixelRatio and then use CSS to scale it back down to the logical pixel size you want.
放大devicePixelRatio 倍canvas的寬高兢孝,然后用css在縮小回到你想要的理想像素。就比如仅偎,之前我們了解到高清屏幕設(shè)備的chrome中devicePixelRatio = 2跨蟹。所以將canvas的寬和高會放大 2 被,相當(dāng)于 * 2橘沥。然后使用css縮放會原來的大小窗轩。
最后我們需要考慮到,我們手動把畫布放大了2倍座咆,又通過css把他的樣式大小縮放回去原來的大小痢艺。這里會造成畫布里的圖形有縮放的問題,所以我們需要縮放回去介陶。
具體的代碼如
/**
* Writes an image into a canvas taking into
* account the backing store pixel ratio and
* the device pixel ratio.
*
* @author Paul Lewis
* @param {Object} opts The params for drawing an image to the canvas
*/
function drawImage(opts) {
if(!opts.canvas) {
throw("A canvas is required");
}
if(!opts.image) {
throw("Image is required");
}
// get the canvas and context
var canvas = opts.canvas,
context = canvas.getContext('2d'),
image = opts.image,
// now default all the dimension info
srcx = opts.srcx || 0,
srcy = opts.srcy || 0,
srcw = opts.srcw || image.naturalWidth,
srch = opts.srch || image.naturalHeight,
desx = opts.desx || srcx,
desy = opts.desy || srcy,
desw = opts.desw || srcw,
desh = opts.desh || srch,
auto = opts.auto,
// finally query the various pixel ratios
devicePixelRatio = window.devicePixelRatio || 1,
// backingStoreRatio此屬性已被棄用
// backingStoreRatio = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1,
// ratio = devicePixelRatio / backingStoreRatio;
ratio = devicePixelRatio;
// ensure we have a value set for auto.
// If auto is set to false then we
// will simply not upscale the canvas
// and the default behaviour will be maintained
if (typeof auto === 'undefined') {
auto = true;
}
// upscale the canvas if the two ratios don't match
// if (auto && devicePixelRatio !== backingStoreRatio) {
if (auto && devicePixelRatio) {
var oldWidth = canvas.width;
var oldHeight = canvas.height;
canvas.width = oldWidth * ratio;
canvas.height = oldHeight * ratio;
canvas.style.width = oldWidth + 'px';
canvas.style.height = oldHeight + 'px';
// now scale the context to counter
// the fact that we've manually scaled
// our canvas element
context.scale(ratio, ratio);
}
context.drawImage(pic, srcx, srcy, srcw, srch, desx, desy, desw, desh);
}