write_xlsx 0.78.0 → 0.79.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|