Jak skalować obrazy na płótnie html5 z lepszą interpolacją?
Po pierwsze: co próbuję zrobić?
Mam aplikację do przeglądania obrazów. Używa elementu canvas do renderowania obrazu. Możesz powiększyć, możesz pomniejszyć i przeciągnąć dookoła. Ta część działa teraz doskonale.
Ale powiedzmy, że mam obraz z dużą ilością tekstu. Ma rozdzielczość 1200x1700, a moje płótno ma 1200x900. Początkowo przy pomniejszeniu prowadzi to do renderowanej rozdzielczości ~ 560x800.
Mój rzeczywisty rysunek wygląda tak:
drawImage(src, srcOffsetX, srcOffsetY, sourceViewWidth, sourceViewHeight,
destOffsetX, destOffsetY, destWidth, destHeight);
Mały tekst na tym obrazie wygląda naprawdę, bardzo źle, zwłaszcza w porównaniu z innymi przeglądarkami obrazów (np. IrfanView) lub nawet elementem html <img>.
Zorientowałem się, że przyczyną tego problemu jest algorytm interpolacji przeglądarek. Porównanie różnych przeglądarek wykazało, że Chrome wyświetla najlepiej skalowane obrazy, ale wciąż nie jest wystarczająco dobry.
Szukałem w każdym zakątku Interwebs prosto przez 4-5 godzin i nie znalazłem tego, czego potrzebuję. Znalazłem opcję „imageSmoothingEnabled”, style CSS „renderowania obrazów”, których nie można używać na płótnie, renderowania na pozycjach float i wielu implementacjach algorytmów interpolacji w JavaScript (są todaleko spowolnić dla mojego celu).
Możesz zapytać, dlaczego ci to wszystko mówię: aby zaoszczędzić ci czasu na udzielenie mi odpowiedzi, które już znam
Więc: jestkażdy dobry i szybki sposób na lepszą interpolację? Moim obecnym pomysłem jest stworzenie obiektu obrazu, zmiana jego rozmiaru (ponieważ img ma dobrą interpolację po przeskalowaniu!) I renderuje go. Niestety, zastosowanie img.width wydaje się tylko wpływać na wyświetlaną szerokość ...
Aktualizacja: Dzięki Simonowi mogłem rozwiązać mój problem. Oto algorytm skalowania dynamicznego, którego użyłem. Zauważ, że zachowuje proporcje, parametr wysokości służy tylko do unikania obliczeń pływakowych. Teraz tylko się skaluje.
scale(destWidth, destHeight){
var start = new Date().getTime();
var scalingSteps = 0;
var ctx = this._sourceImageCanvasContext;
var curWidth = this._sourceImageWidth;
var curHeight = this._sourceImageHeight;
var lastWidth = this._sourceImageWidth;
var lastHeight = this._sourceImageHeight;
var end = false;
var scale=0.75;
while(end==false){
scalingSteps +=1;
curWidth *= scale;
curHeight *= scale;
if(curWidth < destWidth){
curWidth = destWidth;
curHeight = destHeight;
end=true;
}
ctx.drawImage(this._sourceImageCanvas, 0, 0, Math.round(lastWidth), Math.round(lastHeight), 0, 0, Math.round(curWidth), Math.round(curHeight));
lastWidth = curWidth;
lastHeight = curHeight;
}
var endTime =new Date().getTime();
console.log("execution time: "+ ( endTime - start) + "ms. scale per frame: "+scale+ " scaling step count: "+scalingSteps);
}