获得JPEG分辨率而不解码图像

时间:2010-10-22 23:47:48

标签: delphi 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字段是错误的。但同样,所有图形应用程序都可以读取此非标准文件。

有人知道一段可以实际读取所有JPEG文件的Delphi代码吗?


Delphi 7,Win 7 32位

4 个答案:

答案 0 :(得分:15)

我不知道所有JPEG文件,但您需要处理JPEG的两种常用文件格式。由于JPEG是一种压缩方法而不是文件格式,因此世界各地开发了一些将JPEG图像数据存储在文件中的方法。你最有可能遇到的两个是JFIF和EXIF。上面的代码涵盖了JFIF,但不处理EXIF。这两个在很大程度上是不兼容的,但都是JPEG,所以如果你使用标题信息,你需要检测和处理,因为它们是推迟的。

作为解决方案,作为一个例子。 EXIF的字段是 x-Resolution y-Resolution ,与X / Y密度方法相比。

我会:

  1. 对两种格式(JFIF和EXIF)进行一些阅读。我发现 维基百科是一个很好的起点 在这个参考(对于一些过去 我做过的项目,但最重要的是 可能有一些很好的信息 主题也是。

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

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

  2. 编写代码以使用起始标题检测格式

  3. 独立处理每种格式

  4. 包裹整个东西,这样你就可以把JPEG扔到它上面然后得到它 密度。这也将为您提供一个很好的位置来折腾其他帮助代码来处理JPEG处理的“有趣”世界

答案 1 :(得分:10)

以下是一些可以帮助您获取所需数据的代码:

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;

答案 2 :(得分:2)

JPEG文件头的

单位 Xdensity Ydensity 成员指定用于描述物理点密度打印文件时。

  • 如果 Units 为1,则 Xdensity Ydensity 为每英寸点数。
  • 如果单位为2,则 Xdensity Ydensity 为每厘米点数。

关键是存储在图像文件中的点分辨率(缩放的打印分辨率)在屏幕上无关紧要。因此,Windows程序将始终在屏幕上显示任何文件的96逻辑ppi。注意,一些应用程序更喜欢使用72逻辑ppi来在屏幕上显示图片,例如Adobe应用程序。

在屏幕上显示JPG文件时,ACDSee,Adobe Photoshop,CorelDRAW等图形应用程序只会忽略 Units Xdensity Ydensity 成员,但图形应用程序在打印JPG文件时会考虑这些成员的价值。如果JPG文件没有 Units Xdensity Ydensity 成员,图形应用程序将使用其自定义默认值(通常为150 dpi)打印JPG文件。

因此,对于可以读取所有JPEG头文件的Delphi代码的问题,答案很简单,只需读取JPG文件头信息;如果文件中不存在可选成员,只需忽略可选成员或告诉最终用户当前未在文件中指定它们。

进一步阅读DPI和PPI混淆

关于JPEG文件格式规范的参考

答案 3 :(得分:0)

有一个TP / TPW / Delphi(1-4,但可能会工作到没有大mod的unicode版本)包,pasjp(e)g可以读取大多数旧的JPG类型(但不是例如JPEG2000)< / p>

FPC也包括此套餐。

来自J. Nommsi的原始网站已经消失,但该套餐仍然可用,例如从