Плохое сглаживание текста на холсте - PullRequest
7 голосов
/ 10 марта 2011

Я рисую текст на холсте и разочарован качеством сглаживания. Насколько мне удалось определить, браузеры не выполняют субпиксельное сглаживание текста на Canvas.

Это точно?

Это особенно заметно на iPhone и Android, где результирующий текст не такой четкий, как текст, отображаемый другими элементами DOM.

Есть ли какие-нибудь предложения по выводу высококачественного текста на холст?

Жубер

Ответы [ 4 ]

9 голосов
/ 02 октября 2014

Мой ответ пришел по этой ссылке, возможно, это поможет кому-то еще.http://www.html5rocks.com/en/tutorials/canvas/hidpi/

Важный код выглядит следующим образом.

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

}
2 голосов
/ 16 ноября 2012

Попробуйте добавить следующий тег META на свою страницу.Похоже, это устраняет проблемы сглаживания, которые были у меня на iPhone Safari:

<meta name="viewport" content="user-scalable=no, width=device-width,
      initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5" />
1 голос
/ 24 января 2014

Я понимаю, что это старый вопрос, но я работал над этой проблемой сегодня и получил, что она работает хорошо. Я использовал ответ Аликс Аксель выше и разобрал код, который нашел там (по ссылке web.archive.org), до самого необходимого.

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

Вот что я придумала ... http://jsfiddle.net/X2cKa/

Код выглядит так:

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

Я также добавил текстовый объект сравнения, чтобы вы могли видеть, как работает сглаживание.

Надеюсь, это кому-нибудь поможет!

0 голосов
/ 10 марта 2011

Субпиксельное сглаживание выполнено, но это зависит от браузера / ОС.

Было немного более раннего обсуждения по этому вопросу, которое может вам помочь.

У меня нет устройства Android или iOS, но только для удовольствия, попробуйте перевести контекст на (.5, 0) пикселей, прежде чем рисовать, и посмотрите, имеет ли это значение в том, как отображается ваш текст.

...