PNG Feature Request: Microsoft PNG Plus

Started by thorsted, January 04, 2024, 05:54:12 PM

Previous topic - Next topic

thorsted

Microsoft PNG Plus is a PNG format used by Picture It! and Digital Image software.
PNG Plus uses a private chunk cpIp which contains a Compound Object (OLE).
Currently Exiftool warns:
Warning: [minor] Text/EXIF chunk(s) found after PNG IDAT (may be ignored by some readers)

Can we add the recognition of the cpIp chunk?

Samples can be found here: https://github.com/thorsted/PRONOM_Research/tree/main/Submissions/PNG%20Plus/Samples

Phil Harvey

The warning isn't related to the PNG Plus information, and doesn't indicate a problem for ExifTool, but there may be problems with other readers.

I can add support for the cpIp chunk, but there isn't much useful information that will be extracted.  For example, this is all I get from one of the samples (the cpIp chunk is FlashPix-format information):

> exiftool DigitalImage10-s01.png -flashpix:all
Comp Obj User Type Len          : 26
Comp Obj User Type              : Quill96 Story Group Class

Here is the -v3 dump of the FlashPix information.  Let me know if there is any of the Unknown information that is useful:

PNG cpIp (131072 bytes):
      df6a: d0 cf 11 e0 a1 b1 1a e1 00 00 00 00 00 00 00 00 [................]
      df7a: 00 00 00 00 00 00 00 00 3e 00 03 00 fe ff 09 00 [........>.......]
      df8a: 06 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 [................]
      df9a: 01 00 00 00 00 00 00 00 00 10 00 00 02 00 00 00 [................]
      dfaa: 01 00 00 00 fe ff ff ff 00 00 00 00 00 00 00 00 [................]
      [snip 130992 bytes]
  Sector size=512
  FAT: Count=2
  DIR: Start=1
  MiniFAT: Mini-sector size=64 Start=2 Count=1 Cutoff=4096
  DIF FAT: Start=4294967294 Count=0
  FAT [1024 bytes]:
  |     0000: fd ff ff ff 04 00 00 00 fe ff ff ff 05 00 00 00 [................]
  |     0010: d7 00 00 00 d8 00 00 00 fd ff ff ff 08 00 00 00 [................]
  |     0020: 09 00 00 00 0a 00 00 00 0b 00 00 00 0c 00 00 00 [................]
  |     0030: 0d 00 00 00 0e 00 00 00 0f 00 00 00 10 00 00 00 [................]
  |     0040: 11 00 00 00 12 00 00 00 13 00 00 00 14 00 00 00 [................]
  |     [snip 944 bytes]
  Mini-FAT [512 bytes]:
  |     0000: 01 00 00 00 02 00 00 00 fe ff ff ff fe ff ff ff [................]
  |     0010: 05 00 00 00 fe ff ff ff 07 00 00 00 fe ff ff ff [................]
  |     0020: fe ff ff ff 0a 00 00 00 0b 00 00 00 0c 00 00 00 [................]
  |     0030: 0d 00 00 00 0e 00 00 00 0f 00 00 00 10 00 00 00 [................]
  |     0040: 11 00 00 00 12 00 00 00 13 00 00 00 14 00 00 00 [................]
  |     [snip 432 bytes]
  Directory [2048 bytes]:
  |     0000: 52 00 6f 00 6f 00 74 00 20 00 45 00 6e 00 74 00 [R.o.o.t. .E.n.t.]
  |     0010: 72 00 79 00 00 00 00 00 00 00 00 00 00 00 00 00 [r.y.............]
  |     0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
  |     0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................]
  |     0040: 16 00 05 00 ff ff ff ff ff ff ff ff 01 00 00 00 [................]
  |     [snip 1968 bytes]
  | + [FPX directory, 2048 bytes]
  | | 0)  Root Entry = .(0 PTYP 7..0 OUTV 8..0 PAFT 2..0 THMS............... ..C!.."..D[snip]
  | |     - Tag 'Root Entry' (Ministream) Type=ROOT Flags=Red Child=1 (5952 bytes):
  | |         0000: 01 00 00 00 00 00 28 30 20 50 54 59 50 20 37 0d [......(0 PTYP 7.]
  | |         0010: 0a 30 20 4f 55 54 56 20 38 0d 0a 30 20 50 41 46 [.0 OUTV 8..0 PAF]
  | |         0020: 54 20 32 0d 0a 30 20 54 48 4d 53 0d 0a 0d 0a 1b [T 2..0 THMS.....]
  | |         0030: 00 f2 04 00 00 00 02 00 00 00 1c 00 f2 04 00 00 [................]
  | |         0040: 00 01 00 00 00 1f 00 04 02 00 00 00 20 00 04 00 [............ ...]
  | |         [snip 5872 bytes]
  | | 1)  DataStore =
  | |     - Tag 'DataStore' Type=STORAGE Flags=Black Left=12 Child=5 (0 bytes):
  | | 2)  Unknown_0x0000 = .(0 PTYP 7..0 OUTV 8..0 PAFT 2..0 THMS............... ..C!..[snip]
  | |     - Tag 0x0000 Type=STREAM Flags=Black (147 bytes):
  | |         0000: 01 00 00 00 00 00 28 30 20 50 54 59 50 20 37 0d [......(0 PTYP 7.]
  | |         0010: 0a 30 20 4f 55 54 56 20 38 0d 0a 30 20 50 41 46 [.0 OUTV 8..0 PAF]
  | |         0020: 54 20 32 0d 0a 30 20 54 48 4d 53 0d 0a 0d 0a 1b [T 2..0 THMS.....]
  | |         0030: 00 f2 04 00 00 00 02 00 00 00 1c 00 f2 04 00 00 [................]
  | |         0040: 00 01 00 00 00 1f 00 04 02 00 00 00 20 00 04 00 [............ ...]
  | |         [snip 67 bytes]
  | | 3)  Unknown_0x0001 = .
  | |     - Tag 0x0001 Type=STREAM Flags=Black Left=2 Right=4 (4 bytes):
  | |         0000: 04 00 00 00                                     [....]
  | | 4)  Unknown_0x0002 = ....C.C.............
  | |     - Tag 0x0002 Type=STREAM Flags=Black (68 bytes):
  | |         0000: 02 00 00 00 1a 00 08 00 00 d8 43 00 00 90 43 1b [..........C...C.]
  | |         0010: 00 f2 0c 00 00 00 03 00 00 00 06 00 00 00 08 00 [................]
  | |         0020: 00 00 1c 00 10 00 00 00 00 00 00 00 00 00 00 00 [................]
  | |         0030: 00 00 00 00 00 1e 00 01 00 1f 00 f2 04 00 00 00 [................]
  | |         0040: 00 00 00 00                                     [....]
  | | 5)  Unknown_0x0003 = ..:..;..C...B<..=.B..Y....@?.;@?...B...B....
  | |     - Tag 0x0003 Type=STREAM Flags=Black Left=3 Right=7 (96 bytes):
  | |         0000: 06 10 00 00 3a 00 04 03 00 00 00 3b 00 10 00 00 [....:......;....]
  | |         0010: 00 00 00 00 00 00 00 00 90 43 ab aa 9a 42 3c 00 [.........C...B<.]
  | |         0020: 04 01 00 00 00 3d 00 04 00 00 00 00 42 00 04 01 [.....=......B...]
  | |         0030: 00 00 00 59 00 04 00 00 00 00 1a 00 18 01 00 40 [...Y...........@]
  | |         0040: 3f 00 00 00 00 00 00 00 00 94 3b 40 3f 1f 85 8f [?.........;@?...]
  | |         0050: 42 cd cc 88 42 1b 00 f2 04 00 00 00 04 00 00 00 [B...B...........]
  | | 6)  Unknown_0x0004 = .
  | |     - Tag 0x0004 Type=STREAM Flags=Black (4 bytes):
  | |         0000: 05 00 00 00                                     [....]
  | | 7)  Unknown_0x0005 = ........PNG.....IHDR.D.>.....=.sRGB.....gAMA....a. cHRMz&...[snip]
  | |     - Tag 0x0005 Type=STREAM Flags=Black Left=6 Right=9 (106423 bytes):
  | |         0000: 00 80 00 00 01 00 00 00 1a 00 f0 a8 9f 01 00 00 [................]
  | |         0010: 00 00 00 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 [....PNG........I]
  | |         0020: 48 44 52 00 00 03 44 00 00 02 3e 08 06 00 00 00 [HDR...D...>.....]
  | |         0030: 9c d7 ca 3d 00 00 00 01 73 52 47 42 00 ae ce 1c [...=....sRGB....]
  | |         0040: e9 00 00 00 04 67 41 4d 41 00 00 b1 8f 0b fc 61 [.....gAMA......a]
  | |         [snip 106343 bytes]
  | | 8)  Unknown_0x0006 = ..:...*..A...B.C.A...B...A...B.c.B...B...B...B.s.B...B.4.B..[snip]
  | |     - Tag 0x0006 Type=STREAM Flags=Black (912 bytes):
  | |         0000: 01 10 00 00 3a 00 f0 f8 02 00 00 2a f6 f0 41 c6 [....:......*..A.]
  | |         0010: de fd 42 b4 43 f5 41 c6 de fd 42 c7 de fd 41 c6 [..B.C.A...B...A.]
  | |         0020: de fd 42 b2 63 05 42 c6 de fd 42 01 d8 0b 42 c6 [..B.c.B...B...B.]
  | |         0030: de fd 42 15 73 14 42 c6 de fd 42 ed 34 1f 42 c6 [..B.s.B...B.4.B.]
  | |         0040: de fd 42 8b 1d 2c 42 c6 de fd 42 64 df 36 42 c6 [..B..,B...Bd.6B.]
  | |         [snip 832 bytes]
  | | 9)  Unknown_0x0007 = .
  | |     - Tag 0x0007 Type=STREAM Flags=Red Left=8 Right=10 (4 bytes):
  | |         0000: 05 00 00 00                                     [....]
  | | 10) Unknown_0x0008 = ..:.H...2B<..C..2B.4.C..2B...C..2BOH Cd.6B.. Cd.6Bc.!C.,;B..[snip]
  | |     - Tag 0x0008 Type=STREAM Flags=Black Right=11 (1578 bytes):
  | |         0000: 01 10 00 00 3a 00 f0 48 05 00 00 da 91 32 42 3c [....:..H.....2B<]
  | |         0010: ab 1e 43 da 91 32 42 ed 34 1f 43 da 91 32 42 9e [..C..2B.4.C..2B.]
  | |         0020: be 1f 43 da 91 32 42 4f 48 20 43 64 df 36 42 01 [..C..2BOH Cd.6B.]
  | |         0030: d2 20 43 64 df 36 42 63 e5 21 43 ee 2c 3b 42 c6 [. Cd.6Bc.!C.,;B.]
  | |         0040: f8 22 43 78 7a 3f 42 28 0c 24 43 01 c8 43 42 3c [."Cxz?B(.$C..CB<]
  | |         [snip 1498 bytes]
  | | 11) Unknown_0x0009 = .
  | |     - Tag 0x0009 Type=STREAM Flags=Red (4 bytes):
  | |         0000: 05 00 00 00                                     [....]
  | | 12) Text =
  | |     - Tag 'Text' Type=STORAGE Flags=Red Child=13 (0 bytes):
  | | 13) CONTENTS = CHNKINK ..............TEXT.TEXT...FDPP.FDPP...FDPC.FDPC...STSH.STS[snip]
  | |     - Tag 'CONTENTS' Type=STREAM Flags=Black Left=14 (2560 bytes):
  | |         0000: 43 48 4e 4b 49 4e 4b 20 04 00 07 00 0c 00 00 03 [CHNKINK ........]
  | |         0010: 00 02 00 00 00 0a 00 00 f8 01 0c 00 ff ff ff ff [................]
  | |         0020: 18 00 54 45 58 54 00 00 01 00 00 00 54 45 58 54 [..TEXT......TEXT]
  | |         0030: 00 02 00 00 12 00 00 00 18 00 46 44 50 50 00 00 [..........FDPP..]
  | |         0040: 01 00 00 00 46 44 50 50 00 04 00 00 00 02 00 00 [....FDPP........]
  | |         [snip 2480 bytes]
  | | 14) CompObj (SubDirectory) -->
  | |     - Tag '\x01CompObj' Type=STREAM Flags=Red (86 bytes):
  | |         0000: 01 00 fe ff 03 0a 00 00 ff ff ff ff 00 00 00 00 [................]
  | |         0010: 00 00 00 00 00 00 00 00 00 00 00 00 1a 00 00 00 [................]
  | |         0020: 51 75 69 6c 6c 39 36 20 53 74 6f 72 79 20 47 72 [Quill96 Story Gr]
  | |         0030: 6f 75 70 20 43 6c 61 73 73 00 ff ff ff ff 01 00 [oup Class.......]
  | |         0040: 00 00 00 00 00 00 f4 39 b2 71 00 00 00 00 00 00 [.......9.q......]
  | |         0050: 00 00 00 00 00 00                               [......]
  | | + [BinaryData directory, 100 bytes]
  | | | CompObjUserTypeLen = 26
  | | | - Tag 0x0000 (4 bytes, int32u[1]):
  | | |     001c: 1a 00 00 00                                     [....]
  | | | CompObjUserType = Quill96 Story Group Class
  | | | - Tag 0x0001 (26 bytes, string[26]):
  | | |     0020: 51 75 69 6c 6c 39 36 20 53 74 6f 72 79 20 47 72 [Quill96 Story Gr]
  | | |     0030: 6f 75 70 20 43 6c 61 73 73 00                   [oup Class.]

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

