%PDF- %PDF-
| Direktori : /lib/calibre/calibre/utils/wmf/ |
| Current File : //lib/calibre/calibre/utils/wmf/emf.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
import sys
from struct import unpack_from
from collections import namedtuple
from calibre.utils.wmf import create_bmp_from_dib, to_png
from polyglot.builtins import iteritems
# Record types {{{
# See: http://msdn.microsoft.com/en-us/library/cc231166.aspx
RECORD_TYPES = {
'EMR_BITBLT' : 0x4C,
'EMR_STRETCHBLT' : 0x4D,
'EMR_MASKBLT' : 0x4E,
'EMR_PLGBLT' : 0x4F,
'EMR_SETDIBITSTODEVICE' : 0x50,
'EMR_STRETCHDIBITS' : 0x51,
'EMR_ALPHABLEND' : 0x72,
'EMR_TRANSPARENTBLT' : 0x74,
'EOF' : 0xe,
'HEADER' : 0x1,
}
RECORD_RMAP = {v:k for k, v in iteritems(RECORD_TYPES)}
# See http://msdn.microsoft.com/en-us/library/cc230601.aspx
StretchDiBits = namedtuple(
'StretchDiBits', 'left top right bottom x_dest y_dest x_src y_src cx_src'
' cy_src bmp_hdr_offset bmp_header_size bmp_bits_offset'
' bmp_bits_size usage op dest_width dest_height')
# }}}
class EMF:
def __init__(self, raw, verbose=0):
self.pos = 0
self.found_eof = False
self.verbose = verbose
self.func_map = {v:getattr(self, 'handle_%s' % (k.replace('EMR_', '').lower()), self.handle_unknown) for k, v in iteritems(RECORD_TYPES)}
self.bitmaps = []
while self.pos < len(raw) and not self.found_eof:
self.read_record(raw)
self.has_raster_image = bool(self.bitmaps)
def handle_unknown(self, rtype, size, raw):
if self.verbose:
print('Ignoring unknown record:', RECORD_RMAP.get(rtype, hex(rtype).upper()))
def handle_header(self, rtype, size, raw):
pass
def handle_stretchdibits(self, rtype, size, raw):
data = StretchDiBits(*unpack_from(b'<18I', raw, 8))
hdr = raw[data.bmp_hdr_offset:data.bmp_hdr_offset + data.bmp_header_size]
bits = raw[data.bmp_bits_offset:data.bmp_bits_offset + data.bmp_bits_size]
bmp = create_bmp_from_dib(hdr + bits)
self.bitmaps.append(bmp)
def handle_eof(self, rtype, size, raw):
self.found_eof = True
def read_record(self, raw):
rtype, size = unpack_from(b'<II', raw, self.pos)
record = raw[self.pos:self.pos+size]
self.pos += size
self.func_map.get(rtype, self.handle_unknown)(rtype, size, record)
def to_png(self):
bmps = list(sorted(self.bitmaps, key=lambda x: len(x)))
bmp = bmps[-1]
return to_png(bmp)
def emf_unwrap(raw, verbose=0):
'''
Return the largest embedded raster image in the EMF.
The returned data is in PNG format.
'''
w = EMF(raw, verbose=verbose)
if not w.has_raster_image:
raise ValueError('No raster image found in the EMF')
return w.to_png()
if __name__ == '__main__':
with open(sys.argv[-1], 'rb') as f:
raw = f.read()
emf = EMF(raw, verbose=4)
open('/t/test.bmp', 'wb').write(emf.bitmaps[0])
open('/t/test.png', 'wb').write(emf.to_png())