123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- from .BIFFRecords import BiffRecord
- from struct import pack, unpack
- def _size_col(sheet, col):
- return sheet.col_width(col)
- def _size_row(sheet, row):
- return sheet.row_height(row)
- def _position_image(sheet, row_start, col_start, x1, y1, width, height):
- """Calculate the vertices that define the position of the image as required by
- the OBJ record.
- +------------+------------+
- | A | B |
- +-----+------------+------------+
- | |(x1,y1) | |
- | 1 |(A1)._______|______ |
- | | | | |
- | | | | |
- +-----+----| BITMAP |-----+
- | | | | |
- | 2 | |______________. |
- | | | (B2)|
- | | | (x2,y2)|
- +---- +------------+------------+
- Example of a bitmap that covers some of the area from cell A1 to cell B2.
- Based on the width and height of the bitmap we need to calculate 8 vars:
- col_start, row_start, col_end, row_end, x1, y1, x2, y2.
- The width and height of the cells are also variable and have to be taken into
- account.
- The values of col_start and row_start are passed in from the calling
- function. The values of col_end and row_end are calculated by subtracting
- the width and height of the bitmap from the width and height of the
- underlying cells.
- The vertices are expressed as a percentage of the underlying cell width as
- follows (rhs values are in pixels):
- x1 = X / W *1024
- y1 = Y / H *256
- x2 = (X-1) / W *1024
- y2 = (Y-1) / H *256
- Where: X is distance from the left side of the underlying cell
- Y is distance from the top of the underlying cell
- W is the width of the cell
- H is the height of the cell
- Note: the SDK incorrectly states that the height should be expressed as a
- percentage of 1024.
- col_start - Col containing upper left corner of object
- row_start - Row containing top left corner of object
- x1 - Distance to left side of object
- y1 - Distance to top of object
- width - Width of image frame
- height - Height of image frame
- """
-
- while x1 >= _size_col(sheet, col_start):
- x1 -= _size_col(sheet, col_start)
- col_start += 1
-
- while y1 >= _size_row(sheet, row_start):
- y1 -= _size_row(sheet, row_start)
- row_start += 1
-
- row_end = row_start
- col_end = col_start
- width = width + x1 - 1
- height = height + y1 - 1
-
- while (width >= _size_col(sheet, col_end)):
- width -= _size_col(sheet, col_end)
- col_end += 1
-
- while (height >= _size_row(sheet, row_end)):
- height -= _size_row(sheet, row_end)
- row_end += 1
-
-
- if ((_size_col(sheet, col_start) == 0) or (_size_col(sheet, col_end) == 0)
- or (_size_row(sheet, row_start) == 0) or (_size_row(sheet, row_end) == 0)):
- return
-
- x1 = int(float(x1) / _size_col(sheet, col_start) * 1024)
- y1 = int(float(y1) / _size_row(sheet, row_start) * 256)
-
- x2 = int(float(width) / _size_col(sheet, col_end) * 1024)
-
- y2 = int(float(height) / _size_row(sheet, row_end) * 256)
- return (col_start, x1, row_start, y1, col_end, x2, row_end, y2)
- class ObjBmpRecord(BiffRecord):
- _REC_ID = 0x005D
- def __init__(self, row, col, sheet, im_data_bmp, x, y, scale_x, scale_y):
-
- width = im_data_bmp.width * scale_x
- height = im_data_bmp.height * scale_y
-
- coordinates = _position_image(sheet, row, col, x, y, width, height)
-
- col_start, x1, row_start, y1, col_end, x2, row_end, y2 = coordinates
- """Store the OBJ record that precedes an IMDATA record. This could be generalise
- to support other Excel objects.
- """
- cObj = 0x0001
- OT = 0x0008
- id = 0x0001
- grbit = 0x0614
- colL = col_start
- dxL = x1
- rwT = row_start
- dyT = y1
- colR = col_end
- dxR = x2
- rwB = row_end
- dyB = y2
- cbMacro = 0x0000
- Reserved1 = 0x0000
- Reserved2 = 0x0000
- icvBack = 0x09
- icvFore = 0x09
- fls = 0x00
- fAuto = 0x00
- icv = 0x08
- lns = 0xff
- lnw = 0x01
- fAutoB = 0x00
- frs = 0x0000
- cf = 0x0009
- Reserved3 = 0x0000
- cbPictFmla = 0x0000
- Reserved4 = 0x0000
- grbit2 = 0x0001
- Reserved5 = 0x0000
- data = pack("<L", cObj)
- data += pack("<H", OT)
- data += pack("<H", id)
- data += pack("<H", grbit)
- data += pack("<H", colL)
- data += pack("<H", dxL)
- data += pack("<H", rwT)
- data += pack("<H", dyT)
- data += pack("<H", colR)
- data += pack("<H", dxR)
- data += pack("<H", rwB)
- data += pack("<H", dyB)
- data += pack("<H", cbMacro)
- data += pack("<L", Reserved1)
- data += pack("<H", Reserved2)
- data += pack("<B", icvBack)
- data += pack("<B", icvFore)
- data += pack("<B", fls)
- data += pack("<B", fAuto)
- data += pack("<B", icv)
- data += pack("<B", lns)
- data += pack("<B", lnw)
- data += pack("<B", fAutoB)
- data += pack("<H", frs)
- data += pack("<L", cf)
- data += pack("<H", Reserved3)
- data += pack("<H", cbPictFmla)
- data += pack("<H", Reserved4)
- data += pack("<H", grbit2)
- data += pack("<L", Reserved5)
- self._rec_data = data
- def _process_bitmap(bitmap):
- """Convert a 24 bit bitmap into the modified internal format used by Windows.
- This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
- MSDN library.
- """
-
- with open(bitmap, "rb") as fh:
-
- data = fh.read()
- return _process_bitmap_data(data)
- def _process_bitmap_data(data):
-
- if len(data) <= 0x36:
- raise Exception("bitmap doesn't contain enough data.")
-
- if (data[:2] != b"BM"):
- raise Exception("bitmap doesn't appear to to be a valid bitmap image.")
-
- data = data[2:]
-
-
-
- size = unpack("<L", data[:4])[0]
- size -= 0x36
- size += 0x0C
- data = data[4:]
-
- data = data[12:]
-
- width, height = unpack("<LL", data[:8])
- data = data[8:]
- if (width > 0xFFFF):
- raise Exception("bitmap: largest image width supported is 65k.")
- if (height > 0xFFFF):
- raise Exception("bitmap: largest image height supported is 65k.")
-
- planes, bitcount = unpack("<HH", data[:4])
- data = data[4:]
- if (bitcount != 24):
- raise Exception("bitmap isn't a 24bit true color bitmap.")
- if (planes != 1):
- raise Exception("bitmap: only 1 plane supported in bitmap image.")
-
- compression = unpack("<L", data[:4])[0]
- data = data[4:]
- if (compression != 0):
- raise Exception("bitmap: compression not supported in bitmap image.")
-
- data = data[20:]
-
- header = pack("<LHHHH", 0x000c, width, height, 0x01, 0x18)
- data = header + data
- return (width, height, size, data)
- class ImRawDataBmpRecord(BiffRecord):
- _REC_ID = 0x007F
- def __init__(self, data):
- """Insert a 24bit bitmap image in a worksheet. The main record required is
- IMDATA but it must be proceeded by a OBJ record to define its position.
- """
- BiffRecord.__init__(self)
- self.width, self.height, self.size, data = _process_bitmap_data(data)
- self._write_imdata(data)
- def _write_imdata(self, data):
-
- cf = 0x09
- env = 0x01
- lcb = self.size
- self._rec_data = pack("<HHL", cf, env, lcb) + data
- class ImDataBmpRecord(ImRawDataBmpRecord):
- def __init__(self, filename):
- """Insert a 24bit bitmap image in a worksheet. The main record required is
- IMDATA but it must be proceeded by a OBJ record to define its position.
- """
- BiffRecord.__init__(self)
- self.width, self.height, self.size, data = _process_bitmap(filename)
- self._write_imdata(data)
|