Skip to content

Conversation

Nadahar
Copy link
Contributor

@Nadahar Nadahar commented Jan 31, 2017

I need to check if the Huffman table used in JPEGs are the "typical" Huffman tables defined in the JPEG standard. Some devices can only display such JPEGs.

I've implemented a small directory and a reader for DHT segments. I was unsure exactly how to "translate" the data to metadata-extractor's tag-based structure, as there are no tags here in reality. A JPEG can have many Huffman tables, although the normal is 4. There can be multiple Huffman tables in one DHT segments, but some implementations write one segment per table.

At first I created one Directory per DHT segment, but that ended up with many Huffman directories with very little information inside for some JPEGs - so I changed it so that there's always just one Huffman directory added to a given Metadata instance and additional tables found are added to this. The tables themselves are stored in the HuffmanTableDirectory instance. They are small, just a few bytes and can be retrieved. ImageIO allows you to specify the Huffman tables to use when writing JPEGs, so this could potentially be usedful. This means that the only TAG I've been able to put at the Directory level is the number of Huffman tables.

An alternative would be to create one HuffmanTableDirectory per Huffman table, and store the tables values and properties as tags. That would mean a lot of HuffmanTableDirectories though, so I figured it was cleaner to hide them away under one Directory.

Sadly I discovered ImageIO's Huffman table class after writing this implementation, so the ImageIO class isn't used, but they are easy to convert. I've noticed that many things implemented in metadata-extractor exists "in parallel" in ImageIO like IIOMetadata for example, so it might be good to be "independent" in that sense. Also, TwelveMonkeys implements their own com.twelvemonkeys.imageio.metadata.Directory (and com.twelvemonkeys.imageio.plugins.jpeg.HuffmanTable) instead of using IIOMetadata to make the confusion complete.

I've also added available() to SequentialReader to make it easier to know if there's more data to read. There's no problem to do this using EOFException, but I try to avoid using exceptions as "control logic".

I also did some very minor changes to JpegSegmentType (mostly comments).

Any feedback, views or thoughts are welcome.

edit: I forgot the most important part: The "typical" Huffman tables from the JPEG standard are hardcoded, so that both each separate HuffmanTable and HuffmanTablesDirectory has isTypical() and isOptimized() methods. This makes it easy to check what kind of Huffman tables a given JPEG has. isTypical and isOptimized are opposites, even though these aren't the most intuitive terms, they come from the JPEG standard itself. The standard basicly presents two scenarios for creating Huffman tables - either by using those embedded in the standard referred to as "typical" or to actually calculate tables suitable to that particular image aka "optimized". The "typical" tables are generated from a statistical average of many images and are there to aid "weak CPU" encoding devices. The trade-off is that the files get a little bit bigger, but this is usually around 5% or so and is often considered "worth it" for cameras etc.

What was never intended by the standard was that some JPEG decoders should also rely on these tables, but the fact is that some implementations do this. To top the crazyness off, both the DCF (Design rule for Camera File system) standard and the DLNA (Digital Living Network Alliance) standard have managed to manifest this flawed implementation in their standards as requirements - meaning that JPEGs can only use these "typical" tables to be compliant.

- Created class HuffmanTablesDirectory
- Created class HuffmanTablesDescriptor
- Created class JpegDhtReader
- Added method SequentialReader.available() to see if there's more to read.
- Did some minor tweaks to JpegSegmentType
@drewnoakes
Copy link
Owner

drewnoakes commented Jan 31, 2017

This looks great. @kwhopper can you take a look? I'm happy to merge.

@Nadahar only feedback would be that you've got some great documentation here on the PR that would be good to have in the Javadoc.

@Nadahar
Copy link
Contributor Author

Nadahar commented Jan 31, 2017

@drewnoakes The explanation about "typical"/"optimized" is in Javadoc on the isTypical() methods. Anything you think is missing from there?

@drewnoakes
Copy link
Owner

My mistake. Very thorough, thanks.

@drewnoakes
Copy link
Owner

I'll merge this now. @kwhopper can provide any feedback at his convenience.

@drewnoakes drewnoakes merged commit 3f863f8 into drewnoakes:master Jan 31, 2017
@Nadahar
Copy link
Contributor Author

Nadahar commented Jan 31, 2017

