2011-03-10 6 views
7

Estoy dibujando texto en lienzo, y estoy decepcionado con la calidad de antialiasing. Por lo que he podido determinar, los navegadores no hacen una antialización subpixel de texto en Canvas.Pobre anti-aliasing de texto dibujado en lienzo

¿Es esto exacto?

Esto es particularmente notable en iPhone y Android, donde el texto resultante no es tan nítido como el texto representado por otros elementos DOM.

¿Alguna sugerencia de texto de alta calidad puesta en lienzo?

Joubert

+1

posible duplicado de [texto Subpixel anti-alias en el elemento de la lona de HTML5] (http://stackoverflow.com/questions/4550926/subpixel-anti-aliased-text-on-html5s-canvas-element) – Phrogz

+0

Descubrí la solución y escribí una publicación en el blog sobre ella, ya que sospecho que otros se han topado con esto también: [http://joubert.posterous.com/crisp-html-5-canvas-text-on-mobile-phones -y] (https://web.archive.org/web/20120427162431/http://joubert.posterous.com/crisp-html-5-canvas-text-on-mobile-phones-and) –

+0

Desafortunadamente ese enlace ahora está roto, me gustaría saber lo que dice. –

Respuesta

0

Hay algo de suavizado de subpíxeles hecho, pero es tarea del navegador/OS.

Hubo un poco de earlier discussion en esto que puede ser de ayuda para usted.

No tengo un dispositivo Android o iOS pero solo por diversión, intente traducir el contexto por (.5, 0) píxeles antes de dibujar y vea si eso hace una diferencia en la forma en que se representa el texto.

2

Intente agregar la siguiente etiqueta META a su página. Esto parece solucionar los problemas de anti-aliasing que he tenido en el iPhone Safari:

<meta name="viewport" content="user-scalable=no, width=device-width, 
     initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5" /> 
+0

¡¡Gracias !! Esto me ha vuelto loco – Jackson

1

Comprendo que esto es una vieja pregunta, pero he trabajado en este problema hoy y tengo trabajo muy bien. Utilicé la respuesta anterior de Alix Axel y desglosé el código que encontré allí (en el enlace web.archive.org) en lo esencial.

Modifiqué la solución un poco, usando dos lienzos, un lienzo oculto para el texto original y un segundo lienzo para mostrar realmente el texto antializante.

Esto es lo que se me ocurrió ... http://jsfiddle.net/X2cKa/

El código es el siguiente;

function alphaBlend(gamma, c1, c2, alpha) { 
    c1 = c1/255.0; 
    c2 = c2/255.0; 
    var c3 = Math.pow(
    Math.pow(c1, gamma) * (1 - alpha) 
     + Math.pow(c2, gamma) * alpha, 
    1/gamma 
    ); 
    return Math.round(c3 * 255); 
} 

function process(textPixels, destPixels, fg, bg) { 
    var gamma = 2.2; 
    for (var y = 0; y < textPixels.height; y ++) { 
     var history = [255, 255, 255]; 
     var pixel_number = y * textPixels.width; 
     var component = 0; 
     for (var x = 0; x < textPixels.width; x ++) { 
      var alpha = textPixels.data[(y * textPixels.width + x) * 4 + 1]/255.0; 
      alpha = Math.pow(alpha, gamma); 
      history[component] = alpha; 
      alpha = (history[0] + history[1] + history[2])/3; 
      out = alphaBlend(gamma, bg[component], fg[component], alpha); 
      destPixels.data[pixel_number * 4 + component] = out;  
      /* advance to next component/pixel */ 
      component ++; 
      if (component == 3) { 
      pixel_number ++; 
      component = 0; 
      } 
     } 
    } 
} 

function toColor(colorString) { 
    return [parseInt(colorString.substr(1, 2), 16), 
    parseInt(colorString.substr(3, 2), 16), 
    parseInt(colorString.substr(5, 2), 16)]; 
} 

function renderOnce() { 
    var phrase = "Corporate GOVERNANCE" 
    var c1 = document.getElementById("c1"); //the hidden canvas 
    var c2 = document.getElementById("c2"); //the canvas 
    var textSize=40; 

    var font = textSize+"px Arial" 
    var fg = "#ff0000"; 
    var bg = "#fff9e1"; 

    var ctx1 = c1.getContext("2d"); 
    var ctx2 = c2.getContext("2d"); 
    ctx1.fillStyle = "rgb(255, 255, 255)"; 
    ctx1.fillRect(0, 0, c1.width, c1.height); 

    ctx1.save(); 
    ctx1.scale(3, 1); 
    ctx1.font = font; 
    ctx1.fillStyle = "rgb(255, 0, 0)"; 
    ctx1.fillText(phrase, 0, textSize); 
    ctx1.restore(); 

    var textPixels = ctx1.getImageData(0, 0, c1.width, c1.height); 

    var colorFg = toColor(fg); 
    var colorBg = toColor(bg); 
    var destPixels3 = ctx1.getImageData(0, 0, c1.width, c1.height); 
    process(textPixels, destPixels3, colorBg, colorFg); 
    ctx2.putImageData(destPixels3, 0, 0); 


    //for comparison, show Comparison Text without anti aliaising 
    ctx2.font = font; 
    ctx2.fillStyle = "rgb(255, 0, 0)"; 
    ctx2.fillText(phrase, 0, textSize*2); 

}; 

renderOnce(); 

También agregué un objeto de texto de comparación para que pueda ver el funcionamiento del anti-aliasing.

Espero que esto ayude a alguien!

8

Mi respuesta vino de este enlace, tal vez ayudará a otra persona. http://www.html5rocks.com/en/tutorials/canvas/hidpi/

El código importante es el siguiente.

// finally query the various pixel ratios 
    devicePixelRatio = window.devicePixelRatio || 1, 
    backingStoreRatio = context.webkitBackingStorePixelRatio || 
         context.mozBackingStorePixelRatio || 
         context.msBackingStorePixelRatio || 
         context.oBackingStorePixelRatio || 
         context.backingStorePixelRatio || 1, 

    ratio = devicePixelRatio/backingStoreRatio; 

// upscale the canvas if the two ratios don't match 
if (devicePixelRatio !== backingStoreRatio) { 

    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); 

} 
+0

¡Gracias por el código! Funciona muy bien.Me levanté hasta este punto pero no escale el lienzo. – Danman