PNGファイルは、最初の8バイトを除けば
チャンク
データ長 | 名称 | データ | CRC-32 |
---|---|---|---|
4バイト | 4バイト | (データ長に示すバイト数) | 4バイト |
で構成されているので1、
parse_png.sh
#!/bin/bash
set -eu
pngFile=$1
headPtr=0
if [ "89504E470D0A1A0A" != $(xxd -ps -u -s $headPtr -l 8 $pngFile) ]
then
echo "pngファイルではありません"
exit 1
fi
headPtr=$((headPtr+8))
chunkName=""
while [ "IEND" != "$chunkName" ]
do
chunkLength=$((0x$(xxd -ps -u -s $headPtr -l 4 $pngFile)))
chunkName=$(dd if=$pngFile ibs=1 skip=$((headPtr+4)) count=4 2> /dev/null)
checkSum=$(xxd -ps -u -s $((headPtr+4+4+chunkLength)) -l 4 $pngFile)
printf "%04x: %s %04x\n" $headPtr $chunkName $chunkLength
recount=$(printf "%08X" 0x$(dd if=$pngFile ibs=1 skip=$((headPtr+4)) count=$((4+chunkLength)) 2> /dev/null | cksum -o3 | cut -d " " -f 1 | xargs -I ZZ dc -e "16oAi ZZ p"))
if [ "$recount" != "$checkSum" ]
then
echo "ファイルが壊れています"
echo $recount is not equal to $checkSum
fi
headPtr=$((headPtr+4+4+chunkLength+4)) #to next chunk
done
https://gist.github.com/nyango/6cd8441edc16c060763a
などと書いてやれば(pngファイルは必ずIENDという名前のチャンクで終わる)、
$ bash parse_png.sh hoge.png
0008: IHDR 000d
0021: pHYs 0009
0036: vpAg 0009
004b: IDAT 8000
8057: IDAT 68e7
e94a: tEXt 0025
e97b: tEXt 0025
e9ac: IEND 0000
pngを構成するチャンクの名称(4文字の英字)とデータ長(バイト数)を確認できる。