Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting JPEG resolution without decoding the image

Tags:

jpeg

delphi

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

like image 496
Server Overflow Avatar asked Oct 22 '10 23:10

Server Overflow


People also ask

What is JPEG decoding?

JPEG Decoding process. The JPEG decoder takes a JPEG image and converts it to a (uncompressed) bitmap using a decoding method called the baseline decoding process.

Does copying a JPEG reduce quality?

Copying the JPEG file won't affect the quality, only opening it and saving it again will do that. Opening the JPEG and by saving it as a lossless TIFF or DNG file, you will prevent further degradation when working on the file.

How are JPEG images encoded?

JPEG uses a lossy form of compression based on the discrete cosine transform (DCT). This mathematical operation converts each frame/field of the video source from the spatial (2D) domain into the frequency domain (a.k.a. transform domain).


3 Answers

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

like image 95
Taylor Bird Avatar answered Nov 15 '22 10:11

Taylor Bird


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;
like image 40
Arnaud Bouchez Avatar answered Nov 15 '22 09:11

Arnaud Bouchez


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

  • Say No to 72 dpi
  • A few scanning tips

References on JPEG File Format Specification

  • JPEG File Interchange Format File Format Summary
  • JPEG File Interchange Format, v1.02
like image 35
Vantomex Avatar answered Nov 15 '22 09:11

Vantomex