Javascript canvas.toDataURL изменения по сравнению с исходным URI данных - PullRequest
5 голосов
/ 08 апреля 2011

В настоящее время я разрабатываю расширение для Mozilla, пытаясь загрузить изображение (PNG), которое закодировано с помощью URI данных, нарисовать его на элементе canvas, чтобы окончательно изменить некоторые значения пикселей и сохранить его обратно в виде файла на диске. .

Странная вещь, которую я замечаю, заключается в том, что даже если я ничего не меняю на изображении, а просто рисую изображение на холсте и использую canvas.toDataURL (), чтобы увидеть, что генерируется, эти закодированные данные отличаются от оригинал.

Код, который я использую, чтобы увидеть это, довольно прост:

var image = new Image();
image.onload = function() {
    var canvas = document.createElement('canvas')
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext('2d').drawImage(image, 0, 0);
    var data = canvas.toDataURL(); // this right here is different from image.scr data!
}
image.src = "data:image/png;base64," + encodedData;

Я предполагаю, что есть какое-то сжатие или, возможно, что-то связанное с прозрачностью.

Я проверил документацию , но не смог найти объяснение. Мне кажется, я видел что-то, что некоторые цвета меняются на другие похожие, и это может быть тем, что мешает тому, чего я хочу достичь (то есть изменяются некоторые значения пикселей).

Есть идеи о том, что происходит?

Если нет, кто-нибудь знает, есть ли другой способ сохранить изображение холста в файл на диске без использования метода toDataURL? Может быть компонент XPCOM, способный сохранять все пиксели в двоичном формате PNG?

Спасибо

Ответы [ 2 ]

1 голос
/ 25 декабря 2015

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

Если вы установите значение альфа меньше 255 (1,0), то другие компоненты для этого пикселя, похоже, изменятся. Обойти эту проблему можно было просто установив все значения альфа на 255.

На данный момент я успешно могу сохранять точные данные точности в Canvas, используя ImageData и элемент DOM Image, а затем извлекать те же самые данные без потерь, установив для альфа-компонента значение 255 и не используя его для хранения данных. .

Вот процедуры, которые я сейчас использую:

function make_image_with_data(contents) {
    // Fractional side length.
    var fside = Math.sqrt(contents.length / 3);
    // Whole integer side length.
    var side = Math.ceil(fside);

    var cv = document.createElement('canvas');

    cv.width = side;
    cv.height = side;

    var ctx = cv.getContext('2d');
    var id = ctx.createImageData(side, side);

    var data = id.data;

    data[0] = (contents.length >> 24) & 0xff;
    data[1] = (contents.length >> 16) & 0xff;
    data[2] = (contents.length >> 8) & 0xff;
    data[3] = 255;
    data[4] = (contents.length) & 0xff;

    var z = 5;
    var x = 0;

    for (; x < contents.length; ++x) {
        data[z] = contents.charCodeAt(x);
        // Skip the image alpha component.
        ++z;
        if (z % 4 == 3) {
            data[z] = 255;
            ++z;
        }
    }

    ctx.putImageData(id, 0, 0);

    var img = document.createElement('img');
    img.width = side;
    img.height = side;

    img.src = cv.toDataURL();

    $(document.body).append(img);

    return img;
}

Тогда функция для возврата данных:

function load_data_from_image(img) {
    var cv = document.createElement('canvas');
    cv.width = img.width;
    cv.height = img.height;
    var ctx = cv.getContext('2d');

    ctx.drawImage(img, 0, 0, img.width, img.height);

    var id = ctx.getImageData(0, 0, img.width, img.height);
    var data = id.data;

    var len = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[4];
    var out = new Uint8Array(new ArrayBuffer(len)); 

    var z = 5;

    for (var x = 0; x < len; ++x) {
        out[x] = data[z];
        // This is skipping the alpha component.
        ++z;
        if (z % 4 == 3) {
            ++z;
        }
    }

    return out;
}
0 голосов
/ 08 апреля 2011

Существует множество законных способов фильтрации без потерь и кодирования PNG. Например, посмотрите на эту диаграмму , показывающую огромные различия в размере файлов, возможные при кодировании одного и того же изображения без потерь с помощью различных инструментов.

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

...