Twinside / Juicy.Pixels

Haskell library to load & save pictures
BSD 3-Clause "New" or "Revised" License
238 stars 57 forks source link

PNG metadata reading #176

Closed claudeha closed 4 years ago

claudeha commented 4 years ago

I use JuicyPixels for PNG saving from my program, and ImageMagick to perform image processing. The PNG metadata survives convert test-good.png test-bad.png, but in a form that neither JuicyPixels nor pngmeta can see. exiftool sees it fine. I had a similar issue with my Kalles Fraktaler 2+ fork, in that case I was using libpng. The issue seems to be that the metadata is stored after the image data chunks in the PNG file, rather than before it (as pngmeta expects). It is also stored in a compressed text chunk instead of uncompressed. Some versions of ImageMagick and/or other software may also change the capitalization of the Comment text field name.

I looked into the pngmeta source code, and for earlier libpng versions it had a way to read the later metadata by skipping the image chunks, but that is disabled for current libpng. My workaround in KF2+ is poor: I simply decode the image data using libpng and check again for metadata afterwards: https://code.mathr.co.uk/kalles-fraktaler-2/blob/3f345212aaf802eb3f688996bf6473b48590e46b:/fraktal_sft/png.cpp#l92

I uploaded my images here: https://mathr.co.uk/tmp/JuicyPixels/test-good.png https://mathr.co.uk/tmp/JuicyPixels/test-bad.png

test-good.png was saved by JuicyPixels, I then ran convert test-good.png test-bad.png.

Hopefully JuicyPixels can implement a more sensible solution, I haven't looked into it yet.

$ pngmeta test-good.png 
pngmeta: PNG metadata for test-good.png:
Comment: Formula
 z:=(|x|+iy)^p+c
 z:=((-|x|)+i(-y))^p+c
 z:=((-y)+i(-|x|))^p+c
 z:=((-y)+i(-x))^p+c

p=4
q=2
d=1.0
e=0.0
a=-0.13475178720234470000000001
b=0.69087070069208289999999996
r=4.6566128730773926e-10
t=(1.0,0.0,0.0,1.0)
n=4096

de=0.25

