2014-11-14 1 views
1

Я пытаюсь создать те же данные base64 для файла изображения как в JavaScript, так и в Ruby. К сожалению, оба из них выводят два очень разных значения.Почему canvas.toDataURL() не создает тот же base64, что и Ruby для изображения?

В Ruby я это сделать:

Base64.encode64(File.binread('test.png')); 

, а затем в JavaScript:

var image = new Image(); 
image.src = 'http://localhost:8000/test.png'; 

$(image).load(function() { 
    var canvas, context, base64ImageData; 

    canvas = document.createElement('canvas'); 
    context = canvas.getContext('2d'); 
    canvas.width = this.width; 
    canvas.height = this.height; 
    context.drawImage(this, 0, 0); 
    imageData = canvas.toDataURL('image/png').replace(/data:image\/[a-z]+;base64,/, ''); 

    console.log(imageData); 
}); 

Любая идея, почему эти результаты отличаются?

+0

делает изображение выглядеть так же, если смотреть? – dandavis

+0

Да, это выглядит так же, если я декодирую base64 в Ruby и сохраняю необработанные данные в PNG-файле. –

ответ

3

При загрузке изображения в Ruby двоичный файл без каких-либо изменений будет закодирован непосредственно на base-64.

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

  • профиль ICC будет применяться (если файл изображения содержит, что)
  • гамма-коррекция (если поддерживается)

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

По мере изменения значений цвета результирующая строка из холста естественно будет также отличаться, прежде чем вы попадете на этап повторного кодирования растрового изображения (поскольку PNG не имеет потерь, кодирование/сжатие должно быть довольно идентичным, но факторы могут существовать в зависимости от реализации браузера, которые также будут влиять на это. Чтобы проверить, сохранить черный необработанный холст в формате PNG и сравнить с похожим изображением из вашего приложения - все значения должны быть равны 0, включая альфа и одинаковые размеры конечно).

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

Возможное решение, которое работает в некоторых случаях, заключается в удалении любого профиля ICC из файла изображения. Чтобы сохранить изображение из Photoshop без ICC, выберите «Сохранить для Интернета» в меню файла.

+0

Отмечая это как ответ, потому что он отвечает на мой вопрос «почему»; хотя, я разместил решение в другом ответе здесь. –

1

Браузер перекодирует изображение при сохранении холста.

Он не генерирует идентичную кодировку в файл, который вы предоставили.

+0

Есть ли способ как-то получить тот же base64? –

+0

Сделайте запрос AJAX на этот URL и вообще не используйте холст. – SLaks

+0

Вы случайно не знаете, где может быть пример этого? –

0

Так что я на самом деле в конечном итоге решить эту ...

К счастью, я использую imgcache.js для кэширования изображений в локальной файловой системе, используя FileSystem API. Мое решение состоит в том, чтобы использовать этот API (и imgcache.js упрощает), чтобы получить данные base64 из фактической кешированной копии файла. Код выглядит следующим образом:

var imageUrl = 'http://localhost:8000/test.png'; 

ImgCache.init(function() { 
    ImgCache.cacheFile(imageUrl, function() { 
     ImgCache.getCachedFile(imageUrl, function(url, fileEntry) { 
      fileEntry.file(function(file) { 
       var reader = new FileReader(); 
       reader.onloadend = function(e) { 
        console.log($.md5(this.result.replace(/data:image\/[a-z]+;base64,/, ''))); 
       }; 
       reader.readAsDataURL(file); 
      }); 
     }); 
    }); 
}); 

Кроме того, и это очень важно, я должен был удалить разрывы строк из base64 в Ruby:

Base64.encode64(File.binread('test.png')).gsub("\n", ''); 
+0

Вам вообще не нужна файловая система; вы можете просто прочитать его из ответа AJAX. См. Также https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data – SLaks

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