Получение разрешения JPEG без декодирования изображения

Я пытаюсь получить разрешение изображения JPEG без декодирования файла. Я получил несколько образцов из Интернета, но ни один не работает должным образом. Кажется, это так, потому что многие файлы JPEG не являются стандартными, хотя любое графическое приложение (Irfan, PSP, Firefox и т. Д.) Может открыть их.

Заголовок JPEG должен был быть:

typedef struct _JFIFHeader
{
  BYTE SOI[2];          /* 00h  Start of Image Marker     */
  BYTE APP0[2];         /* 02h  Application Use Marker    */
  BYTE Length[2];       /* 04h  Length of APP0 Field      */
  BYTE Identifier[5];   /* 06h  "JFIF" (zero terminated) Id String */
  BYTE Version[2];      /* 07h  JFIF Format Revision      */
  BYTE Units;           /* 09h  Units used for Resolution */
  BYTE Xdensity[2];     /* 0Ah  Horizontal Resolution     */
  BYTE Ydensity[2];     /* 0Ch  Vertical Resolution       */
  BYTE XThumbnail;      /* 0Eh  Horizontal Pixel Count    */
  BYTE YThumbnail;      /* 0Fh  Vertical Pixel Count      */
} JFIFHEAD;

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

Кто-нибудь знает кусок кода Delphi, который может читать все файлы JPEG?


Delphi 7, Win 7 32 бит

4 ответа

Решение

Вот код, который может помочь вам получить нужные данные:

function GetJpegSize(jpeg: TMemoryStream; out width, height, BitDepth: integer): boolean;
var n: integer;
    b: byte;
    w: Word;
begin
  result := false;
  n := jpeg.Size-8;
  jpeg.Position := 0;
  if n<=0 then
    exit;
  jpeg.Read(w,2);
  if w<>$D8FF then
    exit; // invalid format
  jpeg.Read(b,1);
  while (jpeg.Position<n) and (b=$FF) do begin
    jpeg.Read(b,1);
    case b of
      $C0..$C3: begin
        jpeg.Seek(3,soFromCurrent);
        jpeg.Read(w,2);
        height := swap(w);
        jpeg.Read(w,2);
        width := swap(w);
        jpeg.Read(b,1);
        BitDepth := b*8;
        Result := true; // JPEG format OK
        exit;
      end;
      $FF:
        jpeg.Read(b,1);
      $D0..$D9, $01: begin
        jpeg.Seek(1,soFromCurrent);
        jpeg.Read(b,1);
      end;
      else begin
        jpeg.Read(w,2);
        jpeg.Seek(swap(w)-2, soFromCurrent);
        jpeg.Read(b,1);
      end;
    end;
  end;
end;

Я не знаю обо всех файлах JPEG, но вам нужно будет обработать два распространенных формата файлов для JPEG. Поскольку JPEG - это метод сжатия, а не формат файла, мир в целом разработал несколько способов хранения данных изображения JPEG в файлах. Скорее всего, вы столкнетесь с JFIF и EXIF. Приведенный выше код охватывает JFIF, но не обрабатывает EXIF. Эти два в значительной степени несовместимы, но оба являются JPEG, поэтому вам нужно будет обнаружить и обработать, если вы используете информацию заголовка, поскольку они откладываются.

Для разрешения, в качестве примера. Поле EXIF ​​- это x-Resolution и y-Resolution против подхода плотности X/Y.

Я мог бы:

  1. Чтение некоторых двух форматов (JFIF и EXIF). Я считаю, что Википедия - отличное место для начала по этой ссылке (для некоторых прошлых проектов, которые я делал), но, скорее всего, у SO тоже есть отличная информация по этой теме.

    JFIF: http://en.wikipedia.org/wiki/JPEG_File_Interchange_Format

    EXIF: http://en.wikipedia.org/wiki/Exif

  2. Напишите код для определения формата, используя начальные заголовки

  3. Обрабатывать каждый формат независимо

  4. Оберните все это так, чтобы вы могли просто добавить к нему JPEG и получить плотность. Это также даст вам отличное место, чтобы бросить другой вспомогательный код для работы с "забавным" миром обработки JPEG.

Элементы Units, Xdensity и Ydensity заголовка файла JPEG задают единицы измерения, используемые для описания физической плотности точек при печати файла.

  • Если Units - 1, Xdensity и Ydensity - это точки на дюйм.
  • Если Units - 2, Xdensity и Ydensity - это точки на см.

Дело в том, что разрешение точек (масштабированное разрешение печати), хранящееся в файле изображения, просто не имеет значения на экране. Таким образом, программы Windows всегда будут показывать вам 96 логических точек на дюйм на экране для любого файла. Обратите внимание, что некоторые приложения предпочитают использовать 72 логических ppi для отображения изображений на экране, например приложения Adobe.

Графические приложения, такие как ACDSee, Adobe Photoshop, CorelDRAW, просто игнорируют элементы Units, Xdensity и Ydensity при отображении файлов JPG на экране, но графические приложения учитывают значение этих элементов при печати файлов JPG, если они существуют. В случае, если файл JPG не имеет элементов Units, Xdensity и Ydensity, графические приложения используют свои пользовательские значения по умолчанию (обычно 150 dpi) для печати файла JPG.

Итак, на вопрос о коде Delphi, который может читать все файлы заголовков JPEG, ответ прост - просто прочитайте информацию заголовка файла JPG; в случае, если дополнительные элементы не существуют в файле, просто проигнорируйте дополнительные элементы или сообщите конечным пользователям, что они в данный момент не указаны в файле.

Дальнейшее чтение путаницы в DPI и PPI

Ссылки на спецификацию формата файла JPEG

Существует пакет TP/TPW/Delphi (1-4, но, вероятно, он будет работать до версий Unicode без больших модов), pasjp(e)g, который может читать большинство старых типов JPG (но не, например, JPEG2000)

FPC также включает этот пакет.

Оригинальный сайт от J. Nommsi исчез, но пакет все еще доступен, например, от

Другие вопросы по тегам