HTML5 - изменить размер изображения и сохранить EXIF ​​в измененном изображении

Как изменить размер изображения (с помощью элемента HTML5 canvas) и сохранить информацию EXIF ​​из исходного изображения? Я могу извлечь информацию EXIF ​​​​из исходного изображения, но я не знаю, как скопировать ее в изображение с измененным размером.

Вот как я получаю данные изображения с измененным размером для отправки коду на стороне сервера:

canvas.toDataURL("image/jpeg", 0.7);

Для получения EXIF ​​я использую библиотеку exif.js.


person Martin Perry    schedule 18.08.2013    source источник


Ответы (4)


Рабочее решение: ExifRestorer.js

Использование с изменением размера изображения HTML5:

function dataURItoBlob(dataURI) 
{
    var binary = atob(dataURI.split(',')[1]);
    var array = [];
    for(var i = 0; i < binary.length; i++) {
        array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
}

И основной код, взятый как часть изменения размера HTML5 с этой страницы: https://github.com/josefrichter/resize/blob/master/public/preprocess.js (с небольшими изменениями)

var reader = new FileReader();

//reader.readAsArrayBuffer(file); //load data ... old version
reader.readAsDataURL(file);       //load data ... new version
reader.onload = function (event) {
// blob stuff
//var blob = new Blob([event.target.result]); // create blob... old version
var blob = dataURItoBlob(event.target.result); // create blob...new version
window.URL = window.URL || window.webkitURL;
var blobURL = window.URL.createObjectURL(blob); // and get it's URL

// helper Image object
var image = new Image();
image.src = blobURL;

image.onload = function() {

   // have to wait till it's loaded
   var resized = ResizeImage(image); // send it to canvas

   resized = ExifRestorer.restore(event.target.result, resized);  //<= EXIF  

   var newinput = document.createElement("input");
   newinput.type = 'hidden';
   newinput.name = 'html5_images[]';
   newinput.value = resized; // put result from canvas into new hidden input
   form.appendChild(newinput);
 };
};
person Martin Perry    schedule 18.08.2013
comment
Вы бы создали репозиторий GitHub для своего файла ExifRestorer.js и добавили бы лицензию, чтобы другие могли его использовать? Или вы бы прямо указали условия, на которых другие могут использовать код в вашем ответе здесь? - person Kenny Evitt; 16.10.2014
comment
@KennyEvitt Вы можете использовать код по своему усмотрению. Я его не создавал, я просто соединил вместе несколько частей разных кодов. - person Martin Perry; 16.10.2014
comment
@MartinPerry - он отлично работает с моим кодом - я делаю некоторые манипуляции с изображением на холсте - тогда я могу восстановить данные. Однако я хотел бы перезаписать значение ориентации exif изображения. Как только я поворачиваю изображение с помощью холста, ориентация exif остается неправильной. Есть ли какое-нибудь решение для этого? - person krystiangw; 01.07.2015
comment
Спасибо за ExifRestorer.js. Прекрасный сценарий! ‹3 - person larsemil; 13.12.2017
comment
Чтобы ExifRestore.js работал с типами файлов, отличными от jpeg, необходимо заменить вхождения 'data:image/jpeg;base64,' в библиотеке на /data:image\/\w+;base64,/ - person whirmill; 29.06.2018

Похоже, мой код используется в ExifRestorer.js...

Я пытаюсь изменить размер изображения на холсте. И я чувствовал, что изображение с измененным размером плохого качества. Если вы тоже так считаете, попробуйте мой код. Мой код изменяет размер JPEG с помощью билинейной интерполяции. Exif естественно не теряется.

https://github.com/hMatoba/JavaScript-MinifyJpegAsync

function post(data) {
    var req = new XMLHttpRequest();
    req.open("POST", "/jpeg", false);
    req.setRequestHeader('Content-Type', 'image/jpeg');
    req.send(data.buffer);
}

function handleFileSelect(evt) {
    var files = evt.target.files;

    for (var i = 0, f; f = files[i]; i++){
        var reader = new FileReader();
        reader.onloadend = function(e){
            MinifyJpegAsync.minify(e.target.result, 1280, post);
        };
    reader.readAsDataURL(f);
    }
}

document.getElementById('files').addEventListener('change', handleFileSelect, false);
person hMatoba    schedule 19.02.2015

Вы можете использовать copyExif.js.

Этот модуль более эффективен, чем решение Мартина, и использует только Blob и ArrayBuffer без кодировщика/декодера Base64.

Кроме того, нет необходимости использовать exif.js, если вы хотите сохранить EXIF . Просто скопируйте весь маркер APP1 из исходного JPEG в целевой блок холста, и все будет работать. Это также то, как работает copyExif.js.

использование

демо: https://codepen.io/tonytonyjan/project/editor/XEkOkv

<input type="file" id="file" accept="image/jpeg" />
import copyExif from "./copyExif.js";

document.getElementById("file").onchange = async ({ target: { files } }) => {
  const file = files[0],
    canvas = document.createElement("canvas"),
    ctx = canvas.getContext("2d");

  ctx.drawImage(await blobToImage(file), 0, 0, canvas.width, canvas.height);
  canvas.toBlob(
    async blob =>
      document.body.appendChild(await blobToImage(await copyExif(file, blob))),
    "image/jpeg"
  );
};

const blobToImage = blob => {
  return new Promise(resolve => {
    const reader = new FileReader(),
      image = new Image();
    image.onload = () => resolve(image);
    reader.onload = ({ target: { result: dataURL } }) => (image.src = dataURL);
    reader.readAsDataURL(blob);
  });
};
person Weihang Jian    schedule 23.09.2019
comment
Я внес некоторые изменения в приведенный выше код по мере необходимости. Теперь, когда изображение вращается, я хочу установить ориентацию на 0, вы можете мне помочь? и я не могу использовать ctx.transform, потому что мне нужен объект Blob в конце. - person mangeshbhuskute; 28.04.2021

Canvas генерирует изображения с 20-байтовым заголовком (до начала сегментов данных jpeg). Вы можете нарезать заголовок сегментами exif из исходного файла и заменить первые 20 байтов в файле с измененным размером.

person Vitaly    schedule 21.09.2014