Software: et-0
$ pngmeta test-bad.png 
pngmeta: PNG metadata for test-bad.png:
$ exiftool test-good.png 
ExifTool Version Number         : 11.16
File Name                       : test-good.png
Directory                       : .
File Size                       : 351 bytes
File Modification Date/Time     : 2019:07:17 18:05:38+01:00
File Access Date/Time           : 2019:07:17 18:05:48+01:00
File Inode Change Date/Time     : 2019:07:17 18:05:38+01:00
File Permissions                : rw-r--r--
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 1
Image Height                    : 1
Bit Depth                       : 8
Color Type                      : RGB
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Comment                         : Formula. z:=(|x|+iy)^p+c. z:=((-|x|)+i(-y))^p+c. z:=((-y)+i(-|x|))^p+c. z:=((-y)+i(-x))^p+c..p=4.q=2.d=1.0.e=0.0.a=-0.13475178720234470000000001.b=0.69087070069208289999999996.r=4.6566128730773926e-10.t=(1.0,0.0,0.0,1.0).n=4096..de=0.25.
Software                        : et-0
Image Size                      : 1x1
Megapixels                      : 0.000001
$ exiftool test-bad.png 
ExifTool Version Number         : 11.16
File Name                       : test-bad.png
Directory                       : .
File Size                       : 464 bytes
File Modification Date/Time     : 2019:07:17 18:05:48+01:00
File Access Date/Time           : 2019:07:17 18:05:56+01:00
File Inode Change Date/Time     : 2019:07:17 18:05:48+01:00
File Permissions                : rw-r--r--
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 1
Image Height                    : 1
Bit Depth                       : 1
Color Type                      : Grayscale
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Gamma                           : 2.2
White Point X                   : 0.3127
White Point Y                   : 0.329
Red X                           : 0.64
Red Y                           : 0.33
Green X                         : 0.3
Green Y                         : 0.6
Blue X                          : 0.15
Blue Y                          : 0.06
Background Color                : 1
Modify Date                     : 2019:07:17 19:05:38
Comment                         : Formula. z:=(|x|+iy)^p+c. z:=((-|x|)+i(-y))^p+c. z:=((-y)+i(-|x|))^p+c. z:=((-y)+i(-x))^p+c..p=4.q=2.d=1.0.e=0.0.a=-0.13475178720234470000000001.b=0.69087070069208289999999996.r=4.6566128730773926e-10.t=(1.0,0.0,0.0,1.0).n=4096..de=0.25.
Datecreate                      : 2019-07-17T18:05:38+01:00
Datemodify                      : 2019-07-17T18:05:38+01:00
Software                        : et-0
Image Size                      : 1x1
Megapixels                      : 0.000001
$ hd test-good.png 
00000000  89 50 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52  |.PNG........IHDR|
00000010  00 00 00 01 00 00 00 01  08 02 00 00 00 90 77 53  |..............wS|
00000020  de 00 00 00 f5 74 45 58  74 43 6f 6d 6d 65 6e 74  |.....tEXtComment|
00000030  00 46 6f 72 6d 75 6c 61  0a 20 7a 3a 3d 28 7c 78  |.Formula. z:=(|x|
00000040  7c 2b 69 79 29 5e 70 2b  63 0a 20 7a 3a 3d 28 28  ||+iy)^p+c. z:=((|
00000050  2d 7c 78 7c 29 2b 69 28  2d 79 29 29 5e 70 2b 63  |-|x|)+i(-y))^p+c|
00000060  0a 20 7a 3a 3d 28 28 2d  79 29 2b 69 28 2d 7c 78  |. z:=((-y)+i(-|x|
00000070  7c 29 29 5e 70 2b 63 0a  20 7a 3a 3d 28 28 2d 79  ||))^p+c. z:=((-y|
00000080  29 2b 69 28 2d 78 29 29  5e 70 2b 63 0a 0a 70 3d  |)+i(-x))^p+c..p=|
00000090  34 0a 71 3d 32 0a 64 3d  31 2e 30 0a 65 3d 30 2e  |4.q=2.d=1.0.e=0.|
000000a0  30 0a 61 3d 2d 30 2e 31  33 34 37 35 31 37 38 37  |0.a=-0.134751787|
000000b0  32 30 32 33 34 34 37 30  30 30 30 30 30 30 30 30  |2023447000000000|
000000c0  31 0a 62 3d 30 2e 36 39  30 38 37 30 37 30 30 36  |1.b=0.6908707006|
000000d0  39 32 30 38 32 38 39 39  39 39 39 39 39 39 39 36  |9208289999999996|
000000e0  0a 72 3d 34 2e 36 35 36  36 31 32 38 37 33 30 37  |.r=4.65661287307|
000000f0  37 33 39 32 36 65 2d 31  30 0a 74 3d 28 31 2e 30  |73926e-10.t=(1.0|
00000100  2c 30 2e 30 2c 30 2e 30  2c 31 2e 30 29 0a 6e 3d  |,0.0,0.0,1.0).n=|
00000110  34 30 39 36 0a 0a 64 65  3d 30 2e 32 35 0a e8 b5  |4096..de=0.25...|
00000120  f8 97 00 00 00 0d 74 45  58 74 53 6f 66 74 77 61  |......tEXtSoftwa|
00000130  72 65 00 65 74 2d 30 63  5c 0a 75 00 00 00 0c 49  |re.et-0c\.u....I|
00000140  44 41 54 78 9c 63 60 60  60 00 00 00 04 00 01 f6  |DATx.c```.......|
00000150  17 38 55 00 00 00 00 49  45 4e 44 ae 42 60 82     |.8U....IEND.B`.|
0000015f
$ hd test-bad.png 
00000000  89 50 4e 47 0d 0a 1a 0a  00 00 00 0d 49 48 44 52  |.PNG........IHDR|
00000010  00 00 00 01 00 00 00 01  01 00 00 00 00 37 6e f9  |.............7n.|
00000020  24 00 00 00 04 67 41 4d  41 00 00 b1 8f 0b fc 61  |$....gAMA......a|
00000030  05 00 00 00 20 63 48 52  4d 00 00 7a 26 00 00 80  |.... cHRM..z&...|
00000040  84 00 00 fa 00 00 00 80  e8 00 00 75 30 00 00 ea  |...........u0...|
00000050  60 00 00 3a 98 00 00 17  70 9c ba 51 3c 00 00 00  |`..:....p..Q<...|
00000060  02 62 4b 47 44 00 01 dd  8a 13 a4 00 00 00 07 74  |.bKGD..........t|
00000070  49 4d 45 07 e3 07 11 13  05 26 b7 9b 43 f7 00 00  |IME......&..C...|
00000080  00 0a 49 44 41 54 08 d7  63 60 00 00 00 02 00 01  |..IDAT..c`......|
00000090  e2 21 bc 33 00 00 00 a9  7a 54 58 74 43 6f 6d 6d  |.!.3....zTXtComm|
000000a0  65 6e 74 00 00 08 99 6d  cd cd 0a c2 30 0c 00 e0  |ent....m....0...|
000000b0  7b 9e c2 e3 ca ec 48 d3  ae 69 85 5c 7d 0c 61 ba  |{.....H..i.\}.a.|
000000c0  1d 06 fe cc a1 b0 c9 1e  de 4e b7 83 60 20 21 7c  |.........N..` !||
000000d0  49 c8 fe d6 5f 9e e7 0a  36 af 9d 64 d3 30 e5 ed  |I..._...6..d.0..|
000000e0  a8 0e 5d 7e fa 42 a6 13  a9 bc cd f4 a8 7e 78 fc  |..]~.B.......~x.|
000000f0  e0 3c fc c3 c3 82 d0 89  83 bb 10 d4 62 0a 84 46  |.<..........b..F|
00000100  30 d5 4a 34 16 c6 3a 2e  0d 07 26 24 eb 1c e3 1a  |0.J4..:...&$....|
00000110  06 8e 69 cb 47 0c 8c 49  7d 24 0c 14 e2 1a 1e 7a  |..i.G..I}$.....z|
00000120  71 85 2f bd 37 14 d8 22  b3 8d e4 1b 6d 10 1e 92  |q./.7.."....m...|
00000130  a5 27 5b 5c 32 f5 0a ae  e2 30 dd 40 3d bf a6 12  |.'[\2....0.@=...|
00000140  de 35 ef 37 ac d8 a4 d3  36 00 00 00 25 74 45 58  |.5.7....6...%tEX|
00000150  74 64 61 74 65 3a 63 72  65 61 74 65 00 32 30 31  |tdate:create.201|
00000160  39 2d 30 37 2d 31 37 54  31 38 3a 30 35 3a 33 38  |9-07-17T18:05:38|
00000170  2b 30 31 3a 30 30 c0 8a  72 cc 00 00 00 25 74 45  |+01:00..r....%tE|
00000180  58 74 64 61 74 65 3a 6d  6f 64 69 66 79 00 32 30  |Xtdate:modify.20|
00000190  31 39 2d 30 37 2d 31 37  54 31 38 3a 30 35 3a 33  |19-07-17T18:05:3|
000001a0  38 2b 30 31 3a 30 30 b1  d7 ca 70 00 00 00 0d 74  |8+01:00...p....t|
000001b0  45 58 74 53 6f 66 74 77  61 72 65 00 65 74 2d 30  |EXtSoftware.et-0|
000001c0  63 5c 0a 75 00 00 00 00  49 45 4e 44 ae 42 60 82  |c\.u....IEND.B`.|
000001d0

Versions:

pngmeta 1.11 (built with libpng 1.6.34 and zlib 1.2.8)
libimage-exiftool-perl/stable,stable,now 11.16-1 all [installed,automatic]
ghc-8.6.5
JuicyPixels-3.3.3.1
claudeha commented 4 years ago

I think it is simply that zTXt is currently not supported/decoded:

https://github.com/Twinside/Juicy.Pixels/blob/305b5021172b6307244c77984154f802a62765a5/src/Codec/Picture/Png/Internal/Metadata.hs#L95-L97