Извлечение эскиза из файла jpeg

Я хочу извлечь эскиз из jpegs без какой-либо внешней библиотеки. Я имею в виду, что это не слишком сложно, потому что мне нужно знать, где начинается эскиз, и заканчивается в файле, и просто разрезайте его. Я изучаю многие документы (например: http://www.media.mit.edu/pia/Research/deepview/exif.html) и пытаюсь проанализировать jpegs, но не все понятно. Я пытался отслеживать шаг за шагом байты, но в глубине я смутился. Есть ли хорошая документация или читаемый исходный код для извлечения информации о стартовой и конечной позиции эскизов в файле jpeg?

Спасибо!

Ответ 1

Для большинства изображений JPEG, созданных телефонами или цифровыми камерами, эскиз (если присутствует) сохраняется в марке APP1 (FFE1). Внутри этого сегмента маркера находится файл TIFF, содержащий информацию EXIF ​​для основного изображения и дополнительное эскизное изображение, сохраненное как сжатое изображение JPEG. Файл TIFF обычно содержит две "страницы", где первой страницей является информация EXIF, а вторая страница - это миниатюра, хранящаяся в "старом" формате TIFF типа 6. Формат типа 6 - это когда файл JPEG только что хранится как внутри TIFF-обертки. Если вы хотите, чтобы простейший возможный код извлекал миниатюру в виде JFIF, вам необходимо выполнить следующие шаги:

  • Ознакомьтесь с маркерами/тегами JFIF и TIFF. Маркеры JFIF состоят из двух байтов: 0xFF, за которым следует тип маркера (0xE1 для APP1). За этими двумя байтами следует двухбайтная длина, хранящаяся в ординарном порядке. Для файлов TIFF обратитесь к справочнику Adobe TIFF 6.0.
  • Найдите файл JPEG для маркера EXIF ​​APP1 (FFE1). Может быть несколько маркеров APP1, и перед APP1 может быть несколько маркеров.
  • Маркер APP1, который вы ищете, содержит буквы "EXIF" сразу после поля длины.
  • Найдите "II" или "MM" (в 6 байт от длины), чтобы указать конечность, используемую в файле TIFF. II = Intel = little endian, MM = Motorola = большой endian.
  • Пропустите теги первой страницы, чтобы найти вторую IFD, где хранится изображение. Во второй "странице" найдите два тега TIFF, которые указывают на данные JPEG. Tag 0x201 имеет смещение данных JPEG (относительно II/MM), а тег 0x202 имеет длину в байтах.

Ответ 2

Exiftool очень легко справляется и быстро:

exiftool -b -ThumbnailImage my_image.jpg > my_thumbnail.jpg

Ответ 3

Существует гораздо более простое решение этой проблемы, но я не знаю, насколько она надежна: начните чтение файла JPEG из третьего байта и найдите FFD8 (начало маркера изображения JPEG), затем для FFD9 (конец маркера изображения JPEG). Извлеките его и вуаля, чтобы ваш эскиз.

Простая реализация JavaScript:

function getThumbnail(file, callback) {
    if (file.type == "image/jpeg") {
        var reader = new FileReader();
        reader.onload = function (e) {
            var array = new Uint8Array(e.target.result),
                start, end;
            for (var i = 2; i < array.length; i++) {
                if (array[i] == 0xFF) {
                    if (!start) {
                        if (array[i + 1] == 0xD8) {
                            start = i;
                        }
                    } else {
                        if (array[i + 1] == 0xD9) {
                            end = i;
                            break;
                        }
                    }
                }
            }
            if (start && end) {
                callback(new Blob([array.subarray(start, end)], {type:"image/jpeg"}));
            } else {
                // TODO scale with canvas
            }
        }
        reader.readAsArrayBuffer(file.slice(0, 50000));
    } else if (file.type.indexOf("image/") === 0) {
        // TODO scale with canvas
    }
}

Ответ 4

Страница wikipedia на JFIF в http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format дает хорошее описание заголовка JPEG (заголовок содержит миниатюру в виде несжатого растрового изображения). Это должно дать вам представление о макете и, следовательно, код, необходимый для извлечения информации.

Hexdump заголовка изображения (маленький конец дисплея):

[email protected]:~$ head -c 48 stfu.jpg |hexdump
0000000 d8ff e0ff 1000 464a 4649 0100 0101 4800
0000010 4800 0000 e1ff 1600 7845 6669 0000 4d4d
0000020 2a00 0000 0800 0000 0000 0000 feff 1700

Магия изображения (байты 1,0), заголовок сегмента App0 Магия (байты 3,2), Длина заголовка (5,4) Подпись заголовка ( "JFIF\0" || "JFXX\0" ) (байты 6 -10), Версия (байты 11,12) Единицы плотности (байт 13), X Плотность (байты 15,14), Y Плотность (байты 17,16), Ширина миниатюры (байт 19), Высота эскиза (байт 18) и, наконец, отдохнуть до "Длина заголовка" - это миниатюрные данные.

В приведенном выше примере вы можете видеть, что длина заголовка составляет 16 байт (байты 6,5), а версия - 01.01 (байты 12,13). Кроме того, поскольку ширина эскиза и высота эскиза равны 0x00, изображение не содержит миниатюры.