Cheers 👍

@Nadahar Nadahar deleted the Huffman_Tables branch January 31, 2017 22:04
}

@Nullable
public String getNumerOfTablesDescription()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Method name typo?

Copy link
Contributor Author

@Nadahar Nadahar Jan 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, seems so 😞

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in d691939.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be a test usage for that method as well

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, force pushed a fix to my fix in fb0b62d.

@kwhopper
Copy link
Collaborator

I can't intelligently comment without reading up on the spec, but I'm fine if you're fine. The code seems reasonable. Has it been run through the images repo?

@Nadahar
Copy link
Contributor Author

Nadahar commented Jan 31, 2017

I haven't run it through the repo, it's a huge download.

@drewnoakes
Copy link
Owner

I ran it through the images repo. Seems good. Lots of diffs like this:

diff --git a/jpg/ImageTestSuite/metadata/316be81dfdeeb942e904feb3a77f4f83.jpg.txt b/jpg/ImageTestSuite/metadata/316be81dfdeeb942e904feb3a77f4f83.jpg.txt
index 4820961..ce5bd52 100644
--- a/jpg/ImageTestSuite/metadata/316be81dfdeeb942e904feb3a77f4f83.jpg.txt
+++ b/jpg/ImageTestSuite/metadata/316be81dfdeeb942e904feb3a77f4f83.jpg.txt
@@ -17,12 +17,15 @@ TYPE: JPEG
 [JFIF - 0x000c] Thumbnail Width Pixels = 0
 [JFIF - 0x000d] Thumbnail Height Pixels = 0
 
+[Huffman - 0x0001] Number of Tables = 2 Huffman tables
+
 [File - 0x0001] File Name = 316be81dfdeeb942e904feb3a77f4f83.jpg
 [File - 0x0002] File Size = 49977 bytes
 [File - 0x0003] File Modified Date = <omitted for regression testing as checkout dependent>
 
 - JPEG
 - JFIF
+- Huffman
 - File

@Nadahar
Copy link
Contributor Author

Nadahar commented Jan 31, 2017

The diff snippet you included made me wonder if I made a bug, only 2 Huffman tables sounded strange. I downloaded JPEGsnoop and 316be81dfdeeb942e904feb3a77f4f83.jpg and processed it. This image has in fact 10 Huffman tables.

I think I've found the reason as well. JpegSegmentReader.readSegments() exits when the first SOS segment is reached. The problem is that this particular image is progressive, so it has many SOS segments with DHT segments in-between. Because of this, the remaining DHT segments are never registered. The two DHT segments that are before the first SOS marker is the same two that metadata-extractor finds, and the content is identical to what JPEGsnoop reports.

I'm not sure if this should be changed or not. This problem will only apply to progressive JPEGs and the only alternative is to scan through the whole file. Is collecting the remaining DHTs really worth that?

Here is the JPEGsnoop report for the image:

JPEGsnoop 1.7.5 by Calvin Hass
  http://www.impulseadventure.com/photo/
  -------------------------------------

  Filename: [testObjects\316be81dfdeeb942e904feb3a77f4f83.jpg]
  Filesize: [49977] Bytes

Start Offset: 0x00000000
*** Marker: SOI (xFFD8) ***
  OFFSET: 0x00000000
 
*** Marker: APP0 (xFFE0) ***
  OFFSET: 0x00000002
  Length     = 16
  Identifier = [JFIF]
  version    = [1.1]
  density    = 229 x 229 DPI (dots per inch)
  thumbnail  = 0 x 0
 
*** Marker: DQT (xFFDB) ***
  Define a Quantization Table.
  OFFSET: 0x00000014
  Table length = 131
  ----
  Precision=16 bits
  Destination ID=0 (Luminance)
    DQT, Row #0:  53  37  33  53  80 133 170 203 
    DQT, Row #1:  40  40  47  63  87 193 200 183 
    DQT, Row #2:  47  43  53  80 133 190 230 186 
    DQT, Row #3:  47  57  73  97 170 290 266 206 
    DQT, Row #4:  60  73 123 186 226 363 343 256 
    DQT, Row #5:  80 117 183 213 270 346 376 306 
    DQT, Row #6: 163 213 260 290 343 403 400 336 
    DQT, Row #7: 240 306 316 326 373 333 343 330 
    Approx quality factor = 15.01 (scaling=333.00 variance=1.25)
 
