write_xlsx 1.12.1 → 1.12.2
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/.rubocop.yml +12 -0
- data/Changes +3 -0
- data/LICENSE.txt +1 -1
- data/examples/autofilter.rb +1 -2
- data/examples/colors.rb +4 -4
- data/examples/formats.rb +14 -14
- data/lib/write_xlsx/chart/area.rb +1 -1
- data/lib/write_xlsx/chart/axis.rb +4 -4
- data/lib/write_xlsx/chart/bar.rb +1 -1
- data/lib/write_xlsx/chart/caption.rb +8 -4
- data/lib/write_xlsx/chart/column.rb +1 -1
- data/lib/write_xlsx/chart/doughnut.rb +2 -2
- data/lib/write_xlsx/chart/line.rb +1 -1
- data/lib/write_xlsx/chart/pie.rb +2 -2
- data/lib/write_xlsx/chart/radar.rb +1 -1
- data/lib/write_xlsx/chart/scatter.rb +1 -1
- data/lib/write_xlsx/chart/series.rb +10 -20
- data/lib/write_xlsx/chart/stock.rb +1 -1
- data/lib/write_xlsx/chart.rb +14 -21
- data/lib/write_xlsx/chartsheet.rb +3 -3
- data/lib/write_xlsx/drawing.rb +108 -114
- data/lib/write_xlsx/format.rb +20 -24
- data/lib/write_xlsx/image.rb +89 -0
- data/lib/write_xlsx/image_property.rb +163 -0
- data/lib/write_xlsx/inserted_chart.rb +42 -0
- data/lib/write_xlsx/package/button.rb +58 -5
- data/lib/write_xlsx/package/conditional_format.rb +4 -4
- data/lib/write_xlsx/package/packager.rb +22 -27
- data/lib/write_xlsx/package/rich_value.rb +1 -1
- data/lib/write_xlsx/package/styles.rb +1 -1
- data/lib/write_xlsx/package/vml.rb +10 -19
- data/lib/write_xlsx/shape.rb +3 -2
- data/lib/write_xlsx/sparkline.rb +1 -1
- data/lib/write_xlsx/utility.rb +8 -203
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +87 -175
- data/lib/write_xlsx/worksheet/data_validation.rb +1 -1
- data/lib/write_xlsx/worksheet/hyperlink.rb +2 -2
- data/lib/write_xlsx/worksheet.rb +478 -484
- data/lib/write_xlsx/zip_file_utils.rb +1 -1
- data/write_xlsx.gemspec +3 -3
- metadata +11 -11
@@ -0,0 +1,42 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Writexlsx
|
5
|
+
class InsertedChart
|
6
|
+
include Writexlsx::Utility
|
7
|
+
|
8
|
+
attr_reader :row, :col, :chart, :x_offset, :y_offset
|
9
|
+
attr_reader :x_scale, :y_scale
|
10
|
+
attr_reader :anchor, :description, :decorative
|
11
|
+
|
12
|
+
def initialize(
|
13
|
+
row, col, chart, x_offset, y_offset, x_scale, y_scale,
|
14
|
+
anchor, description, decorative
|
15
|
+
)
|
16
|
+
@row = row
|
17
|
+
@col = col
|
18
|
+
@chart = chart
|
19
|
+
@x_offset = x_offset
|
20
|
+
@y_offset = y_offset
|
21
|
+
@x_scale = x_scale || 0
|
22
|
+
@y_scale = y_scale || 0
|
23
|
+
@anchor = anchor
|
24
|
+
@description = description
|
25
|
+
@decorative = decorative
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
chart.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def scaled_width
|
33
|
+
width = chart.width if ptrue?(chart.width)
|
34
|
+
(0.5 + (width * x_scale)).to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
def scaled_height
|
38
|
+
height = chart.height if ptrue?(chart.height)
|
39
|
+
(0.5 + (height * y_scale)).to_i
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -8,13 +8,66 @@ module Writexlsx
|
|
8
8
|
class Button
|
9
9
|
include Writexlsx::Utility
|
10
10
|
|
11
|
-
|
11
|
+
def initialize(worksheet, row, col, params, default_row_pixels, button_number)
|
12
|
+
@worksheet = worksheet
|
13
|
+
@default_row_pixels = default_row_pixels
|
14
|
+
|
15
|
+
# Set the button caption.
|
16
|
+
caption = params[:caption] || "Button #{button_number}"
|
17
|
+
|
18
|
+
@font = { _caption: caption }
|
19
|
+
|
20
|
+
# Set the macro name.
|
21
|
+
@macro = if params[:macro]
|
22
|
+
"[0]!#{params[:macro]}"
|
23
|
+
else
|
24
|
+
"[0]!Button#{button_number}_Click"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Set the alt text for the button.
|
28
|
+
@description = params[:description]
|
29
|
+
|
30
|
+
# Ensure that a width and height have been set.
|
31
|
+
default_height = @default_row_pixels
|
32
|
+
width = params[:width] || DEFAULT_COL_PIXELS
|
33
|
+
height = params[:height] || default_row_pixels
|
34
|
+
|
35
|
+
# Scale the size of the button box if required.
|
36
|
+
width *= params[:x_scale] if params[:x_scale]
|
37
|
+
height *= params[:y_scale] if params[:y_scale]
|
38
|
+
|
39
|
+
# Round the dimensions to the nearest pixel.
|
40
|
+
width = (0.5 + width).to_i
|
41
|
+
height = (0.5 + height).to_i
|
42
|
+
|
43
|
+
# Set the x/y offsets.
|
44
|
+
x_offset = params[:x_offset] || 0
|
45
|
+
y_offset = params[:y_offset] || 0
|
46
|
+
|
47
|
+
start_row = row
|
48
|
+
start_col = col
|
49
|
+
|
50
|
+
# Calculate the positions of button object.
|
51
|
+
vertices = @worksheet.position_object_pixels(
|
52
|
+
start_col,
|
53
|
+
start_row,
|
54
|
+
x_offset,
|
55
|
+
y_offset,
|
56
|
+
width,
|
57
|
+
height
|
58
|
+
)
|
59
|
+
|
60
|
+
# Add the width and height for VML.
|
61
|
+
vertices << [width, height]
|
62
|
+
|
63
|
+
@vertices = vertices
|
64
|
+
end
|
12
65
|
|
13
66
|
def v_shape_attributes(id, z_index)
|
14
67
|
attributes = v_shape_attributes_base(id)
|
15
|
-
attributes << ['alt', description] if description
|
68
|
+
attributes << ['alt', @description] if @description
|
16
69
|
|
17
|
-
attributes << ['style', (v_shape_style_base(z_index, vertices) + style_addition).join]
|
70
|
+
attributes << ['style', (v_shape_style_base(z_index, @vertices) + style_addition).join]
|
18
71
|
attributes << ['o:button', 't']
|
19
72
|
attributes << ['fillcolor', color]
|
20
73
|
attributes << ['strokecolor', 'windowText [64]']
|
@@ -81,7 +134,7 @@ module Writexlsx
|
|
81
134
|
|
82
135
|
@writer.tag_elements('v:textbox', attributes) do
|
83
136
|
# Write the div element.
|
84
|
-
write_div('center', font)
|
137
|
+
write_div('center', @font)
|
85
138
|
end
|
86
139
|
end
|
87
140
|
|
@@ -118,7 +171,7 @@ module Writexlsx
|
|
118
171
|
# Write the <x:FmlaMacro> element.
|
119
172
|
#
|
120
173
|
def write_fmla_macro
|
121
|
-
@writer.data_element('x:FmlaMacro', macro)
|
174
|
+
@writer.data_element('x:FmlaMacro', @macro)
|
122
175
|
end
|
123
176
|
|
124
177
|
#
|
@@ -409,7 +409,7 @@ module Writexlsx
|
|
409
409
|
|
410
410
|
def row_col_param_for_conditional_formatting(*args)
|
411
411
|
# Check for a cell reference in A1 notation and substitute row and column
|
412
|
-
user_range = if args[0].to_s =~
|
412
|
+
user_range = if args[0].to_s =~ /^\D/ && (args[0] =~ /,/)
|
413
413
|
# Check for a user defined multiple range like B3:K6,B8:K11.
|
414
414
|
args[0].sub(/^=/, '').gsub(/\s*,\s*/, ' ').gsub("$", '')
|
415
415
|
end
|
@@ -516,7 +516,7 @@ module Writexlsx
|
|
516
516
|
end
|
517
517
|
|
518
518
|
# 'Between' and 'Not between' criteria require 2 values.
|
519
|
-
if
|
519
|
+
if %w[between notBetween].include?(param[:criteria])
|
520
520
|
raise WriteXLSXOptionParameterError, "Invalid criteria : #{param[:criteria]}" unless param.has_key?(:minimum) || param.has_key?(:maximum)
|
521
521
|
else
|
522
522
|
param[:minimum] = nil
|
@@ -524,7 +524,7 @@ module Writexlsx
|
|
524
524
|
end
|
525
525
|
|
526
526
|
# Convert date/times value if required.
|
527
|
-
raise WriteXLSXOptionParameterError if
|
527
|
+
raise WriteXLSXOptionParameterError if %w[date time].include?(param[:type]) && !(convert_date_time_value(param, :value) || convert_date_time_value(param, :maximum))
|
528
528
|
end
|
529
529
|
|
530
530
|
def convert_date_time_if_required(val)
|
@@ -697,7 +697,7 @@ module Writexlsx
|
|
697
697
|
max_data = user_props.size
|
698
698
|
max_data = total_icons - 1 if max_data >= total_icons
|
699
699
|
|
700
|
-
(0..max_data - 1).each do |i|
|
700
|
+
(0..(max_data - 1)).each do |i|
|
701
701
|
# Set the user defined 'value' property.
|
702
702
|
props[i][:value] = user_props[i][:value].to_s.sub(/^=/, '') if user_props[i][:value]
|
703
703
|
|
@@ -203,11 +203,9 @@ module Writexlsx
|
|
203
203
|
# Write the rdrichvalue(*).xml file.
|
204
204
|
#
|
205
205
|
def write_rich_value_files
|
206
|
-
dir = @package_dir
|
207
|
-
|
208
206
|
return unless @workbook.has_embedded_images?
|
209
207
|
|
210
|
-
FileUtils.mkdir_p("#{
|
208
|
+
FileUtils.mkdir_p("#{@package_dir}/xl/richData")
|
211
209
|
|
212
210
|
write_rich_value_file
|
213
211
|
write_rich_value_structure_file
|
@@ -219,12 +217,11 @@ module Writexlsx
|
|
219
217
|
# Write the rdrichvalue.xml file.
|
220
218
|
#
|
221
219
|
def write_rich_value_file
|
222
|
-
dir = @package_dir
|
223
220
|
rich_value = Package::RichValue.new
|
224
221
|
|
225
222
|
rich_value.embedded_images = @workbook.embedded_images
|
226
223
|
|
227
|
-
rich_value.set_xml_writer("#{
|
224
|
+
rich_value.set_xml_writer("#{@package_dir}/xl/richData/rdrichvalue.xml")
|
228
225
|
rich_value.assemble_xml_file
|
229
226
|
end
|
230
227
|
|
@@ -232,12 +229,11 @@ module Writexlsx
|
|
232
229
|
# Write the rdrichvaluestructure.xml file.
|
233
230
|
#
|
234
231
|
def write_rich_value_structure_file
|
235
|
-
dir = @package_dir
|
236
232
|
rich_value = Package::RichValueStructure.new
|
237
233
|
|
238
234
|
rich_value.has_embedded_descriptions = @workbook.has_embedded_descriptions?
|
239
235
|
|
240
|
-
rich_value.set_xml_writer("#{
|
236
|
+
rich_value.set_xml_writer("#{@package_dir}/xl/richData/rdrichvaluestructure.xml")
|
241
237
|
rich_value.assemble_xml_file
|
242
238
|
end
|
243
239
|
|
@@ -246,9 +242,8 @@ module Writexlsx
|
|
246
242
|
#
|
247
243
|
def write_rich_value_types_file
|
248
244
|
rich_value = Package::RichValueTypes.new
|
249
|
-
dir = @package_dir
|
250
245
|
|
251
|
-
rich_value.set_xml_writer("#{
|
246
|
+
rich_value.set_xml_writer("#{@package_dir}/xl/richData/rdRichValueTypes.xml")
|
252
247
|
rich_value.assemble_xml_file
|
253
248
|
end
|
254
249
|
|
@@ -256,12 +251,11 @@ module Writexlsx
|
|
256
251
|
# Write the rdrichvalue.xml file.
|
257
252
|
#
|
258
253
|
def write_rich_value_rel
|
259
|
-
dir = @package_dir
|
260
254
|
rich_value = Package::RichValueRel.new
|
261
255
|
|
262
256
|
rich_value.value_count = @workbook.embedded_images.size
|
263
257
|
|
264
|
-
rich_value.set_xml_writer("#{
|
258
|
+
rich_value.set_xml_writer("#{@package_dir}/xl/richData/richValueRel.xml")
|
265
259
|
rich_value.assemble_xml_file
|
266
260
|
end
|
267
261
|
|
@@ -456,22 +450,21 @@ module Writexlsx
|
|
456
450
|
def write_rich_value_rels_files
|
457
451
|
return if @workbook.embedded_images.empty?
|
458
452
|
|
459
|
-
dir = @package_dir
|
460
|
-
|
461
453
|
# Create the .rels dirs.
|
462
|
-
|
454
|
+
rich_value_rels_dir = "#{@package_dir}/xl/richData/_rels"
|
455
|
+
FileUtils.mkdir_p(rich_value_rels_dir)
|
463
456
|
|
464
457
|
rels = Package::Relationships.new
|
465
458
|
|
466
459
|
@workbook.embedded_images.each_with_index do |image_data, index|
|
467
|
-
file_type = image_data
|
460
|
+
file_type = image_data.type
|
468
461
|
image_file = "../media/image#{index + 1}.#{file_type}"
|
469
462
|
|
470
463
|
rels.add_worksheet_relationship('/image', image_file)
|
471
464
|
end
|
472
465
|
|
473
466
|
# Create the .rels file.
|
474
|
-
rels.set_xml_writer("#{
|
467
|
+
rels.set_xml_writer("#{rich_value_rels_dir}/richValueRel.xml.rels")
|
475
468
|
rels.assemble_xml_file
|
476
469
|
end
|
477
470
|
|
@@ -481,32 +474,34 @@ module Writexlsx
|
|
481
474
|
def add_image_files
|
482
475
|
index = 1
|
483
476
|
|
484
|
-
dir = "#{@package_dir}/xl/media"
|
485
|
-
|
486
477
|
@workbook.embedded_images.each do |image|
|
487
|
-
|
488
|
-
FileUtils.cp(image[0], "#{dir}/image#{index}.#{image[1]}")
|
489
|
-
index += 1
|
478
|
+
index = write_image_x_xml_files(image, index)
|
490
479
|
end
|
491
480
|
|
492
481
|
@workbook.images.each do |image|
|
493
|
-
|
494
|
-
FileUtils.cp(image[0], "#{dir}/image#{index}.#{image[1]}")
|
495
|
-
index += 1
|
482
|
+
index = write_image_x_xml_files(image, index)
|
496
483
|
end
|
497
484
|
end
|
498
485
|
|
486
|
+
def write_image_x_xml_files(image, index)
|
487
|
+
FileUtils.mkdir_p("#{@package_dir}/xl/media")
|
488
|
+
FileUtils.cp(
|
489
|
+
image.filename,
|
490
|
+
"#{@package_dir}/xl/media/image#{index}.#{image.type}"
|
491
|
+
)
|
492
|
+
index + 1
|
493
|
+
end
|
494
|
+
|
499
495
|
#
|
500
496
|
# Write the vbaProject.bin file.
|
501
497
|
#
|
502
498
|
def add_vba_project
|
503
|
-
dir = @package_dir
|
504
499
|
vba_project = @workbook.vba_project
|
505
500
|
|
506
501
|
return unless vba_project
|
507
502
|
|
508
|
-
FileUtils.mkdir_p("#{
|
509
|
-
FileUtils.copy(vba_project, "#{
|
503
|
+
FileUtils.mkdir_p("#{@package_dir}/xl")
|
504
|
+
FileUtils.copy(vba_project, "#{@package_dir}/xl/vbaProject.bin")
|
510
505
|
end
|
511
506
|
end
|
512
507
|
end
|
@@ -265,21 +265,10 @@ module Writexlsx
|
|
265
265
|
#
|
266
266
|
# Write the <v:shape> element.
|
267
267
|
#
|
268
|
-
def write_image_shape(id, index,
|
269
|
-
type = '#_x0000_t75'
|
270
|
-
|
271
|
-
# Get the image parameters
|
272
|
-
width = image_data[0]
|
273
|
-
height = image_data[1]
|
274
|
-
name = image_data[2]
|
275
|
-
position = image_data[3]
|
276
|
-
x_dpi = image_data[4]
|
277
|
-
y_dpi = image_data[5]
|
278
|
-
ref_id = image_data[6]
|
279
|
-
|
268
|
+
def write_image_shape(id, index, image_property)
|
280
269
|
# Scale the height/width by the resolution, relative to 72dpi.
|
281
|
-
width = width * 72.0 / x_dpi
|
282
|
-
height = height * 72.0 / y_dpi
|
270
|
+
width = image_property.width * 72.0 / image_property.x_dpi
|
271
|
+
height = image_property.height * 72.0 / image_property.y_dpi
|
283
272
|
|
284
273
|
# Excel uses a rounding based around 72 and 96 dpi.
|
285
274
|
width = 72 / 96.0 * ((width * 96 / 72.0) + 0.25).to_i
|
@@ -288,13 +277,15 @@ module Writexlsx
|
|
288
277
|
width = width.to_i if (width - width.to_i).abs < 0.1
|
289
278
|
height = height.to_i if (height - height.to_i).abs < 0.1
|
290
279
|
|
280
|
+
type = '#_x0000_t75'
|
281
|
+
|
291
282
|
style = [
|
292
283
|
"position:absolute", "margin-left:0", "margin-top:0",
|
293
284
|
"width:#{width}pt", "height:#{height}pt",
|
294
285
|
"z-index:#{index}"
|
295
286
|
].join(';')
|
296
287
|
attributes = [
|
297
|
-
['id', position],
|
288
|
+
['id', image_property.position],
|
298
289
|
['o:spid', "_x0000_s#{id}"],
|
299
290
|
['type', type],
|
300
291
|
['style', style]
|
@@ -302,7 +293,7 @@ module Writexlsx
|
|
302
293
|
|
303
294
|
@writer.tag_elements('v:shape', attributes) do
|
304
295
|
# Write the v:imagedata element.
|
305
|
-
write_imagedata(
|
296
|
+
write_imagedata(image_property)
|
306
297
|
|
307
298
|
# Write the o:lock element.
|
308
299
|
write_rotation_lock
|
@@ -312,10 +303,10 @@ module Writexlsx
|
|
312
303
|
#
|
313
304
|
# Write the <v:imagedata> element.
|
314
305
|
#
|
315
|
-
def write_imagedata(
|
306
|
+
def write_imagedata(image_property)
|
316
307
|
attributes = [
|
317
|
-
['o:relid', "rId#{
|
318
|
-
['o:title',
|
308
|
+
['o:relid', "rId#{image_property.ref_id}"],
|
309
|
+
['o:title', image_property.body]
|
319
310
|
]
|
320
311
|
|
321
312
|
@writer.empty_tag('v:imagedata', attributes)
|
data/lib/write_xlsx/shape.rb
CHANGED
@@ -150,8 +150,9 @@ module Writexlsx
|
|
150
150
|
# Calculate the vertices that define the position of a shape object within
|
151
151
|
# the worksheet in EMUs. Save the vertices with the object.
|
152
152
|
#
|
153
|
-
# The vertices are expressed as English Metric Units (EMUs).
|
154
|
-
# EMUs per point. Therefore, 12,700 * 3 /4 = 9,525
|
153
|
+
# The vertices are expressed as English Metric Units (EMUs).
|
154
|
+
# There are 12,700 EMUs per point. Therefore, 12,700 * 3 /4 = 9,525
|
155
|
+
# EMUs per pixel.
|
155
156
|
#
|
156
157
|
def calc_position_emus(worksheet)
|
157
158
|
c_start, r_start,
|
data/lib/write_xlsx/sparkline.rb
CHANGED
@@ -246,7 +246,7 @@ module Writexlsx
|
|
246
246
|
def write_sparklines # :nodoc:
|
247
247
|
# Write the sparkline elements.
|
248
248
|
@writer.tag_elements('x14:sparklines') do
|
249
|
-
(0..count - 1).each do |i|
|
249
|
+
(0..(count - 1)).each do |i|
|
250
250
|
range = @ranges[i]
|
251
251
|
location = @locations[i]
|
252
252
|
|
data/lib/write_xlsx/utility.rb
CHANGED
@@ -27,6 +27,9 @@ module Writexlsx
|
|
27
27
|
't' => 5, 'u' => 8, 'v' => 7, 'w' => 11, 'x' => 7, 'y' => 7,
|
28
28
|
'z' => 6, '{' => 5, '|' => 7, '}' => 5, '~' => 7
|
29
29
|
}.freeze
|
30
|
+
MAX_DIGIT_WIDTH = 7 # For Calabri 11. # :nodoc:
|
31
|
+
PADDING = 5 # :nodoc:
|
32
|
+
DEFAULT_COL_PIXELS = 64
|
30
33
|
|
31
34
|
#
|
32
35
|
# xl_rowcol_to_cell($row, col, row_absolute, col_absolute)
|
@@ -169,7 +172,7 @@ module Writexlsx
|
|
169
172
|
if time =~ /^(\d\d):(\d\d)(:(\d\d(\.\d+)?))?/
|
170
173
|
hour = ::Regexp.last_match(1).to_i
|
171
174
|
min = ::Regexp.last_match(2).to_i
|
172
|
-
sec = ::Regexp.last_match(4).to_f
|
175
|
+
sec = ::Regexp.last_match(4).to_f
|
173
176
|
else
|
174
177
|
return nil # Not a valid time format.
|
175
178
|
end
|
@@ -226,7 +229,7 @@ module Writexlsx
|
|
226
229
|
|
227
230
|
# Accumulate the number of days since the epoch.
|
228
231
|
days = day # Add days for current month
|
229
|
-
(0..month - 2).each do |m|
|
232
|
+
(0..(month - 2)).each do |m|
|
230
233
|
days += mdays[m] # Add days for past months
|
231
234
|
end
|
232
235
|
days += range * 365 # Add days for past years
|
@@ -552,7 +555,7 @@ module Writexlsx
|
|
552
555
|
# Write the <x:Anchor> element.
|
553
556
|
#
|
554
557
|
def write_anchor
|
555
|
-
col_start, row_start, x1, y1, col_end, row_end, x2, y2 = vertices
|
558
|
+
col_start, row_start, x1, y1, col_end, row_end, x2, y2 = @vertices
|
556
559
|
data = [col_start, x1, row_start, y1, col_end, x2, row_end, y2].join(', ')
|
557
560
|
|
558
561
|
@writer.data_element('x:Anchor', data)
|
@@ -749,7 +752,7 @@ module Writexlsx
|
|
749
752
|
hash[key.to_sym]
|
750
753
|
end
|
751
754
|
|
752
|
-
def
|
755
|
+
def palette_color_from_index(index)
|
753
756
|
# Adjust the colour index.
|
754
757
|
idx = index - 8
|
755
758
|
|
@@ -757,32 +760,6 @@ module Writexlsx
|
|
757
760
|
sprintf("%02X%02X%02X", r, g, b)
|
758
761
|
end
|
759
762
|
|
760
|
-
#
|
761
|
-
# Workbook の生成時のオプションハッシュを解析する
|
762
|
-
#
|
763
|
-
def process_workbook_options(*params)
|
764
|
-
case params.size
|
765
|
-
when 0
|
766
|
-
[{}, {}]
|
767
|
-
when 1 # one hash
|
768
|
-
options_keys = %i[tempdir date_1904 optimization excel2003_style strings_to_urls]
|
769
|
-
|
770
|
-
hash = params.first
|
771
|
-
options = hash.reject { |k, _v| !options_keys.include?(k) }
|
772
|
-
|
773
|
-
default_format_properties =
|
774
|
-
hash[:default_format_properties] ||
|
775
|
-
hash.reject { |k, _v| options_keys.include?(k) }
|
776
|
-
|
777
|
-
[options, default_format_properties.dup]
|
778
|
-
when 2 # array which includes options and default_format_properties
|
779
|
-
options, default_format_properties = params
|
780
|
-
default_format_properties ||= {}
|
781
|
-
|
782
|
-
[options.dup, default_format_properties.dup]
|
783
|
-
end
|
784
|
-
end
|
785
|
-
|
786
763
|
#
|
787
764
|
# Convert user defined font values into private hash values.
|
788
765
|
#
|
@@ -960,7 +937,7 @@ module Writexlsx
|
|
960
937
|
index = Format.color(color_code)
|
961
938
|
raise "Unknown color '#{color_code}' used in chart formatting." unless index
|
962
939
|
|
963
|
-
|
940
|
+
palette_color_from_index(index)
|
964
941
|
end
|
965
942
|
end
|
966
943
|
|
@@ -988,178 +965,6 @@ module Writexlsx
|
|
988
965
|
def write_a_end_para_rpr # :nodoc:
|
989
966
|
@writer.empty_tag('a:endParaRPr', [%w[lang en-US]])
|
990
967
|
end
|
991
|
-
|
992
|
-
#
|
993
|
-
# Extract information from the image file such as dimension, type, filename,
|
994
|
-
# and extension. Also keep track of previously seen images to optimise out
|
995
|
-
# any duplicates.
|
996
|
-
#
|
997
|
-
def get_image_properties(filename)
|
998
|
-
# Note the image_id, and previous_images mechanism isn't currently used.
|
999
|
-
x_dpi = 96
|
1000
|
-
y_dpi = 96
|
1001
|
-
|
1002
|
-
workbook = @workbook || self
|
1003
|
-
|
1004
|
-
# Open the image file and import the data.
|
1005
|
-
data = File.binread(filename)
|
1006
|
-
md5 = Digest::MD5.hexdigest(data)
|
1007
|
-
if data.unpack1('x A3') == 'PNG'
|
1008
|
-
# Test for PNGs.
|
1009
|
-
type, width, height, x_dpi, y_dpi = process_png(data)
|
1010
|
-
workbook.image_types[:png] = 1
|
1011
|
-
elsif data.unpack1('n') == 0xFFD8
|
1012
|
-
# Test for JPEG files.
|
1013
|
-
type, width, height, x_dpi, y_dpi = process_jpg(data, filename)
|
1014
|
-
workbook.image_types[:jpeg] = 1
|
1015
|
-
elsif data.unpack1('A4') == 'GIF8'
|
1016
|
-
# Test for GIFs.
|
1017
|
-
type, width, height, x_dpi, y_dpi = process_gif(data, filename)
|
1018
|
-
workbook.image_types[:gif] = 1
|
1019
|
-
elsif data.unpack1('A2') == 'BM'
|
1020
|
-
# Test for BMPs.
|
1021
|
-
type, width, height = process_bmp(data, filename)
|
1022
|
-
workbook.image_types[:bmp] = 1
|
1023
|
-
else
|
1024
|
-
# TODO. Add Image::Size to support other types.
|
1025
|
-
raise "Unsupported image format for file: #{filename}\n"
|
1026
|
-
end
|
1027
|
-
|
1028
|
-
# Set a default dpi for images with 0 dpi.
|
1029
|
-
x_dpi = 96 if x_dpi == 0
|
1030
|
-
y_dpi = 96 if y_dpi == 0
|
1031
|
-
|
1032
|
-
[type, width, height, File.basename(filename), x_dpi, y_dpi, md5]
|
1033
|
-
end
|
1034
|
-
|
1035
|
-
#
|
1036
|
-
# Extract width and height information from a PNG file.
|
1037
|
-
#
|
1038
|
-
def process_png(data)
|
1039
|
-
type = 'png'
|
1040
|
-
width = 0
|
1041
|
-
height = 0
|
1042
|
-
x_dpi = 96
|
1043
|
-
y_dpi = 96
|
1044
|
-
|
1045
|
-
offset = 8
|
1046
|
-
data_length = data.size
|
1047
|
-
|
1048
|
-
# Search through the image data to read the height and width in th the
|
1049
|
-
# IHDR element. Also read the DPI in the pHYs element.
|
1050
|
-
while offset < data_length
|
1051
|
-
|
1052
|
-
length = data[offset + 0, 4].unpack1("N")
|
1053
|
-
png_type = data[offset + 4, 4].unpack1("A4")
|
1054
|
-
|
1055
|
-
case png_type
|
1056
|
-
when "IHDR"
|
1057
|
-
width = data[offset + 8, 4].unpack1("N")
|
1058
|
-
height = data[offset + 12, 4].unpack1("N")
|
1059
|
-
when "pHYs"
|
1060
|
-
x_ppu = data[offset + 8, 4].unpack1("N")
|
1061
|
-
y_ppu = data[offset + 12, 4].unpack1("N")
|
1062
|
-
units = data[offset + 16, 1].unpack1("C")
|
1063
|
-
|
1064
|
-
if units == 1
|
1065
|
-
x_dpi = x_ppu * 0.0254
|
1066
|
-
y_dpi = y_ppu * 0.0254
|
1067
|
-
end
|
1068
|
-
end
|
1069
|
-
|
1070
|
-
offset = offset + length + 12
|
1071
|
-
|
1072
|
-
break if png_type == "IEND"
|
1073
|
-
end
|
1074
|
-
raise "#{filename}: no size data found in png image.\n" unless height
|
1075
|
-
|
1076
|
-
[type, width, height, x_dpi, y_dpi]
|
1077
|
-
end
|
1078
|
-
|
1079
|
-
def process_jpg(data, filename)
|
1080
|
-
type = 'jpeg'
|
1081
|
-
x_dpi = 96
|
1082
|
-
y_dpi = 96
|
1083
|
-
|
1084
|
-
offset = 2
|
1085
|
-
data_length = data.bytesize
|
1086
|
-
|
1087
|
-
# Search through the image data to read the JPEG markers.
|
1088
|
-
while offset < data_length
|
1089
|
-
marker = data[offset + 0, 2].unpack1("n")
|
1090
|
-
length = data[offset + 2, 2].unpack1("n")
|
1091
|
-
|
1092
|
-
# Read the height and width in the 0xFFCn elements
|
1093
|
-
# (Except C4, C8 and CC which aren't SOF markers).
|
1094
|
-
if (marker & 0xFFF0) == 0xFFC0 &&
|
1095
|
-
marker != 0xFFC4 && marker != 0xFFCC
|
1096
|
-
height = data[offset + 5, 2].unpack1("n")
|
1097
|
-
width = data[offset + 7, 2].unpack1("n")
|
1098
|
-
end
|
1099
|
-
|
1100
|
-
# Read the DPI in the 0xFFE0 element.
|
1101
|
-
if marker == 0xFFE0
|
1102
|
-
units = data[offset + 11, 1].unpack1("C")
|
1103
|
-
x_density = data[offset + 12, 2].unpack1("n")
|
1104
|
-
y_density = data[offset + 14, 2].unpack1("n")
|
1105
|
-
|
1106
|
-
if units == 1
|
1107
|
-
x_dpi = x_density
|
1108
|
-
y_dpi = y_density
|
1109
|
-
elsif units == 2
|
1110
|
-
x_dpi = x_density * 2.54
|
1111
|
-
y_dpi = y_density * 2.54
|
1112
|
-
end
|
1113
|
-
end
|
1114
|
-
|
1115
|
-
offset += length + 2
|
1116
|
-
break if marker == 0xFFDA
|
1117
|
-
end
|
1118
|
-
|
1119
|
-
raise "#{filename}: no size data found in jpeg image.\n" unless height
|
1120
|
-
|
1121
|
-
[type, width, height, x_dpi, y_dpi]
|
1122
|
-
end
|
1123
|
-
|
1124
|
-
#
|
1125
|
-
# Extract width and height information from a GIF file.
|
1126
|
-
#
|
1127
|
-
def process_gif(data, filename)
|
1128
|
-
type = 'gif'
|
1129
|
-
x_dpi = 96
|
1130
|
-
y_dpi = 96
|
1131
|
-
|
1132
|
-
width = data[6, 2].unpack1("v")
|
1133
|
-
height = data[8, 2].unpack1("v")
|
1134
|
-
|
1135
|
-
raise "#{filename}: no size data found in gif image.\n" if height.nil?
|
1136
|
-
|
1137
|
-
[type, width, height, x_dpi, y_dpi]
|
1138
|
-
end
|
1139
|
-
|
1140
|
-
# Extract width and height information from a BMP file.
|
1141
|
-
def process_bmp(data, filename) # :nodoc:
|
1142
|
-
type = 'bmp'
|
1143
|
-
|
1144
|
-
# Check that the file is big enough to be a bitmap.
|
1145
|
-
raise "#{filename} doesn't contain enough data." if data.bytesize <= 0x36
|
1146
|
-
|
1147
|
-
# Read the bitmap width and height. Verify the sizes.
|
1148
|
-
width, height = data.unpack("x18 V2")
|
1149
|
-
raise "#{filename}: largest image width #{width} supported is 65k." if width > 0xFFFF
|
1150
|
-
raise "#{filename}: largest image height supported is 65k." if height > 0xFFFF
|
1151
|
-
|
1152
|
-
# Read the bitmap planes and bpp data. Verify them.
|
1153
|
-
planes, bitcount = data.unpack("x26 v2")
|
1154
|
-
raise "#{filename} isn't a 24bit true color bitmap." unless bitcount == 24
|
1155
|
-
raise "#{filename}: only 1 plane supported in bitmap image." unless planes == 1
|
1156
|
-
|
1157
|
-
# Read the bitmap compression. Verify compression.
|
1158
|
-
compression = data.unpack1("x30 V")
|
1159
|
-
raise "#{filename}: compression not supported in bitmap image." unless compression == 0
|
1160
|
-
|
1161
|
-
[type, width, height]
|
1162
|
-
end
|
1163
968
|
end
|
1164
969
|
|
1165
970
|
module WriteDPtPoint
|
data/lib/write_xlsx/version.rb
CHANGED