无需解码图像即可获取 JPEG 分辨率

发布于 2024-09-28 09:38:54 字数 993 浏览 7 评论 0原文

我试图在不解码文件的情况下获取 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;

但是,当我查看其中一个非标准文件时,X 密度和 Y 密度字段是错误的。但同样,所有图形应用程序都可以读取这个非标准文件。

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


德尔福 7、Win 7 32 位

I am trying to get the resolution of a JPEG image without decoding the file. I got several samples from internet but none is working properly. It seems to be this way because many JPEG files are not standard, though any graphic application (Irfan, PSP, Firefox etc) can open them.

The header of a JPEG was supposed to be:

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;

However, when I looked into one of those non-standard files, the Xdensity and Ydensity fields were wrong. But again, all graphic applications can read this non-standard file.

Does anybody knows a piece of Delphi code that can actually read all JPEG files?


Delphi 7, Win 7 32 bit

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

无边思念无边月 2024-10-05 09:38:54

我不知道所有 JPEG 文件,但您需要处理 JPEG 的两种常见文件格式。由于 JPEG 是一种压缩方法而不是文件格式,因此全世界已经开发了几种在文件中存储 JPEG 图像数据的方法。您最有可能遇到的两个是 JFIF 和 EXIF。上面的代码涵盖了 JFIF,但不处理 EXIF。这两者在很大程度上不兼容,但都是 JPEG,因此您需要检测并处理是否使用标头信息,因为它们是不同的。

以分辨率为例。 EXIF 的字段是x 分辨率y 分辨率,而不是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 处理的“有趣”世界

I don't know about ALL JPEG files, but you will need to handle the two common file formats for JPEG. Since JPEG is a compression method and not a file format, the world at large has developed a few ways of storing JPEG image data in files. The two you are most likely to encounter are JFIF and EXIF. The above code covers JFIF, but doesn't handle EXIF. These two are largely incompatible but both are JPEG, so you'll need to detect and handle if you are using header information, as they defer.

For resolution, as an example. EXIF's field are x-Resolution and y-Resolution, vs the X/Y Density approach.

I would:

  1. Do some reading on the two formats (JFIF and EXIF). I find
    Wikipedia is a great place to start
    on this reference (for some past
    projects I've done), but SO most
    likely has some great info on this
    topic as well.

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

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

  2. Write code to detect the format using the starting headers

  3. Handle each format independently

  4. Wrap the whole thing so you can just toss a JPEG at it and get the
    density. This will also give you a great spot to toss other helper code to deals with the "fun" world of JPEG handling

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

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;

Here is some code which could help you get the data you want:

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;
闻呓 2024-10-05 09:38:54

JPEG 文件头的 UnitsX 密度Y 密度 成员指定用于描述物理点密度的测量单位。文件被打印。

  • 如果单位为1,X密度Y密度为每英寸点数。
  • 如果单位为2,X密度Y密度为每厘米的点数。

要点是,存储在图像文件中的点分辨率(缩放后的打印分辨率)在屏幕上并不重要。因此,Windows 程序将始终在屏幕上为任何文件显示 96 逻辑 ppi。请注意,某些应用程序更喜欢使用 72 逻辑 ppi 在屏幕上显示图片,例如 Adob​​e 应用程序。

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

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

关于 DPI 和 PPI 混淆的进一步阅读

JPEG 文件格式规范参考

Units, Xdensity and Ydensity members of JPEG file header specifies unit of measurement used to describe physical dot density when a file is printed.

  • If Units is 1, Xdensity and Ydensity are dots per inch.
  • If Units is 2, Xdensity and Ydensity are dots per cm.

The point is that dot resolution (the scaled printing resolution) stored in an image file simply does not matter on the screen. Thus, Windows programs will always show you 96 logical ppi on the screen for any file. Note, some applications prefer using 72 logical ppi to display pictures on the screen, e.g. Adobe applications.

Graphics applications such as ACDSee, Adobe Photoshop, CorelDRAW, simply ignores Units, Xdensity and Ydensity members when displaying JPG files on the screen, but graphics applications consider the value of those members when printing JPG files if they exist. In case, a JPG file does not have Units, Xdensity and Ydensity members, graphics applications use their custom default values (usually 150 dpi) to print the JPG file.

So, for the question about a Delphi code that can read all JPEG header files, the answer is simple, just read JPG file header information; in case the optional members did not exist in a file, just ignore the optional members or tell end-users that they were currently not specified in the file.

Further Reading on DPI and PPI confusions

References on JPEG File Format Specification

孤独难免 2024-10-05 09:38:54

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

FPC 也包括这个包裹。

J. Nommsi 的原始站点已消失,但该软件包仍然可用,例如来自

There is a TP/TPW/Delphi (1-4, but will probably work till unicode versions without big mods) package, pasjp(e)g that can read most of the older JPG types (but not e.g. JPEG2000)

FPC also includes this package.

The original site from J. Nommsi has disappeared, but the package is still available, e.g. from

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文