# -*- coding: windows-1251 -*- # Portions are Copyright (C) 2005 Roman V. Kiseliov # Portions are Copyright (c) 2004 Evgeny Filatov # Portions are Copyright (c) 2002-2004 John McNamara (Perl Spreadsheet::WriteExcel) 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 """ # Adjust start column for offsets that are greater than the col width while x1 >= _size_col(sheet, col_start): x1 -= _size_col(sheet, col_start) col_start += 1 # Adjust start row for offsets that are greater than the row height while y1 >= _size_row(sheet, row_start): y1 -= _size_row(sheet, row_start) row_start += 1 # Initialise end cell to the same as the start cell row_end = row_start # Row containing bottom right corner of object col_end = col_start # Col containing lower right corner of object width = width + x1 - 1 height = height + y1 - 1 # Subtract the underlying cell widths to find the end cell of the image while (width >= _size_col(sheet, col_end)): width -= _size_col(sheet, col_end) col_end += 1 # Subtract the underlying cell heights to find the end cell of the image while (height >= _size_row(sheet, row_end)): height -= _size_row(sheet, row_end) row_end += 1 # Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell # with zero height or width. 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 # Convert the pixel values to the percentage value expected by Excel x1 = int(float(x1) / _size_col(sheet, col_start) * 1024) y1 = int(float(y1) / _size_row(sheet, row_start) * 256) # Distance to right side of object x2 = int(float(width) / _size_col(sheet, col_end) * 1024) # Distance to bottom of object 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 # Record identifier def __init__(self, row, col, sheet, im_data_bmp, x, y, scale_x, scale_y): # Scale the frame of the image. width = im_data_bmp.width * scale_x height = im_data_bmp.height * scale_y # Calculate the vertices of the image and write the OBJ record coordinates = _position_image(sheet, row, col, x, y, width, height) # print coordinates 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 # Count of objects in file (set to 1) OT = 0x0008 # Object type. 8 = Picture id = 0x0001 # Object ID grbit = 0x0614 # Option flags colL = col_start # Col containing upper left corner of object dxL = x1 # Distance from left side of cell rwT = row_start # Row containing top left corner of object dyT = y1 # Distance from top of cell colR = col_end # Col containing lower right corner of object dxR = x2 # Distance from right of cell rwB = row_end # Row containing bottom right corner of object dyB = y2 # Distance from bottom of cell cbMacro = 0x0000 # Length of FMLA structure Reserved1 = 0x0000 # Reserved Reserved2 = 0x0000 # Reserved icvBack = 0x09 # Background colour icvFore = 0x09 # Foreground colour fls = 0x00 # Fill pattern fAuto = 0x00 # Automatic fill icv = 0x08 # Line colour lns = 0xff # Line style lnw = 0x01 # Line weight fAutoB = 0x00 # Automatic border frs = 0x0000 # Frame style cf = 0x0009 # Image format, 9 = bitmap Reserved3 = 0x0000 # Reserved cbPictFmla = 0x0000 # Length of FMLA structure Reserved4 = 0x0000 # Reserved grbit2 = 0x0001 # Option flags Reserved5 = 0x0000 # Reserved data = pack(" 0xFFFF): raise Exception("bitmap: largest image width supported is 65k.") if (height > 0xFFFF): raise Exception("bitmap: largest image height supported is 65k.") # Read and remove the bitmap planes and bpp data. Verify them. planes, bitcount = unpack("