*** Marker: DQT (xFFDB) ***
  Define a Quantization Table.
  OFFSET: 0x00000099
  Table length = 131
  ----
  Precision=16 bits
  Destination ID=1 (Chrominance)
    DQT, Row #0:  57  60  80 157 330 330 330 330 
    DQT, Row #1:  60  70  87 220 330 330 330 330 
    DQT, Row #2:  80  87 186 330 330 330 330 330 
    DQT, Row #3: 157 220 330 330 330 330 330 330 
    DQT, Row #4: 330 330 330 330 330 330 330 330 
    DQT, Row #5: 330 330 330 330 330 330 330 330 
    DQT, Row #6: 330 330 330 330 330 330 330 330 
    DQT, Row #7: 330 330 330 330 330 330 330 330 
    Approx quality factor = 15.00 (scaling=333.41 variance=0.14)
 
*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) ***
  OFFSET: 0x0000011E
  Frame header length = 17
  Precision = 8
  Number of Lines = 1071
  Samples per Line = 1443
  Image Size = 1443 x 1071
  Raw Image Orientation = Landscape
  Number of Img components = 3
    Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y)
    Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb)
    Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr)
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x00000131
  Huffman table length = 25
  ----
  Destination ID = 0
  Class = 0 (DC / Lossless Table)
    Codes of length 01 bits (001 total): 00 
    Codes of length 02 bits (001 total): 01 
    Codes of length 03 bits (001 total): 02 
    Codes of length 04 bits (001 total): 03 
    Codes of length 05 bits (001 total): 04 
    Codes of length 06 bits (001 total): 05 
    Codes of length 07 bits (000 total): 
    Codes of length 08 bits (000 total): 
    Codes of length 09 bits (000 total): 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (000 total): 
    Codes of length 12 bits (000 total): 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 006

 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x0000014C
  Huffman table length = 22
  ----
  Destination ID = 1
  Class = 0 (DC / Lossless Table)
    Codes of length 01 bits (001 total): 00 
    Codes of length 02 bits (001 total): 01 
    Codes of length 03 bits (001 total): 02 
    Codes of length 04 bits (000 total): 
    Codes of length 05 bits (000 total): 
    Codes of length 06 bits (000 total): 
    Codes of length 07 bits (000 total): 
    Codes of length 08 bits (000 total): 
    Codes of length 09 bits (000 total): 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (000 total): 
    Codes of length 12 bits (000 total): 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 003

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x00000164
  Scan header length = 12
  Number of img components = 3
    Component[1]: selector=0x01, table=0(DC),0(AC)
    Component[2]: selector=0x02, table=1(DC),0(AC)
    Component[3]: selector=0x03, table=1(DC),0(AC)
  Spectral selection = 0 .. 0
  Successive approximation = 0x01

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x000028E0
  Huffman table length = 38
  ----
  Destination ID = 0
  Class = 1 (AC Table)
    Codes of length 01 bits (000 total): 
    Codes of length 02 bits (002 total): 00 01 
    Codes of length 03 bits (001 total): 11 
    Codes of length 04 bits (004 total): 02 10 20 30 
    Codes of length 05 bits (003 total): 12 31 40 
    Codes of length 06 bits (000 total): 
    Codes of length 07 bits (003 total): 21 41 50 
    Codes of length 08 bits (001 total): 60 
    Codes of length 09 bits (001 total): 03 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (003 total): 22 32 42 
    Codes of length 12 bits (001 total): 13 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 019

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x00002908
  Scan header length = 8
  Number of img components = 1
    Component[1]: selector=0x01, table=0(DC),0(AC)
  Spectral selection = 1 .. 5
  Successive approximation = 0x02

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x00003D97
  Huffman table length = 29
  ----
  Destination ID = 1
  Class = 1 (AC Table)
    Codes of length 01 bits (001 total): 01 
    Codes of length 02 bits (000 total): 
    Codes of length 03 bits (003 total): 00 10 11 
    Codes of length 04 bits (001 total): 20 
    Codes of length 05 bits (000 total): 
    Codes of length 06 bits (002 total): 30 60 
    Codes of length 07 bits (003 total): 80 90 C0 
    Codes of length 08 bits (000 total): 
    Codes of length 09 bits (000 total): 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (000 total): 
    Codes of length 12 bits (000 total): 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 010

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x00003DB6
  Scan header length = 8
  Number of img components = 1
    Component[1]: selector=0x03, table=0(DC),1(AC)
  Spectral selection = 1 .. 63
  Successive approximation = 0x01

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x00003DE1
  Huffman table length = 28
  ----
  Destination ID = 1
  Class = 1 (AC Table)
    Codes of length 01 bits (001 total): 01 
    Codes of length 02 bits (000 total): 
    Codes of length 03 bits (002 total): 10 11 
    Codes of length 04 bits (003 total): 00 20 60 
    Codes of length 05 bits (000 total): 
    Codes of length 06 bits (003 total): 80 90 C0 
    Codes of length 07 bits (000 total): 
    Codes of length 08 bits (000 total): 
    Codes of length 09 bits (000 total): 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (000 total): 
    Codes of length 12 bits (000 total): 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 009

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x00003DFF
  Scan header length = 8
  Number of img components = 1
    Component[1]: selector=0x02, table=0(DC),1(AC)
  Spectral selection = 1 .. 63
  Successive approximation = 0x01

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x00003E21
  Huffman table length = 23
  ----
  Destination ID = 0
  Class = 1 (AC Table)
    Codes of length 01 bits (001 total): 21 
    Codes of length 02 bits (001 total): D0 
    Codes of length 03 bits (001 total): A0 
    Codes of length 04 bits (001 total): B0 
    Codes of length 05 bits (000 total): 
    Codes of length 06 bits (000 total): 
    Codes of length 07 bits (000 total): 
    Codes of length 08 bits (000 total): 
    Codes of length 09 bits (000 total): 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (000 total): 
    Codes of length 12 bits (000 total): 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 004

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x00003E3A
  Scan header length = 8
  Number of img components = 1
    Component[1]: selector=0x01, table=0(DC),0(AC)
  Spectral selection = 6 .. 63
  Successive approximation = 0x02

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x00003E4C
  Huffman table length = 36
  ----
  Destination ID = 0
  Class = 1 (AC Table)
    Codes of length 01 bits (000 total): 
    Codes of length 02 bits (002 total): 00 01 
    Codes of length 03 bits (002 total): 10 11 
    Codes of length 04 bits (002 total): 21 31 
    Codes of length 05 bits (003 total): 20 30 41 
    Codes of length 06 bits (000 total): 
    Codes of length 07 bits (003 total): 40 50 51 
    Codes of length 08 bits (001 total): 61 
    Codes of length 09 bits (001 total): 60 
    Codes of length 10 bits (001 total): 71 
    Codes of length 11 bits (001 total): 81 
    Codes of length 12 bits (001 total): B1 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 017

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x00003E72
  Scan header length = 8
  Number of img components = 1
    Component[1]: selector=0x01, table=0(DC),0(AC)
  Spectral selection = 1 .. 63
  Successive approximation = 0x21

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x00006325
  Scan header length = 12
  Number of img components = 3
    Component[1]: selector=0x01, table=0(DC),0(AC)
    Component[2]: selector=0x02, table=0(DC),0(AC)
    Component[3]: selector=0x03, table=0(DC),0(AC)
  Spectral selection = 0 .. 0
  Successive approximation = 0x10

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x00007512
  Huffman table length = 30
  ----
  Destination ID = 1
  Class = 1 (AC Table)
    Codes of length 01 bits (000 total): 
    Codes of length 02 bits (003 total): 00 01 11 
    Codes of length 03 bits (000 total): 
    Codes of length 04 bits (003 total): 10 21 60 
    Codes of length 05 bits (001 total): 31 
    Codes of length 06 bits (000 total): 
    Codes of length 07 bits (003 total): 20 41 80 
    Codes of length 08 bits (001 total): C0 
    Codes of length 09 bits (000 total): 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (000 total): 
    Codes of length 12 bits (000 total): 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 011

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x00007532
  Scan header length = 8
  Number of img components = 1
    Component[1]: selector=0x03, table=0(DC),1(AC)
  Spectral selection = 1 .. 63
  Successive approximation = 0x10

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x000075CE
  Huffman table length = 30
  ----
  Destination ID = 1
  Class = 1 (AC Table)
    Codes of length 01 bits (000 total): 
    Codes of length 02 bits (003 total): 00 01 11 
    Codes of length 03 bits (001 total): 10 
    Codes of length 04 bits (000 total): 
    Codes of length 05 bits (003 total): 21 31 60 
    Codes of length 06 bits (001 total): 41 
    Codes of length 07 bits (000 total): 
    Codes of length 08 bits (003 total): 20 80 C0 
    Codes of length 09 bits (000 total): 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (000 total): 
    Codes of length 12 bits (000 total): 
    Codes of length 13 bits (000 total): 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (000 total): 
    Codes of length 16 bits (000 total): 
    Total number of codes: 011

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x000075EE
  Scan header length = 8
  Number of img components = 1
    Component[1]: selector=0x02, table=0(DC),1(AC)
  Spectral selection = 1 .. 63
  Successive approximation = 0x10

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: DHT (Define Huffman Table) (xFFC4) ***
  OFFSET: 0x00007676
  Huffman table length = 43
  ----
  Destination ID = 0
  Class = 1 (AC Table)
    Codes of length 01 bits (001 total): 01 
    Codes of length 02 bits (001 total): 00 
    Codes of length 03 bits (001 total): 11 
    Codes of length 04 bits (000 total): 
    Codes of length 05 bits (002 total): 21 31 
    Codes of length 06 bits (002 total): 10 41 
    Codes of length 07 bits (002 total): 20 51 
    Codes of length 08 bits (002 total): 30 61 
    Codes of length 09 bits (003 total): 40 50 71 
    Codes of length 10 bits (000 total): 
    Codes of length 11 bits (003 total): 60 81 91 
    Codes of length 12 bits (001 total): A1 
    Codes of length 13 bits (001 total): B1 
    Codes of length 14 bits (000 total): 
    Codes of length 15 bits (002 total): C1 D1 
    Codes of length 16 bits (003 total): E1 F0 F1 
    Total number of codes: 024

 
