2013-09-12 3 views
31

Прежде всего: что я пытаюсь сделать?Как масштабировать изображения на холсте html5 с лучшей интерполяцией?

У меня есть приложение для просмотра изображений. Он использует элемент холста для рендеринга изображения. Вы можете увеличить масштаб, вы можете уменьшить масштаб, и вы можете перетащить его. Эта часть работает совершенно прямо сейчас.

Но скажем, у меня есть изображение с большим количеством текста. Он имеет разрешение 1200x1700, а у моего холста 1200x900. Первоначально, при увеличении, это приводит к отображению разрешения ~ 560x800.

Моего фактический рисунок выглядит следующим образом:

drawImage(src, srcOffsetX, srcOffsetY, sourceViewWidth, sourceViewHeight, 
destOffsetX, destOffsetY, destWidth, destHeight); 

Небольшой текст на этом изображении выглядит очень, очень плохо, особенно по сравнению с другими зрителями изображений (например, IrfanView), или даже HTML < IMG> элемента.

Я понял, что алгоритм интерполяции браузеров является причиной этой проблемы. Сравнение разных браузеров показало, что Chrome делает масштабированные изображения лучшими, но все же недостаточно хорошими.

Ну, я искал в каждом углу Interwebs в течение 4-5 часов подряд и не нашел то, что мне нужно. Я нашел параметр «imageSmoothingEnabled», стили CSS-изображения, которые нельзя использовать на холсте, рендеринг на позициях с плавающей точкой и многие варианты реализации алгоритмов интерполяции JavaScript (это far для замедления для моей цели).

Вы можете спросить, почему я говорю вам все это: чтобы сэкономить ваше время, чтобы дать мне ответы я уже знаю :))

Итак: есть любой хороший и быстрый способ, чтобы лучше интерполяции ? Моя идея состоит в том, чтобы создать объект изображения, изменить его размер (потому что img имеет хорошую интерполяцию при масштабировании!) И затем визуализирует его. К сожалению, применение img.width, по-видимому, влияет только на отображаемую ширину ...

Большое спасибо за ваши ответы !! :)

Обновление: Благодаря Саймону, я мог бы решить свою проблему. Вот динамический алгоритм масштабирования, который я использовал. Обратите внимание, что он поддерживает соотношение сторон, параметр высоты - только для предотвращения более плавающих вычислений. Он только масштабируется прямо сейчас.

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); 
    } 
+0

Под «лучшей интерполяцией» вы подразумеваете интерполяцию, предназначенную для лучшей читаемости текста при уменьшении? –

+0

лучшая интерполяция в целом. плохое качество текста - это всего лишь самая заметная вещь, которую вы видите ... и читаемость текста, к сожалению, очень важна для этого проекта. но если вы знаете способ сделать текст лучше, пожалуйста, скажите мне тогда! – Kumpu

+0

Возможный дубликат [Html5 canvas drawImage: как применять сглаживание] (http://stackoverflow.com/questions/17861447/html5-canvas-drawimage-how-to-apply-antialiasing) – K3N

ответ

42

Вам нужно «уйти в отставку» несколько раз. Вместо масштабирования от очень большого изображения до очень маленького, вам нужно повторно масштабировать его до размеров посредников.

Рассмотрите изображение, которое хотите нарисовать в масштабе 1/6. Вы можете сделать это:

var w = 1280; 
var h = 853; 

ctx.drawImage(img, 0, 0, w/6, h/6); 

Или вы могли бы нарисовать его на холсте в памяти на 1/2 шкалы, то масштаб 1/2 раз, то масштаб 1/2 снова.В результате масштаб 1/6 изображений, но мы используем три этапа:

var can2 = document.createElement('canvas'); 
can2.width = w/2; 
can2.height = w/2; 
var ctx2 = can2.getContext('2d'); 

ctx2.drawImage(img, 0, 0, w/2, h/2); 
ctx2.drawImage(can2, 0, 0, w/2, h/2, 0, 0, w/4, h/4); 
ctx2.drawImage(can2, 0, 0, w/4, h/4, 0, 0, w/6, h/6); 

Затем вы можете сделать, что вернуться к исходному контексту:

ctx.drawImage(can2, 0, 0, w/6, h/6, 0, 200, w/6, h/6); 

Вы можете увидеть разницу в прямом эфире, здесь:

var can = document.getElementById('canvas1'); 
 
var ctx = can.getContext('2d'); 
 

 
var img = new Image(); 
 
var w = 1280; 
 
var h = 853; 
 
img.onload = function() { 
 
    // step it down only once to 1/6 size: 
 
    ctx.drawImage(img, 0, 0, w/6, h/6); 
 
    
 
    // Step it down several times 
 
    var can2 = document.createElement('canvas'); 
 
    can2.width = w/2; 
 
    can2.height = w/2; 
 
    var ctx2 = can2.getContext('2d'); 
 
    
 
    // Draw it at 1/2 size 3 times (step down three times) 
 
    
 
    ctx2.drawImage(img, 0, 0, w/2, h/2); 
 
    ctx2.drawImage(can2, 0, 0, w/2, h/2, 0, 0, w/4, h/4); 
 
    ctx2.drawImage(can2, 0, 0, w/4, h/4, 0, 0, w/6, h/6); 
 
    ctx.drawImage(can2, 0, 0, w/6, h/6, 0, 200, w/6, h/6); 
 
} 
 

 

 

 
img.src = 'http://upload.wikimedia.org/wikipedia/commons/thumb/a/a4/Equus_quagga_%28Namutoni%2C_2012%29.jpg/1280px-Equus_quagga_%28Namutoni%2C_2012%29.jpg'
canvas { 
 
    border: 1px solid gray; 
 
}
<canvas id="canvas1" width="400" height="400"></canvas>

View same snippet on jsfiddle.

+0

Большое спасибо за эту идею! Второе изображение выглядит намного лучше! Я попробую это сейчас и посмотрю, насколько он эффективен ... – Kumpu

+0

wow я действительно впечатлен. масштабирование в 15 шагов требует всего 2 мс! (хорошо, у меня есть i7, но все же ....) спасибо – Kumpu

+0

Yeja 'drawImage()' - одна из самых быстрых операций, которые вы можете делать на холсте, так что не чувствуйте себя плохо в 8-кратном понижении на изображении весы –

Смежные вопросы