14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"""Recognize image file formats based on their first few bytes."""
24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm__all__ = ["what"]
44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#-------------------------#
64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Recognize image headers #
74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#-------------------------#
84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef what(file, h=None):
104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h is None:
114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if isinstance(file, basestring):
124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            f = open(file, 'rb')
134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            h = f.read(32)
144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else:
154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            location = file.tell()
164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            h = file.read(32)
174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            file.seek(location)
184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            f = None
194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else:
204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f = None
214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    try:
224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        for tf in tests:
234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            res = tf(h, f)
244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if res:
254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return res
264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    finally:
274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if f: f.close()
284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return None
294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#---------------------------------#
324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Subroutines per image file type #
334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#---------------------------------#
344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests = []
364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_jpeg(h, f):
384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """JPEG data in JFIF format"""
394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[6:10] == 'JFIF':
404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'jpeg'
414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_jpeg)
434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_exif(h, f):
454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """JPEG data in Exif format"""
464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[6:10] == 'Exif':
474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'jpeg'
484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_exif)
504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_png(h, f):
524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[:8] == "\211PNG\r\n\032\n":
534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'png'
544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_png)
564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_gif(h, f):
584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """GIF ('87 and '89 variants)"""
594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[:6] in ('GIF87a', 'GIF89a'):
604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'gif'
614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_gif)
634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_tiff(h, f):
654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """TIFF (can be in Motorola or Intel byte order)"""
664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[:2] in ('MM', 'II'):
674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'tiff'
684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_tiff)
704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_rgb(h, f):
724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """SGI image library"""
734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[:2] == '\001\332':
744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'rgb'
754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_rgb)
774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_pbm(h, f):
794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """PBM (portable bitmap)"""
804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if len(h) >= 3 and \
814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        h[0] == 'P' and h[1] in '14' and h[2] in ' \t\n\r':
824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'pbm'
834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_pbm)
854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_pgm(h, f):
874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """PGM (portable graymap)"""
884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if len(h) >= 3 and \
894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        h[0] == 'P' and h[1] in '25' and h[2] in ' \t\n\r':
904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'pgm'
914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_pgm)
934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_ppm(h, f):
954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """PPM (portable pixmap)"""
964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if len(h) >= 3 and \
974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        h[0] == 'P' and h[1] in '36' and h[2] in ' \t\n\r':
984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'ppm'
994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_ppm)
1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_rast(h, f):
1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """Sun raster file"""
1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[:4] == '\x59\xA6\x6A\x95':
1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'rast'
1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_rast)
1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_xbm(h, f):
1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """X bitmap (X10 or X11)"""
1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    s = '#define '
1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[:len(s)] == s:
1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'xbm'
1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_xbm)
1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test_bmp(h, f):
1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if h[:2] == 'BM':
1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 'bmp'
1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtests.append(test_bmp)
1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#--------------------#
1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Small test program #
1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#--------------------#
1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef test():
1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    import sys
1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    recursive = 0
1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if sys.argv[1:] and sys.argv[1] == '-r':
1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        del sys.argv[1:2]
1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        recursive = 1
1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    try:
1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if sys.argv[1:]:
1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            testall(sys.argv[1:], recursive, 1)
1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else:
1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            testall(['.'], recursive, 1)
1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    except KeyboardInterrupt:
1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sys.stderr.write('\n[Interrupted]\n')
1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sys.exit(1)
1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef testall(list, recursive, toplevel):
1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    import sys
1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    import os
1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    for filename in list:
1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if os.path.isdir(filename):
1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            print filename + '/:',
1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if recursive or toplevel:
1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                print 'recursing down:'
1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                import glob
1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                names = glob.glob(os.path.join(filename, '*'))
1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                testall(names, recursive, 0)
1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else:
1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                print '*** directory (use -r) ***'
1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else:
1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            print filename + ':',
1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            sys.stdout.flush()
1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            try:
1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                print what(filename)
1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            except IOError:
1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                print '*** not found ***'
162