*** Marker: SOS (Start of Scan) (xFFDA) ***
  OFFSET: 0x000076A3
  Scan header length = 8
  Number of img components = 1
    Component[1]: selector=0x01, table=0(DC),0(AC)
  Spectral selection = 1 .. 63
  Successive approximation = 0x10

  NOTE: Scan parsing doesn't support this SOF mode.
 
*** Marker: EOI (End of Image) (xFFD9) ***
  OFFSET: 0x0000C337


*** Searching Compression Signatures ***

  Signature:           0105A3D95D2D36DE9351313E30D8E945
  Signature (Rotated): 013C3A43642D2E8325A76C3818B3C324
  File Offset:         0 bytes
  Chroma subsampling:  2x2
  EXIF Make/Model:     NONE
  EXIF Makernotes:     NONE
  EXIF Software:       NONE

  Searching Compression Signatures: (3347 built-in, 0 user(*) )

          EXIF.Make / Software        EXIF.Model                            Quality           Subsamp Match?
          -------------------------   -----------------------------------   ----------------  --------------
     SW :[IJG Library              ]                                       [015             ]                  

    The following IJG-based editors also match this signature:
     SW :[GIMP                     ]                                       [015             ]                  
     SW :[IrfanView                ]                                       [015             ]                  
     SW :[idImager                 ]                                       [015             ]                  
     SW :[FastStone Image Viewer   ]                                       [015             ]                  
     SW :[NeatImage                ]                                       [015             ]                  
     SW :[Paint.NET                ]                                       [015             ]                  
     SW :[Photomatix               ]                                       [015             ]                  
     SW :[XnView                   ]                                       [015             ]                  

  Based on the analysis of compression characteristics and EXIF metadata:

  ASSESSMENT: Class 1 - Image is processed/edited

  This may be a new software editor for the database.
  If this file is processed, and editor doesn't appear in list above,
  PLEASE ADD TO DATABASE with [Tools->Add Camera to DB]

@drewnoakes
Copy link
Owner

In the .NET project I wrote a newer JPEG reader that shouldn't suffer this problem. It's currently used only in a PowerShell Cmdlet, but with some more review and testing would end up in the current JpegSegmentReader in both .NET and Java versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants