Skip to content

Instantly share code, notes, and snippets.

@Hermann-SW
Created January 25, 2020 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Hermann-SW/27fb7cdb7145c233017491d69ddf9052 to your computer and use it in GitHub Desktop.
Save Hermann-SW/27fb7cdb7145c233017491d69ddf9052 to your computer and use it in GitHub Desktop.
pipeable "file" command replacement for gif/jpeg/png (https://www.raspberrypi.org/forums/viewtopic.php?f=32&t=262967)
#!/usr/bin/env python3
'''
Pipeable "file" command replacement for gif/jpeg/png images.
Outputs three lines (type, width, height), followed by copy of input.
'''
import struct
import sys
def get_image_type_size(fhandle):
'''Determine the image type of fhandle and return its size.
from draco / Fred the Fantastic / Dagh Bunnstad;
imghdr removed and pipe handling added by HermannSW'''
not_ok = False, False, False, False
read_sofar = bytearray()
head = fhandle.peek(24)
if len(head) < 24:
return not_ok
if head[:4] == b'\x89\x50\x4e\x47':
check = struct.unpack('>i', head[4:8])[0]
if check != 0x0d0a1a0a:
return not_ok
width, height = struct.unpack('>ii', head[16:24])
itype = "png"
elif head[:4] == b'\x47\x49\x46\x38':
width, height = struct.unpack('<HH', head[6:10])
itype = "gif"
elif head[:2] == b'\xff\xd8':
try:
# Because of .peek(24) above, no .seek(0) needed. Read 0xff next
size = 2
ftype = 0
while not 0xc0 <= ftype <= 0xcf or ftype in (0xc4, 0xc8, 0xcc):
read_sofar += fhandle.read(size+1)
while read_sofar[-1] == 0xff:
read_sofar += fhandle.read(1)
ftype = read_sofar[-1]
read_sofar += fhandle.read(2)
size = struct.unpack('>H', read_sofar[-2:])[0] - 2
# We are at a SOFn block
read_sofar += fhandle.read(1+4) # Skip `precision' byte.
height, width = struct.unpack('>HH', read_sofar[-4:])
itype = "jpeg"
except Exception: #IGNORE:W0703
return not_ok
else:
return not_ok
return itype, width, height, read_sofar
FROM_FILE = len(sys.argv) > 1 and sys.argv[1] != '-'
FHANDLE = open(sys.argv[1], 'rb') if FROM_FILE else sys.stdin.buffer
RET = get_image_type_size(FHANDLE)
if not RET[0]:
sys.exit()
print(str(RET[0])+'\n'+str(RET[1])+'\n'+str(RET[2]))
sys.stdout.flush()
# sys.exit()
sys.stdout.buffer.write(RET[3])
while True:
BUF = FHANDLE.read(1024)
if BUF:
sys.stdout.buffer.write(BUF)
else:
break
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment