Class: ObjBmpRecord

Inherits:
BiffRecord show all
Defined in:
lib/surpass/bitmap.rb

Constant Summary collapse

RECORD_ID =

Record identifier

0x005D

Constants inherited from BiffRecord

BiffRecord::BIFF_LIMIT, BiffRecord::CONTINUE_RECORD_ID

Instance Attribute Summary

Attributes inherited from BiffRecord

#record_data

Instance Method Summary collapse

Methods inherited from BiffRecord

#record_header, #to_biff

Constructor Details

#initialize(row, col, sheet, im_data_bmp, x, y, scale_x, scale_y) ⇒ ObjBmpRecord

Returns a new instance of ObjBmpRecord.



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/surpass/bitmap.rb', line 4

def initialize(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
  
  col_start, x1, row_start, y1, col_end, x2, row_end, y2 = position_image(sheet, row, col, x, y, width, height)
  
  # 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
  
  args = [cobj, ot, id, grbit, coll, dxl, rwt, dyt, colr, dxr, rwb, dyb, cbmacro, reserved1, reserved2, icvback, icvfore, fls, fauto, icv, lns, lnw, fautob, frs, cf, reserved3, cbpictfmla, reserved4, grbit2, reserved5]
  @record_data = args.pack('L v12 L v C8 v L v4 L')
end

Instance Method Details

#position_image(sheet, row_start, col_start, x1, y1, width, height) ⇒ Object

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



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/surpass/bitmap.rb', line 96

def position_image(sheet, row_start, col_start, x1, y1, width, height)
  while x1 >= size_col(sheet, col_start) do
    x1 -= size_col(sheet, col_start)
    col_start += 1
  end
  
  # Adjust start row for offsets that are greater than the row height
  while y1 >= size_row(sheet, row_start) do
    y1 -= size_row(sheet, row_start)
    row_start += 1
  end
  
  # 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)) do
    width -= size_col(sheet, col_end)
    col_end += 1
  end
  
  # Subtract the underlying cell heights to find the end cell of the image
  while (height >= size_row(sheet, row_end)) do
    height -= size_row(sheet, row_end)
    row_end += 1
  end
  
  # Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
  # with zero height or width.
  starts_or_ends_in_hidden_cell = ((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 if starts_or_ends_in_hidden_cell

  # Convert the pixel values to the percentage value expected by Excel
  x1 = (x1.to_f / size_col(sheet, col_start) * 1024).to_i
  y1 = (y1.to_f / size_row(sheet, row_start) * 256).to_i
  # Distance to right side of object
  x2 = (width.to_f / size_col(sheet, col_end) * 1024).to_i
  # Distance to bottom of object
  y2 = (height.to_f / size_row(sheet, row_end) * 256).to_i
  
  [col_start, x1, row_start, y1, col_end, x2, row_end, y2]
end

#size_col(sheet, col) ⇒ Object



142
143
144
# File 'lib/surpass/bitmap.rb', line 142

def size_col(sheet, col)
  sheet.col_width(col)
end

#size_row(sheet, row) ⇒ Object



146
147
148
# File 'lib/surpass/bitmap.rb', line 146

def size_row(sheet, row)
  sheet.row_height(row)
end