write_xlsx 0.78.0 → 0.79.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changes +7 -0
- data/README.md +1 -1
- data/examples/chart_pie.rb +1 -1
- data/lib/write_xlsx/drawing.rb +1 -1
- data/lib/write_xlsx/package/vml.rb +194 -7
- data/lib/write_xlsx/sheets.rb +38 -5
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +150 -55
- data/lib/write_xlsx/worksheet/page_setup.rb +5 -2
- data/lib/write_xlsx/worksheet.rb +136 -11
- data/test/helper.rb +1 -1
- data/test/perl_output/demo.xlsx +0 -0
- data/test/regression/images/black_150.jpg +0 -0
- data/test/regression/images/black_150.png +0 -0
- data/test/regression/images/black_150e.png +0 -0
- data/test/regression/images/black_300.jpg +0 -0
- data/test/regression/images/black_300.png +0 -0
- data/test/regression/images/black_300e.png +0 -0
- data/test/regression/images/black_72.jpg +0 -0
- data/test/regression/images/black_72.png +0 -0
- data/test/regression/images/black_72e.png +0 -0
- data/test/regression/images/black_96.jpg +0 -0
- data/test/regression/images/black_96.png +0 -0
- data/test/regression/test_chart_scatter15.rb +44 -0
- data/test/regression/test_header01.rb +28 -0
- data/test/regression/test_header02.rb +28 -0
- data/test/regression/test_header03.rb +31 -0
- data/test/regression/test_header_image01.rb +26 -0
- data/test/regression/test_header_image02.rb +33 -0
- data/test/regression/test_header_image03.rb +34 -0
- data/test/regression/test_header_image04.rb +34 -0
- data/test/regression/test_header_image05.rb +28 -0
- data/test/regression/test_header_image06.rb +32 -0
- data/test/regression/test_header_image07.rb +29 -0
- data/test/regression/test_header_image08.rb +33 -0
- data/test/regression/test_header_image09.rb +36 -0
- data/test/regression/test_header_image10.rb +36 -0
- data/test/regression/test_header_image11.rb +28 -0
- data/test/regression/test_header_image12.rb +28 -0
- data/test/regression/test_header_image13.rb +36 -0
- data/test/regression/test_header_image14.rb +36 -0
- data/test/regression/test_image22.rb +24 -0
- data/test/regression/test_image23.rb +30 -0
- data/test/regression/test_image24.rb +24 -0
- data/test/regression/test_image25.rb +24 -0
- data/test/regression/test_image26.rb +30 -0
- data/test/regression/test_image27.rb +24 -0
- data/test/regression/xlsx_files/chart_scatter15.xlsx +0 -0
- data/test/regression/xlsx_files/header01.xlsx +0 -0
- data/test/regression/xlsx_files/header02.xlsx +0 -0
- data/test/regression/xlsx_files/header03.xlsx +0 -0
- data/test/regression/xlsx_files/header_image01.xlsx +0 -0
- data/test/regression/xlsx_files/header_image02.xlsx +0 -0
- data/test/regression/xlsx_files/header_image03.xlsx +0 -0
- data/test/regression/xlsx_files/header_image04.xlsx +0 -0
- data/test/regression/xlsx_files/header_image05.xlsx +0 -0
- data/test/regression/xlsx_files/header_image06.xlsx +0 -0
- data/test/regression/xlsx_files/header_image07.xlsx +0 -0
- data/test/regression/xlsx_files/header_image08.xlsx +0 -0
- data/test/regression/xlsx_files/header_image09.xlsx +0 -0
- data/test/regression/xlsx_files/header_image10.xlsx +0 -0
- data/test/regression/xlsx_files/header_image11.xlsx +0 -0
- data/test/regression/xlsx_files/header_image12.xlsx +0 -0
- data/test/regression/xlsx_files/header_image13.xlsx +0 -0
- data/test/regression/xlsx_files/header_image14.xlsx +0 -0
- data/test/regression/xlsx_files/image22.xlsx +0 -0
- data/test/regression/xlsx_files/image23.xlsx +0 -0
- data/test/regression/xlsx_files/image24.xlsx +0 -0
- data/test/regression/xlsx_files/image25.xlsx +0 -0
- data/test/regression/xlsx_files/image26.xlsx +0 -0
- data/test/regression/xlsx_files/image27.xlsx +0 -0
- metadata +119 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e671b68b1de5d627fc5e2306b17a157dd669ac0b
|
4
|
+
data.tar.gz: 9a33233b791e917331d2714bfa1212789ff7d515
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b218047dedb38eb475c41a3dda88d3eefca2d185ea34af3270f6d5ca9ebb884f1e81d3b8f893b16cbb84930fda41f28b2a62c926d2a58b9754c2c0e296204ce
|
7
|
+
data.tar.gz: d9ea75c34d0510b98d1a9a985fabbe3bcd62a73b8f31eba6b9d334313d1f94e29ffe6392dda2bc12cc84e1d4a778ace0e8ddff6afe530a5c5eb3661aeaa7ef07
|
data/Changes
CHANGED
@@ -1,4 +1,11 @@
|
|
1
1
|
Change history of write_xlsx rubygem.
|
2
|
+
2014-11-29 v0.79.0
|
3
|
+
Added option to add images to headers and footers.
|
4
|
+
Added option to not scale heaader/footer with page.
|
5
|
+
Fixed issue where non 96dpi images weren’t scaled properly in Excel.
|
6
|
+
Fix for issue where X axis title formula was overwritten by the
|
7
|
+
Y axis title.
|
8
|
+
|
2
9
|
2014-11-22 v0.78.0
|
3
10
|
Added Doughnut chart with set_rotation and set_hole_size methods.
|
4
11
|
Added set_rotation method to Pie charts.
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
gem to create a new file in the Excel 2007+ XLSX format, and you can use the
|
6
6
|
same interface as writeexcel gem. write_xlsx is converted from Perl's module
|
7
|
-
[Excel::Writer::XLSX-0.
|
7
|
+
[Excel::Writer::XLSX-0.79](https://github.com/jmcnamara/excel-writer-xlsx) .
|
8
8
|
|
9
9
|
## Description
|
10
10
|
|
data/examples/chart_pie.rb
CHANGED
@@ -60,7 +60,7 @@ worksheet.insert_chart('C2', chart1, 25, 10)
|
|
60
60
|
# Create an example Pie chart like above.
|
61
61
|
chart2 = workbook.add_chart(:type => 'pie', :embedded => 1)
|
62
62
|
|
63
|
-
# Configure the series
|
63
|
+
# Configure the series.
|
64
64
|
chart2.add_series(
|
65
65
|
:name => 'Pie sales data',
|
66
66
|
:categories => '=Sheet1!$A$2:$A$4',
|
data/lib/write_xlsx/drawing.rb
CHANGED
@@ -86,7 +86,7 @@ module Writexlsx
|
|
86
86
|
@writer.tag_elements('xdr:twoCellAnchor', attributes) do
|
87
87
|
# Write the xdr:from element.
|
88
88
|
write_from(col_from, row_from, col_from_offset, row_from_offset)
|
89
|
-
# Write the xdr:
|
89
|
+
# Write the xdr:to element.
|
90
90
|
write_to(col_to, row_to, col_to_offset, row_to_offset)
|
91
91
|
|
92
92
|
if type == 1
|
@@ -16,30 +16,42 @@ module Writexlsx
|
|
16
16
|
@writer.set_xml_writer(filename)
|
17
17
|
end
|
18
18
|
|
19
|
-
def assemble_xml_file(
|
19
|
+
def assemble_xml_file(
|
20
|
+
data_id, vml_shape_id, comments_data,
|
21
|
+
buttons_data, header_images_data = []
|
22
|
+
)
|
20
23
|
return unless @writer
|
21
24
|
|
22
25
|
write_xml_namespace do
|
23
26
|
# Write the o:shapelayout element.
|
24
|
-
write_shapelayout(
|
27
|
+
write_shapelayout(data_id)
|
25
28
|
|
26
29
|
z_index = 1
|
27
|
-
|
28
|
-
unless worksheet.buttons_data.empty?
|
30
|
+
unless buttons_data.empty?
|
29
31
|
vml_shape_id, z_index =
|
30
32
|
write_shape_type_and_shape(
|
31
|
-
|
33
|
+
buttons_data,
|
32
34
|
vml_shape_id, z_index) do
|
33
35
|
write_button_shapetype
|
34
36
|
end
|
35
37
|
end
|
36
|
-
unless
|
38
|
+
unless comments_data.empty?
|
37
39
|
write_shape_type_and_shape(
|
38
|
-
|
40
|
+
comments_data,
|
39
41
|
vml_shape_id, z_index) do
|
40
42
|
write_comment_shapetype
|
41
43
|
end
|
42
44
|
end
|
45
|
+
unless header_images_data.empty?
|
46
|
+
write_image_shapetype
|
47
|
+
index = 1
|
48
|
+
header_images_data.each do |image|
|
49
|
+
# Write the v:shape element.
|
50
|
+
vml_shape_id += 1
|
51
|
+
write_image_shape(vml_shape_id, index, image)
|
52
|
+
index += 1
|
53
|
+
end
|
54
|
+
end
|
43
55
|
end
|
44
56
|
@writer.crlf
|
45
57
|
@writer.close
|
@@ -144,6 +156,43 @@ module Writexlsx
|
|
144
156
|
end
|
145
157
|
end
|
146
158
|
|
159
|
+
#
|
160
|
+
# Write the <v:shapetype> element.
|
161
|
+
#
|
162
|
+
def write_image_shapetype
|
163
|
+
id = '_x0000_t75'
|
164
|
+
coordsize = '21600,21600'
|
165
|
+
spt = 75
|
166
|
+
o_preferrelative = 't'
|
167
|
+
path = 'm@4@5l@4@11@9@11@9@5xe'
|
168
|
+
filled = 'f'
|
169
|
+
stroked = 'f'
|
170
|
+
|
171
|
+
attributes = [
|
172
|
+
['id', id],
|
173
|
+
['coordsize', coordsize],
|
174
|
+
['o:spt', spt],
|
175
|
+
['o:preferrelative', o_preferrelative],
|
176
|
+
['path', path],
|
177
|
+
['filled', filled],
|
178
|
+
['stroked', stroked]
|
179
|
+
]
|
180
|
+
|
181
|
+
@writer.tag_elements('v:shapetype', attributes) do
|
182
|
+
# Write the v:stroke element.
|
183
|
+
write_stroke
|
184
|
+
|
185
|
+
# Write the v:formulas element.
|
186
|
+
write_formulas
|
187
|
+
|
188
|
+
# Write the v:path element.
|
189
|
+
write_image_path
|
190
|
+
|
191
|
+
# Write the o:lock element.
|
192
|
+
write_aspect_ratio_lock
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
147
196
|
#
|
148
197
|
# Write the <v:path> element.
|
149
198
|
#
|
@@ -158,6 +207,23 @@ module Writexlsx
|
|
158
207
|
@writer.empty_tag('v:path', attributes)
|
159
208
|
end
|
160
209
|
|
210
|
+
#
|
211
|
+
# Write the <v:path> element.
|
212
|
+
#
|
213
|
+
def write_image_path
|
214
|
+
extrusionok = 'f'
|
215
|
+
gradientshapeok = 't'
|
216
|
+
connecttype = 'rect'
|
217
|
+
|
218
|
+
attributes = [
|
219
|
+
['o:extrusionok', extrusionok],
|
220
|
+
['gradientshapeok', gradientshapeok],
|
221
|
+
['o:connecttype', connecttype]
|
222
|
+
]
|
223
|
+
|
224
|
+
@writer.empty_tag('v:path', attributes)
|
225
|
+
end
|
226
|
+
|
161
227
|
#
|
162
228
|
# Write the <o:lock> element.
|
163
229
|
#
|
@@ -168,6 +234,127 @@ module Writexlsx
|
|
168
234
|
]
|
169
235
|
@writer.empty_tag('o:lock', attributes)
|
170
236
|
end
|
237
|
+
|
238
|
+
#
|
239
|
+
# Write the <o:lock> element.
|
240
|
+
#
|
241
|
+
def write_rotation_lock
|
242
|
+
attributes = [
|
243
|
+
['v:ext', 'edit'],
|
244
|
+
['rotation', 't']
|
245
|
+
]
|
246
|
+
@writer.empty_tag('o:lock', attributes)
|
247
|
+
end
|
248
|
+
|
249
|
+
#
|
250
|
+
# Write the <o:lock> element.
|
251
|
+
#
|
252
|
+
def write_aspect_ratio_lock
|
253
|
+
ext = 'edit'
|
254
|
+
aspectratio = 't'
|
255
|
+
|
256
|
+
attributes = [
|
257
|
+
['v:ext', ext],
|
258
|
+
['aspectratio', aspectratio]
|
259
|
+
]
|
260
|
+
|
261
|
+
@writer.empty_tag('o:lock', attributes)
|
262
|
+
end
|
263
|
+
|
264
|
+
#
|
265
|
+
# Write the <v:shape> element.
|
266
|
+
#
|
267
|
+
def write_image_shape(id, index, image_data)
|
268
|
+
type = '#_x0000_t75'
|
269
|
+
|
270
|
+
# Set the shape index.
|
271
|
+
shape_index = "_x0000_s#{id}"
|
272
|
+
|
273
|
+
# Get the image parameters
|
274
|
+
width = image_data[0]
|
275
|
+
height = image_data[1]
|
276
|
+
name = image_data[2]
|
277
|
+
position = image_data[3]
|
278
|
+
x_dpi = image_data[4]
|
279
|
+
y_dpi = image_data[5]
|
280
|
+
|
281
|
+
# Scale the height/width by the resolution, relative to 72dpi.
|
282
|
+
width = width * 72.0 / x_dpi
|
283
|
+
height = height * 72.0 / y_dpi
|
284
|
+
|
285
|
+
# Excel uses a rounding based around 72 and 96 dpi.
|
286
|
+
width = 72/96.0 * (width * 96/72.0 + 0.25).to_i
|
287
|
+
height = 72/96.0 * (height * 96/72.0 + 0.25).to_i
|
288
|
+
|
289
|
+
if (width - width.to_i).abs < 0.1
|
290
|
+
width = width.to_i
|
291
|
+
end
|
292
|
+
if (height - height.to_i).abs < 0.1
|
293
|
+
height = height.to_i
|
294
|
+
end
|
295
|
+
|
296
|
+
style = [
|
297
|
+
"position:absolute", "margin-left:0", "margin-top:0",
|
298
|
+
"width:#{width}pt", "height:#{height}pt",
|
299
|
+
"z-index:#{index}"
|
300
|
+
].join(';')
|
301
|
+
attributes = [
|
302
|
+
['id', position],
|
303
|
+
['o:spid', "_x0000_s#{id}"],
|
304
|
+
['type', type],
|
305
|
+
['style', style]
|
306
|
+
]
|
307
|
+
|
308
|
+
@writer.tag_elements('v:shape', attributes) do
|
309
|
+
# Write the v:imagedata element.
|
310
|
+
write_imagedata(index, name)
|
311
|
+
|
312
|
+
# Write the o:lock element.
|
313
|
+
write_rotation_lock
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
#
|
318
|
+
# Write the <v:imagedata> element.
|
319
|
+
#
|
320
|
+
def write_imagedata(index, o_title)
|
321
|
+
attributes = [
|
322
|
+
['o:relid', "rId#{index}"],
|
323
|
+
['o:title', o_title]
|
324
|
+
]
|
325
|
+
|
326
|
+
@writer.empty_tag('v:imagedata', attributes)
|
327
|
+
end
|
328
|
+
|
329
|
+
#
|
330
|
+
# Write the <v:formulas> element.
|
331
|
+
#
|
332
|
+
def write_formulas
|
333
|
+
@writer.tag_elements('v:formulas') do
|
334
|
+
# Write the v:f elements.
|
335
|
+
write_f('if lineDrawn pixelLineWidth 0')
|
336
|
+
write_f('sum @0 1 0')
|
337
|
+
write_f('sum 0 0 @1')
|
338
|
+
write_f('prod @2 1 2')
|
339
|
+
write_f('prod @3 21600 pixelWidth')
|
340
|
+
write_f('prod @3 21600 pixelHeight')
|
341
|
+
write_f('sum @0 0 1')
|
342
|
+
write_f('prod @6 1 2')
|
343
|
+
write_f('prod @7 21600 pixelWidth')
|
344
|
+
write_f('sum @8 21600 0')
|
345
|
+
write_f('prod @7 21600 pixelHeight')
|
346
|
+
write_f('sum @10 21600 0')
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
#
|
351
|
+
# Write the <v:f> element.
|
352
|
+
#
|
353
|
+
def write_f(eqn)
|
354
|
+
attributes = [ ['eqn', eqn] ]
|
355
|
+
|
356
|
+
@writer.empty_tag('v:f', attributes)
|
357
|
+
end
|
171
358
|
end
|
172
359
|
end
|
173
360
|
end
|
data/lib/write_xlsx/sheets.rb
CHANGED
@@ -58,13 +58,30 @@ module Writexlsx
|
|
58
58
|
|
59
59
|
def write_vml_files(package_dir)
|
60
60
|
dir = "#{package_dir}/xl/drawings"
|
61
|
-
|
62
|
-
|
61
|
+
index = 1
|
62
|
+
self.each do |sheet|
|
63
|
+
next if !sheet.has_vml? and !sheet.has_header_vml?
|
63
64
|
FileUtils.mkdir_p(dir)
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
66
|
+
if sheet.has_vml?
|
67
|
+
vml = Package::Vml.new
|
68
|
+
vml.set_xml_writer("#{dir}/vmlDrawing#{index}.vml")
|
69
|
+
vml.assemble_xml_file(
|
70
|
+
sheet.vml_data_id, sheet.vml_shape_id,
|
71
|
+
sheet.sorted_comments, sheet.buttons_data
|
72
|
+
)
|
73
|
+
index += 1
|
74
|
+
end
|
75
|
+
if sheet.has_header_vml?
|
76
|
+
vml = Package::Vml.new
|
77
|
+
vml.set_xml_writer("#{dir}/vmlDrawing#{index}.vml")
|
78
|
+
vml.assemble_xml_file(
|
79
|
+
sheet.vml_header_id, sheet.vml_header_id * 1024,
|
80
|
+
[], [], sheet.header_images_data
|
81
|
+
)
|
82
|
+
write_vml_drawing_rels_files(package_dir, sheet, index)
|
83
|
+
index += 1
|
84
|
+
end
|
68
85
|
end
|
69
86
|
end
|
70
87
|
|
@@ -125,6 +142,22 @@ module Writexlsx
|
|
125
142
|
end
|
126
143
|
end
|
127
144
|
|
145
|
+
def write_vml_drawing_rels_files(package_dir, worksheet, index)
|
146
|
+
# Create the drawing .rels dir.
|
147
|
+
dir = "#{package_dir}/xl/drawings/_rels"
|
148
|
+
FileUtils.mkdir_p(dir)
|
149
|
+
|
150
|
+
rels = Package::Relationships.new
|
151
|
+
|
152
|
+
worksheet.vml_drawing_links.each do |drawing_data|
|
153
|
+
rels.add_document_relationship(*drawing_data)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Create the .rels file such as /xl/drawings/_rels/vmlDrawing1.vml.rels.
|
157
|
+
rels.set_xml_writer("#{dir}/vmlDrawing#{index}.vml.rels")
|
158
|
+
rels.assemble_xml_file
|
159
|
+
end
|
160
|
+
|
128
161
|
def write_worksheet_rels_files(package_dir)
|
129
162
|
write_sheet_rels_files_base(worksheets, "#{package_dir}/xl/worksheets/_rels",
|
130
163
|
'sheet')
|
data/lib/write_xlsx/version.rb
CHANGED
data/lib/write_xlsx/workbook.rb
CHANGED
@@ -985,7 +985,7 @@ module Writexlsx
|
|
985
985
|
end
|
986
986
|
|
987
987
|
def num_vml_files
|
988
|
-
@worksheets.select { |sheet| sheet.has_vml? }.count
|
988
|
+
@worksheets.select { |sheet| sheet.has_vml? || sheet.has_header_vml? }.count
|
989
989
|
end
|
990
990
|
|
991
991
|
def num_comment_files
|
@@ -1534,18 +1534,32 @@ module Writexlsx
|
|
1534
1534
|
comment_id = 0
|
1535
1535
|
vml_drawing_id = 0
|
1536
1536
|
vml_data_id = 1
|
1537
|
+
vml_header_id = 0
|
1537
1538
|
vml_shape_id = 1024
|
1539
|
+
comment_files = 0
|
1538
1540
|
|
1539
|
-
@worksheets.
|
1540
|
-
|
1541
|
-
|
1541
|
+
@worksheets.each do |sheet|
|
1542
|
+
next if !sheet.has_vml? && !sheet.has_header_vml?
|
1543
|
+
if sheet.has_vml?
|
1544
|
+
if sheet.has_comments?
|
1545
|
+
comment_files += 1
|
1546
|
+
comment_id += 1
|
1547
|
+
end
|
1548
|
+
vml_drawing_id += 1
|
1542
1549
|
|
1543
|
-
|
1544
|
-
|
1550
|
+
sheet.prepare_vml_objects(vml_data_id, vml_shape_id,
|
1551
|
+
vml_drawing_id, comment_id)
|
1545
1552
|
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1553
|
+
# Each VML file should start with a shape id incremented by 1024.
|
1554
|
+
vml_data_id += 1 * ( 1 + sheet.num_comments_block )
|
1555
|
+
vml_shape_id += 1024 * ( 1 + sheet.num_comments_block )
|
1556
|
+
end
|
1557
|
+
|
1558
|
+
if sheet.has_header_vml?
|
1559
|
+
vml_header_id += 1
|
1560
|
+
vml_drawing_id += 1
|
1561
|
+
sheet.prepare_header_vml_objects(vml_header_id, vml_drawing_id)
|
1562
|
+
end
|
1549
1563
|
end
|
1550
1564
|
|
1551
1565
|
add_font_format_for_cell_comments if num_comment_files > 0
|
@@ -1730,27 +1744,69 @@ module Writexlsx
|
|
1730
1744
|
chart_count = sheet.charts.size
|
1731
1745
|
image_count = sheet.images.size
|
1732
1746
|
shape_count = sheet.shapes.size
|
1733
|
-
|
1747
|
+
header_image_count = sheet.header_images.size
|
1748
|
+
footer_image_count = sheet.footer_images.size
|
1749
|
+
has_drawing = false
|
1734
1750
|
|
1735
|
-
|
1751
|
+
# Check that some image or drawing needs to be processed.
|
1752
|
+
next if chart_count + image_count + shape_count + header_image_count + footer_image_count == 0
|
1736
1753
|
|
1754
|
+
# Don't increase the drawing_id header/footer images.
|
1755
|
+
if chart_count + image_count + shape_count > 0
|
1756
|
+
drawing_id += 1
|
1757
|
+
has_drawing = true
|
1758
|
+
end
|
1759
|
+
|
1760
|
+
# Prepare the worksheet charts.
|
1737
1761
|
sheet.charts.each_with_index do |chart, index|
|
1738
1762
|
chart_ref_id += 1
|
1739
1763
|
sheet.prepare_chart(index, chart_ref_id, drawing_id)
|
1740
1764
|
end
|
1741
1765
|
|
1766
|
+
# Prepare the worksheet images.
|
1742
1767
|
sheet.images.each_with_index do |image, index|
|
1743
|
-
|
1768
|
+
type, width, height, name, x_dpi, y_dpi = get_image_properties(image[2])
|
1744
1769
|
image_ref_id += 1
|
1745
|
-
sheet.prepare_image(index, image_ref_id, drawing_id, width, height, name, type)
|
1770
|
+
sheet.prepare_image(index, image_ref_id, drawing_id, width, height, name, type, x_dpi, y_dpi)
|
1746
1771
|
end
|
1747
1772
|
|
1773
|
+
# Prepare the worksheet shapes.
|
1748
1774
|
sheet.shapes.each_with_index do |shape, index|
|
1749
1775
|
sheet.prepare_shape(index, drawing_id)
|
1750
1776
|
end
|
1751
1777
|
|
1752
|
-
|
1753
|
-
|
1778
|
+
# Prepare the header images.
|
1779
|
+
header_image_count.times do |index|
|
1780
|
+
filename = sheet.header_images[index][0]
|
1781
|
+
position = sheet.header_images[index][1]
|
1782
|
+
|
1783
|
+
type, width, height, name, x_dpi, y_dpi =
|
1784
|
+
get_image_properties(filename)
|
1785
|
+
|
1786
|
+
image_ref_id += 1
|
1787
|
+
|
1788
|
+
sheet.prepare_header_image(image_ref_id, width, height,
|
1789
|
+
name, type, position, x_dpi, y_dpi)
|
1790
|
+
end
|
1791
|
+
|
1792
|
+
# Prepare the footer images.
|
1793
|
+
footer_image_count.times do |index|
|
1794
|
+
filename = sheet.footer_images[index][0]
|
1795
|
+
position = sheet.footer_images[index][1]
|
1796
|
+
|
1797
|
+
type, width, height, name, x_dpi, y_dpi =
|
1798
|
+
get_image_properties(filename)
|
1799
|
+
|
1800
|
+
image_ref_id += 1
|
1801
|
+
|
1802
|
+
sheet.prepare_header_image(image_ref_id, width, height,
|
1803
|
+
name, type, position, x_dpi, y_dpi)
|
1804
|
+
end
|
1805
|
+
|
1806
|
+
if has_drawing
|
1807
|
+
drawing = sheet.drawing
|
1808
|
+
@drawings << drawing
|
1809
|
+
end
|
1754
1810
|
end
|
1755
1811
|
|
1756
1812
|
# Sort the workbook charts references into the order that the were
|
@@ -1766,41 +1822,32 @@ module Writexlsx
|
|
1766
1822
|
# any duplicates.
|
1767
1823
|
#
|
1768
1824
|
def get_image_properties(filename)
|
1769
|
-
previous_images
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1825
|
+
# Note the image_id, and previous_images mechanism isn't currently used.
|
1826
|
+
x_dpi = 96
|
1827
|
+
y_dpi = 96
|
1828
|
+
|
1829
|
+
# Open the image file and import the data.
|
1830
|
+
data = File.binread(filename)
|
1831
|
+
if data.unpack('x A3')[0] == 'PNG'
|
1832
|
+
# Test for PNGs.
|
1833
|
+
type, width, height, x_dpi, y_dpi = process_png(data)
|
1834
|
+
@image_types[:png] = 1
|
1835
|
+
elsif data.unpack('n')[0] == 0xFFD8
|
1836
|
+
# Test for JPEG files.
|
1837
|
+
type, width, height, x_dpi, y_dpi = process_jpg(data, filename)
|
1838
|
+
@image_types[:jpeg] = 1
|
1839
|
+
elsif data.unpack('A2')[0] == 'BM'
|
1840
|
+
# Test for BMPs.
|
1841
|
+
type, width, height = process_bmp(data, filename)
|
1842
|
+
@image_types[:bmp] = 1
|
1775
1843
|
else
|
1776
|
-
#
|
1777
|
-
|
1778
|
-
if data.unpack('x A3')[0] == 'PNG'
|
1779
|
-
# Test for PNGs.
|
1780
|
-
type, width, height = process_png(data)
|
1781
|
-
@image_types[:png] = 1
|
1782
|
-
elsif data.unpack('n')[0] == 0xFFD8
|
1783
|
-
# Test for JPEG files.
|
1784
|
-
type, width, height = process_jpg(data, filename)
|
1785
|
-
@image_types[:jpeg] = 1
|
1786
|
-
elsif data.unpack('A2')[0] == 'BM'
|
1787
|
-
# Test for BMPs.
|
1788
|
-
type, width, height = process_bmp(data, filename)
|
1789
|
-
@image_types[:bmp] = 1
|
1790
|
-
else
|
1791
|
-
# TODO. Add Image::Size to support other types.
|
1792
|
-
raise "Unsupported image format for file: #{filename}\n"
|
1793
|
-
end
|
1794
|
-
|
1795
|
-
@images << [filename, type]
|
1796
|
-
|
1797
|
-
# Also store new data for use in duplicate images.
|
1798
|
-
previous_images << [image_id, type, width, height]
|
1799
|
-
images_seen[filename] = image_id
|
1800
|
-
image_id += 1
|
1844
|
+
# TODO. Add Image::Size to support other types.
|
1845
|
+
raise "Unsupported image format for file: #{filename}\n"
|
1801
1846
|
end
|
1802
1847
|
|
1803
|
-
[
|
1848
|
+
@images << [filename, type]
|
1849
|
+
|
1850
|
+
[type, width, height, File.basename(filename), x_dpi, y_dpi]
|
1804
1851
|
end
|
1805
1852
|
|
1806
1853
|
#
|
@@ -1808,27 +1855,75 @@ module Writexlsx
|
|
1808
1855
|
#
|
1809
1856
|
def process_png(data)
|
1810
1857
|
type = 'png'
|
1811
|
-
width =
|
1812
|
-
height =
|
1858
|
+
width = 0
|
1859
|
+
height = 0
|
1860
|
+
x_dip = 96
|
1861
|
+
y_dpi = 96
|
1813
1862
|
|
1814
|
-
|
1863
|
+
offset = 8
|
1864
|
+
data_length = data.size
|
1865
|
+
|
1866
|
+
# Search through the image data to read the height and width in th the
|
1867
|
+
# IHDR element. Also read the DPI in the pHYs element.
|
1868
|
+
while offset < data_length
|
1869
|
+
|
1870
|
+
length = data[offset + 0, 4].unpack("N")[0]
|
1871
|
+
png_type = data[offset + 4, 4].unpack("A4")[0]
|
1872
|
+
|
1873
|
+
case png_type
|
1874
|
+
when "IHDR"
|
1875
|
+
width = data[offset + 8, 4].unpack("N")[0]
|
1876
|
+
height = data[offset + 12, 4].unpack("N")[0]
|
1877
|
+
when "pHYs"
|
1878
|
+
x_ppu = data[offset + 8, 4].unpack("N")[0]
|
1879
|
+
y_ppu = data[offset + 12, 4].unpack("N")[0]
|
1880
|
+
units = data[offset + 16, 1].unpack("C")[0]
|
1881
|
+
|
1882
|
+
if units == 1
|
1883
|
+
x_dpi = x_ppu * 0.0254
|
1884
|
+
y_dpi = y_ppu * 0.0254
|
1885
|
+
end
|
1886
|
+
end
|
1887
|
+
|
1888
|
+
offset = offset + length + 12
|
1889
|
+
|
1890
|
+
break if png_type == "IEND"
|
1891
|
+
end
|
1892
|
+
raise "#{filename}: no size data found in png image.\n" unless height
|
1893
|
+
|
1894
|
+
[type, width, height, x_dpi, y_dpi]
|
1815
1895
|
end
|
1816
1896
|
|
1817
1897
|
def process_jpg(data, filename)
|
1818
1898
|
type = 'jpeg'
|
1899
|
+
x_dpi = 96
|
1900
|
+
y_dpi = 96
|
1901
|
+
|
1819
1902
|
offset = 2
|
1820
1903
|
data_length = data.bytesize
|
1821
1904
|
|
1822
|
-
# Search through the image data to
|
1823
|
-
#
|
1905
|
+
# Search through the image data to read the height and width in the
|
1906
|
+
# 0xFFC0/C2 element. Also read the DPI in the 0xFFE0 element.
|
1824
1907
|
while offset < data_length
|
1825
|
-
marker = data[offset,
|
1908
|
+
marker = data[offset+0, 2].unpack("n")[0]
|
1826
1909
|
length = data[offset+2, 2].unpack("n")[0]
|
1827
1910
|
|
1828
1911
|
if marker == 0xFFC0 || marker == 0xFFC2
|
1829
1912
|
height = data[offset+5, 2].unpack("n")[0]
|
1830
1913
|
width = data[offset+7, 2].unpack("n")[0]
|
1831
|
-
|
1914
|
+
end
|
1915
|
+
if marker == 0xFFE0
|
1916
|
+
units = data[offset + 11, 1].unpack("C")[0]
|
1917
|
+
x_density = data[offset + 12, 2].unpack("n")[0]
|
1918
|
+
y_density = data[offset + 14, 2].unpack("n")[0]
|
1919
|
+
|
1920
|
+
if units == 1
|
1921
|
+
x_dpi = x_density
|
1922
|
+
y_dpi = y_density
|
1923
|
+
elsif units == 2
|
1924
|
+
x_dpi = x_density * 2.54
|
1925
|
+
y_dpi = y_density * 2.54
|
1926
|
+
end
|
1832
1927
|
end
|
1833
1928
|
|
1834
1929
|
offset += length + 2
|
@@ -1836,7 +1931,7 @@ module Writexlsx
|
|
1836
1931
|
end
|
1837
1932
|
|
1838
1933
|
raise "#{filename}: no size data found in jpeg image.\n" unless height
|
1839
|
-
[type, width, height]
|
1934
|
+
[type, width, height, x_dpi, y_dpi]
|
1840
1935
|
end
|
1841
1936
|
|
1842
1937
|
# Extract width and height information from a BMP file.
|
@@ -12,7 +12,7 @@ module Writexlsx
|
|
12
12
|
attr_accessor :fit_page, :fit_width, :fit_height, :page_setup_changed # :nodoc:
|
13
13
|
attr_writer :across # :nodoc:
|
14
14
|
attr_accessor :orientation, :print_options_changed # :nodoc:
|
15
|
-
attr_accessor :header, :footer, :header_footer_changed, :header_footer_aligns
|
15
|
+
attr_accessor :header, :footer, :header_footer_changed, :header_footer_aligns, :header_footer_scales
|
16
16
|
attr_writer :page_start
|
17
17
|
|
18
18
|
def initialize # :nodoc:
|
@@ -34,6 +34,8 @@ module Writexlsx
|
|
34
34
|
@page_setup_changed = false
|
35
35
|
@across = false
|
36
36
|
@orientation = true
|
37
|
+
@header_footer_aligns = true
|
38
|
+
@header_footer_scales = true
|
37
39
|
end
|
38
40
|
|
39
41
|
def paper=(paper_size)
|
@@ -139,7 +141,8 @@ module Writexlsx
|
|
139
141
|
def write_header_footer(writer, excel2003_style) #:nodoc:
|
140
142
|
tag = 'headerFooter'
|
141
143
|
attributes = []
|
142
|
-
attributes << ['
|
144
|
+
attributes << ['scaleWithDoc', 0] unless ptrue?(@header_footer_scales)
|
145
|
+
attributes << ['alignWithMargins', 0] unless ptrue?(@header_footer_aligns)
|
143
146
|
|
144
147
|
if @header_footer_changed
|
145
148
|
writer.tag_elements(tag, attributes) do
|