Como escalar imagens em uma tela html5 com melhor interpolação?
Primeiro de tudo: o que estou tentando fazer?
Eu tenho um aplicativo para visualizar imagens. Ele usa o elemento canvas para renderizar a imagem. Você pode aumentar o zoom, diminuir o zoom e arrastá-lo. Esta parte funciona perfeitamente agora.
Mas digamos que eu tenha uma imagem com muito texto. Tem uma resolução de 1200x1700 e a minha tela tem 1200x900. Inicialmente, quando diminuído, isso leva a uma resolução renderizada de ~ 560x800.
Meu desenho real é assim:
drawImage(src, srcOffsetX, srcOffsetY, sourceViewWidth, sourceViewHeight,
destOffsetX, destOffsetY, destWidth, destHeight);
O texto pequeno nesta imagem parece muito, muito ruim, especialmente quando comparado a outros visualizadores de imagens (por exemplo, IrfanView), ou mesmo ao elemento html <img>.
Eu descobri que o algoritmo de interpolação dos navegadores é a causa desse problema. A comparação de diferentes navegadores mostrou que o Google Chrome torna as imagens dimensionadas melhor, mas ainda não é bom o suficiente.
Bem, eu procurei em todos os cantos da Interwebs por 4-5 horas seguidas e não encontrei o que eu preciso. Eu encontrei a opção "imageSmoothingEnabled", os estilos CSS "image-rendering" que você não pode usar em canvas, renderizando em posições flutuantes e muitas implementações em JavaScript de algoritmos de interpolação (estes sãolonge para retardar para o meu propósito).
Você pode perguntar por que eu estou lhe dizendo tudo isso: para economizar tempo para me dar respostas que eu já sei
Então: existequalquer maneira boa e rápida de ter melhor interpolação? Minha idéia atual é criar um objeto de imagem, redimensionar isso (porque img tem boa interpolação quando dimensionado!) E processá-lo então. Infelizmente, aplicar img.width parece afetar apenas a largura exibida ...
Atualizar: Graças ao Simon, eu poderia resolver o meu problema. Aqui está o algoritmo de escala dinâmica que usei. Observe que ele mantém a proporção, o parâmetro height é apenas para evitar mais computação float. Ele só diminui agora.
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);
}