Neal Krawetz

QuoteLet me know if there is any of the Unknown information that is useful

There are some timestamps and directory names that I find interesting.

$ hfmeta PictureIt10-s01.png | grep -e Directory -e filetime
    <meta field='Directory Chain Start' value='Sector 1 at 0x400' />
    <sector field='Sector 1' defined='0x204' offset='0x400' value='Link to Sector 4 (0xa00), Directory, Start' />
    <sector field='Sector 4' defined='0x210' offset='0xa00' value='Link to Sector 5 (0xc00), Directory' />
    <sector field='Sector 5' defined='0x214' offset='0xc00' value='End of Chain, Directory' />
    <object value='Directory Entry #0: Root Entry' offset='0x400' length='128'>
    <object value='Directory Entry #1: DataStore' offset='0x480' length='128'>
     <meta field='Create Time' filetime='01da387d63c73cc0' value='2023-12-27 04:30:15.69200' />
     <meta field='Modified Time' filetime='01da387d63c73cc0' value='2023-12-27 04:30:15.69200' />
    <object value='Directory Entry #2: 0' offset='0x500' length='128'>
    <object value='Directory Entry #3: 1' offset='0x580' length='128'>
    <object value='Directory Entry #4: 2' offset='0xa00' length='128'>
    <object value='Directory Entry #5: 3' offset='0xa80' length='128'>
    <object value='Directory Entry #6: 4' offset='0xb00' length='128'>
    <object value='Directory Entry #7: Text' offset='0xb80' length='128'>
     <meta field='Create Time' filetime='01da387d63c73cc0' value='2023-12-27 04:30:15.69200' />
     <meta field='Modified Time' filetime='01da387d63c73cc0' value='2023-12-27 04:30:15.69200' />
    <object value='Directory Entry #8: CONTENTS' offset='0xc00' length='128'>
    <object value='Directory Entry #9:  CompObj' offset='0xc80' length='128'>

thorsted

Phil,

I think initially the most important part is knowing it is a PNG Plus file so we know it isn't just a thumbnail PNG and actually contains additional data. I would parse the XML output from ExifTool to identify the file as having the cpIp chunk which would allow me to mange these files differently in my repository. The Quill96 information from the CompObj is semi useful as it is common with Microsoft Works products.

The Adobe Fireworks PNG format at least uses the text chunks to identify themselves, but would probably be useful to know they have additional private tags which contain layers and additional pages.

Phil Harvey

Do you have an Adobe Fireworks sample you can share?  Also, a PNG Plus sample containing more than 2 additional pages would be useful (I may be able to extract these).

You won't get any indication of a cpIp chunk except for the Quill96 information, but I could possibly change the FileType to "PNG Plus" if a cpIp chunk is found if you think that makes sense.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

thorsted

Phil,

Here is a PNG Plus file with 12 pages.
DigitalImage10-s03.png

Filetype to PNG Plus if cpIp is present would be awesome.

Some Adobe Fireworks samples.

Neal Krawetz

Fascinating example. The OLE contains 24 jpeg images that alternate teal and black.