write_xlsx 1.07.0 → 1.09.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/Changes +40 -0
  3. data/README.md +1 -1
  4. data/examples/background.rb +19 -0
  5. data/examples/ignore_errors.rb +39 -0
  6. data/ignore_errors.xlsx +0 -0
  7. data/lib/write_xlsx/chart/axis.rb +3 -3
  8. data/lib/write_xlsx/chart/scatter.rb +0 -15
  9. data/lib/write_xlsx/chart/series.rb +1 -1
  10. data/lib/write_xlsx/chart.rb +31 -33
  11. data/lib/write_xlsx/chartsheet.rb +3 -3
  12. data/lib/write_xlsx/drawing.rb +118 -55
  13. data/lib/write_xlsx/format.rb +11 -179
  14. data/lib/write_xlsx/package/app.rb +5 -5
  15. data/lib/write_xlsx/package/button.rb +8 -8
  16. data/lib/write_xlsx/package/comments.rb +8 -8
  17. data/lib/write_xlsx/package/conditional_format.rb +2 -8
  18. data/lib/write_xlsx/package/content_types.rb +18 -9
  19. data/lib/write_xlsx/package/core.rb +5 -5
  20. data/lib/write_xlsx/package/custom.rb +2 -2
  21. data/lib/write_xlsx/package/metadata.rb +159 -0
  22. data/lib/write_xlsx/package/packager.rb +22 -0
  23. data/lib/write_xlsx/package/shared_strings.rb +6 -6
  24. data/lib/write_xlsx/package/styles.rb +27 -14
  25. data/lib/write_xlsx/package/table.rb +31 -23
  26. data/lib/write_xlsx/package/theme.rb +1 -1
  27. data/lib/write_xlsx/package/vml.rb +43 -43
  28. data/lib/write_xlsx/shape.rb +17 -15
  29. data/lib/write_xlsx/sparkline.rb +340 -340
  30. data/lib/write_xlsx/utility.rb +9 -24
  31. data/lib/write_xlsx/version.rb +1 -1
  32. data/lib/write_xlsx/workbook.rb +193 -643
  33. data/lib/write_xlsx/worksheet/cell_data.rb +25 -3
  34. data/lib/write_xlsx/worksheet/data_validation.rb +21 -26
  35. data/lib/write_xlsx/worksheet/hyperlink.rb +4 -4
  36. data/lib/write_xlsx/worksheet/page_setup.rb +12 -12
  37. data/lib/write_xlsx/worksheet.rb +461 -4233
  38. data/test/drawing/{test_write_ext.rb → test_write_xdr_ext.rb} +2 -2
  39. data/test/perl_output/background.xlsx +0 -0
  40. data/test/perl_output/ignore_errors.xlsx +0 -0
  41. data/test/regression/images/logo.gif +0 -0
  42. data/test/regression/images/logo.jpg +0 -0
  43. data/test/regression/images/red.gif +0 -0
  44. data/test/regression/test_background01.rb +23 -0
  45. data/test/regression/test_background02.rb +23 -0
  46. data/test/regression/test_background03.rb +24 -0
  47. data/test/regression/test_background04.rb +25 -0
  48. data/test/regression/test_background05.rb +25 -0
  49. data/test/regression/test_background06.rb +31 -0
  50. data/test/regression/test_background07.rb +37 -0
  51. data/test/regression/test_chart_axis47.rb +52 -0
  52. data/test/regression/test_chart_axis48.rb +53 -0
  53. data/test/regression/test_chart_crossing01.rb +1 -1
  54. data/test/regression/test_chart_crossing05.rb +46 -0
  55. data/test/regression/test_chart_crossing06.rb +46 -0
  56. data/test/regression/test_chart_data_labels48.rb +55 -0
  57. data/test/regression/test_chart_data_labels49.rb +55 -0
  58. data/test/regression/test_chart_data_labels50.rb +57 -0
  59. data/test/regression/test_dynamic_array01.rb +25 -0
  60. data/test/regression/test_format16.rb +24 -0
  61. data/test/regression/test_format17.rb +24 -0
  62. data/test/regression/test_header04.rb +30 -0
  63. data/test/regression/test_hyperlink50.rb +27 -0
  64. data/test/regression/test_hyperlink51.rb +27 -0
  65. data/test/regression/test_ignore_error01.rb +23 -0
  66. data/test/regression/test_ignore_error02.rb +24 -0
  67. data/test/regression/test_ignore_error03.rb +26 -0
  68. data/test/regression/test_ignore_error04.rb +26 -0
  69. data/test/regression/test_ignore_error05.rb +32 -0
  70. data/test/regression/test_ignore_error06.rb +32 -0
  71. data/test/regression/test_image52.rb +26 -0
  72. data/test/regression/test_image53.rb +26 -0
  73. data/test/regression/test_image54.rb +26 -0
  74. data/test/regression/test_image55.rb +27 -0
  75. data/test/regression/test_image56.rb +23 -0
  76. data/test/regression/test_image57.rb +23 -0
  77. data/test/regression/test_protect04.rb +32 -0
  78. data/test/regression/test_protect05.rb +35 -0
  79. data/test/regression/test_protect06.rb +35 -0
  80. data/test/regression/test_protect07.rb +23 -0
  81. data/test/regression/test_set_column10.rb +55 -0
  82. data/test/regression/test_set_column11.rb +48 -0
  83. data/test/regression/test_set_row01.rb +35 -0
  84. data/test/regression/test_set_row02.rb +35 -0
  85. data/test/regression/test_set_row03.rb +35 -0
  86. data/test/regression/test_set_row04.rb +35 -0
  87. data/test/regression/test_table26.rb +38 -0
  88. data/test/regression/xlsx_files/background01.xlsx +0 -0
  89. data/test/regression/xlsx_files/background02.xlsx +0 -0
  90. data/test/regression/xlsx_files/background03.xlsx +0 -0
  91. data/test/regression/xlsx_files/background04.xlsx +0 -0
  92. data/test/regression/xlsx_files/background05.xlsx +0 -0
  93. data/test/regression/xlsx_files/background06.xlsx +0 -0
  94. data/test/regression/xlsx_files/background07.xlsx +0 -0
  95. data/test/regression/xlsx_files/chart_axis47.xlsx +0 -0
  96. data/test/regression/xlsx_files/chart_axis48.xlsx +0 -0
  97. data/test/regression/xlsx_files/chart_crossing05.xlsx +0 -0
  98. data/test/regression/xlsx_files/chart_crossing06.xlsx +0 -0
  99. data/test/regression/xlsx_files/chart_data_labels48.xlsx +0 -0
  100. data/test/regression/xlsx_files/chart_data_labels49.xlsx +0 -0
  101. data/test/regression/xlsx_files/chart_data_labels50.xlsx +0 -0
  102. data/test/regression/xlsx_files/dynamic_array01.xlsx +0 -0
  103. data/test/regression/xlsx_files/format16.xlsx +0 -0
  104. data/test/regression/xlsx_files/format17.xlsx +0 -0
  105. data/test/regression/xlsx_files/header04.xlsx +0 -0
  106. data/test/regression/xlsx_files/hyperlink50.xlsx +0 -0
  107. data/test/regression/xlsx_files/hyperlink51.xlsx +0 -0
  108. data/test/regression/xlsx_files/ignore_error01.xlsx +0 -0
  109. data/test/regression/xlsx_files/ignore_error02.xlsx +0 -0
  110. data/test/regression/xlsx_files/ignore_error03.xlsx +0 -0
  111. data/test/regression/xlsx_files/ignore_error04.xlsx +0 -0
  112. data/test/regression/xlsx_files/ignore_error05.xlsx +0 -0
  113. data/test/regression/xlsx_files/ignore_error06.xlsx +0 -0
  114. data/test/regression/xlsx_files/image52.xlsx +0 -0
  115. data/test/regression/xlsx_files/image53.xlsx +0 -0
  116. data/test/regression/xlsx_files/image54.xlsx +0 -0
  117. data/test/regression/xlsx_files/image55.xlsx +0 -0
  118. data/test/regression/xlsx_files/image56.xlsx +0 -0
  119. data/test/regression/xlsx_files/image57.xlsx +0 -0
  120. data/test/regression/xlsx_files/protect04.xlsx +0 -0
  121. data/test/regression/xlsx_files/protect05.xlsx +0 -0
  122. data/test/regression/xlsx_files/protect06.xlsx +0 -0
  123. data/test/regression/xlsx_files/protect07.xlsx +0 -0
  124. data/test/regression/xlsx_files/set_row01.xlsx +0 -0
  125. data/test/regression/xlsx_files/set_row03.xlsx +0 -0
  126. data/test/regression/xlsx_files/table26.xlsx +0 -0
  127. data/test/test_example_match.rb +43 -0
  128. data/test/utility/test_range.rb +20 -0
  129. data/test/worksheet/test_pixels_to_row_col.rb +46 -0
  130. metadata +190 -8
@@ -19,81 +19,25 @@ module Writexlsx
19
19
 
20
20
  OFFICE_URL = 'http://schemas.microsoft.com/office/' # :nodoc:
21
21
 
22
- # The WriteXLSX provides an object oriented interface to a new Excel workbook.
23
- # The following methods are available through a new workbook.
24
- #
25
- # * new[#method-c-new]
26
- # * add_worksheet[#method-i-add_worksheet]
27
- # * add_format[#method-i-add_format]
28
- # * add_chart[#method-i-add_chart]
29
- # * add_shape[#method-i-add_shape]
30
- # * add_vba_project[#method-i-add_vba_project]
31
- # * close[#method-i-close]
32
- # * set_properties[#method-i-set_properties]
33
- # * define_name[#method-i-define_name]
34
- # * set_custom_color[#method-i-set_custom_color]
35
- # * sheets[#method-i-sheets]
36
- # * set_1904[#method-i-set_1904]
37
- #
38
22
  class Workbook
39
23
 
40
24
  include Writexlsx::Utility
41
25
 
42
- attr_writer :firstsheet # :nodoc:
43
- attr_reader :palette # :nodoc:
44
- attr_reader :worksheets, :charts, :drawings # :nodoc:
45
- attr_reader :named_ranges # :nodoc:
46
- attr_reader :doc_properties # :nodoc:
47
- attr_reader :custom_properties # :nodoc:
48
- attr_reader :image_types, :images # :nodoc:
49
- attr_reader :shared_strings # :nodoc:
50
- attr_reader :vba_project # :nodoc:
51
- attr_reader :excel2003_style # :nodoc:
52
- attr_reader :max_url_length # :nodoc:
53
- attr_reader :strings_to_urls # :nodoc:
54
- attr_reader :default_url_format # :nodoc:
26
+ attr_writer :firstsheet # :nodoc:
27
+ attr_reader :palette # :nodoc:
28
+ attr_reader :worksheets, :charts, :drawings # :nodoc:
29
+ attr_reader :named_ranges # :nodoc:
30
+ attr_reader :doc_properties # :nodoc:
31
+ attr_reader :custom_properties # :nodoc:
32
+ attr_reader :image_types, :images # :nodoc:
33
+ attr_reader :shared_strings # :nodoc:
34
+ attr_reader :vba_project # :nodoc:
35
+ attr_reader :excel2003_style # :nodoc:
36
+ attr_reader :max_url_length # :nodoc:
37
+ attr_reader :strings_to_urls # :nodoc:
38
+ attr_reader :default_url_format # :nodoc:
39
+ attr_reader :read_only # :nodoc:
55
40
 
56
- #
57
- # A new Excel workbook is created using the +new+ constructor
58
- # which accepts either a filename or an IO object as a parameter.
59
- # The following example creates a new Excel file based on a filename:
60
- #
61
- # workbook = WriteXLSX.new('filename.xlsx')
62
- # worksheet = workbook.add_worksheet
63
- # worksheet.write(0, 0, 'Hi Excel!')
64
- # workbook.close
65
- #
66
- # Here are some other examples of using +new+ with filenames:
67
- #
68
- # workbook1 = WriteXLSX.new(filename)
69
- # workbook2 = WriteXLSX.new('/tmp/filename.xlsx')
70
- # workbook3 = WriteXLSX.new("c:\\tmp\\filename.xlsx")
71
- # workbook4 = WriteXLSX.new('c:\tmp\filename.xlsx')
72
- #
73
- # The last two examples demonstrates how to create a file on DOS or Windows
74
- # where it is necessary to either escape the directory separator \
75
- # or to use single quotes to ensure that it isn't interpolated.
76
- #
77
- # It is recommended that the filename uses the extension .xlsx
78
- # rather than .xls since the latter causes an Excel warning
79
- # when used with the XLSX format.
80
- #
81
- # The +new+ constructor returns a WriteXLSX object that you can use to
82
- # add worksheets and store data.
83
- #
84
- # You can also pass a valid IO object to the +new+ constructor.
85
- #
86
- # xlsx = StringIO.new
87
- # workbook = WriteXLSX.new(xlsx)
88
- # ....
89
- # workbook.close
90
- # # you can get XLSX binary data as xlsx.string
91
- #
92
- # And you can pass default_formats parameter like this:
93
- #
94
- # formats = { :font => 'Arial', :size => 10.5 }
95
- # workbook = WriteXLSX.new('file.xlsx', formats)
96
- #
97
41
  def initialize(file, *option_params)
98
42
  options, default_formats = process_workbook_options(*option_params)
99
43
  @writer = Package::XMLWriterSimple.new
@@ -133,6 +77,8 @@ module Writexlsx
133
77
 
134
78
  @max_url_length = 2079
135
79
  @has_comments = false
80
+ @read_only = 0
81
+ @has_metadata = false
136
82
  if options[:max_url_length]
137
83
  @max_url_length = options[:max_url_length]
138
84
 
@@ -147,8 +93,13 @@ module Writexlsx
147
93
  @calc_on_load = true
148
94
 
149
95
  if @excel2003_style
150
- add_format(default_formats
151
- .merge(:xf_index => 0, :font_family => 0, :font => 'Arial', :size => 10, :theme => -1))
96
+ add_format(default_formats.merge(
97
+ :xf_index => 0,
98
+ :font_family => 0,
99
+ :font => 'Arial',
100
+ :size => 10,
101
+ :theme => -1
102
+ ))
152
103
  else
153
104
  add_format(default_formats.merge(:xf_index => 0))
154
105
  end
@@ -162,13 +113,6 @@ module Writexlsx
162
113
  #
163
114
  # The close method is used to close an Excel file.
164
115
  #
165
- # An explicit close is required if the file must be closed prior to performing
166
- # some external action on it such as copying it, reading its size or attaching
167
- # it to an email.
168
- #
169
- # In general, if you create a file with a size of 0 bytes or you fail to create
170
- # a file you need to call close.
171
- #
172
116
  def close
173
117
  # In case close() is called twice.
174
118
  return if @fileclosed
@@ -184,32 +128,6 @@ module Writexlsx
184
128
  # sheets -> array of all Wordsheet object
185
129
  # sheets(1, 3, 4) -> array of spcified Worksheet object.
186
130
  #
187
- # The sheets method returns a array, or a sliced array, of the worksheets
188
- # in a workbook.
189
- #
190
- # If no arguments are passed the method returns a list of all the worksheets
191
- # in the workbook. This is useful if you want to repeat an operation on each
192
- # worksheet:
193
- #
194
- # workbook.sheets.each do |worksheet|
195
- # print worksheet.get_name
196
- # end
197
- #
198
- # You can also specify a slice list to return one or more worksheet objects:
199
- #
200
- # worksheet = workbook.sheets(0)
201
- # worksheet.write('A1', 'Hello')
202
- #
203
- # you can write the above example as:
204
- #
205
- # workbook.sheets(0).write('A1', 'Hello')
206
- #
207
- # The following example returns the first and last worksheet in a workbook:
208
- #
209
- # workbook.sheets(0, -1).each do |sheet|
210
- # # Do something
211
- # end
212
- #
213
131
  def sheets(*args)
214
132
  if args.empty?
215
133
  @worksheets
@@ -229,20 +147,6 @@ module Writexlsx
229
147
  #
230
148
  # Set the date system: false = 1900 (the default), true = 1904
231
149
  #
232
- # Excel stores dates as real numbers where the integer part stores
233
- # the number of days since the epoch and the fractional part stores
234
- # the percentage of the day. The epoch can be either 1900 or 1904.
235
- # Excel for Windows uses 1900 and Excel for Macintosh uses 1904.
236
- # However, Excel on either platform will convert automatically between
237
- # one system and the other.
238
- #
239
- # WriteXLSX stores dates in the 1900 format by default. If you wish to
240
- # change this you can call the set_1904 workbook method.
241
- # You can query the current value by calling the get_1904 workbook method.
242
- # This returns false for 1900 and true for 1904.
243
- #
244
- # In general you probably won't need to use set_1904.
245
- #
246
150
  def set_1904(mode = true)
247
151
  unless sheets.empty?
248
152
  raise "set_1904() must be called before add_worksheet()"
@@ -292,6 +196,9 @@ module Writexlsx
292
196
  # Write the XLSX file version.
293
197
  write_file_version
294
198
 
199
+ # Write the fileSharing element.
200
+ write_file_sharing
201
+
295
202
  # Write the workbook properties.
296
203
  write_workbook_pr
297
204
 
@@ -316,20 +223,6 @@ module Writexlsx
316
223
  #
317
224
  # At least one worksheet should be added to a new workbook. A worksheet is used to write data into cells:
318
225
  #
319
- # worksheet1 = workbook.add_worksheet # Sheet1
320
- # worksheet2 = workbook.add_worksheet('Foglio2') # Foglio2
321
- # worksheet3 = workbook.add_worksheet('Data') # Data
322
- # worksheet4 = workbook.add_worksheet # Sheet4
323
- # If name is not specified the default Excel convention will be followed, i.e. Sheet1, Sheet2, etc.
324
- #
325
- # The worksheet name must be a valid Excel worksheet name,
326
- # i.e. it cannot contain any of the following characters,
327
- # [ ] : * ? / \
328
- #
329
- # and it must be less than 32 characters.
330
- # In addition, you cannot use the same, case insensitive,
331
- # sheetname for more than one worksheet.
332
- #
333
226
  def add_worksheet(name = '')
334
227
  name = check_sheetname(name)
335
228
  worksheet = Worksheet.new(self, @worksheets.size, name)
@@ -340,72 +233,7 @@ module Writexlsx
340
233
  #
341
234
  # This method is use to create a new chart either as a standalone worksheet
342
235
  # (the default) or as an embeddable object that can be inserted into
343
- # a worksheet via the
344
- # {Worksheet#insert_chart}[Worksheet.html#method-i-insert_chart] method.
345
- #
346
- # chart = workbook.add_chart(:type => 'column')
347
- #
348
- # The properties that can be set are:
349
- #
350
- # :type (required)
351
- # :subtype (optional)
352
- # :name (optional)
353
- # :embedded (optional)
354
- #
355
- # === :type
356
- #
357
- # This is a required parameter.
358
- # It defines the type of chart that will be created.
359
- #
360
- # chart = workbook.add_chart(:type => 'line')
361
- #
362
- # The available types are:
363
- #
364
- # area
365
- # bar
366
- # column
367
- # line
368
- # pie
369
- # scatter
370
- # stock
371
- #
372
- # === :subtype
373
- #
374
- # Used to define a chart subtype where available.
375
- #
376
- # chart = workbook.add_chart(:type => 'bar', :subtype => 'stacked')
377
- #
378
- # Currently only Bar and Column charts support subtypes
379
- # (stacked and percent_stacked). See the documentation for those chart
380
- # types.
381
- #
382
- # === :name
383
- #
384
- # Set the name for the chart sheet. The name property is optional and
385
- # if it isn't supplied will default to Chart1 .. n. The name must be
386
- # a valid Excel worksheet name. See add_worksheet
387
- # for more details on valid sheet names. The name property can be
388
- # omitted for embedded charts.
389
- #
390
- # chart = workbook.add_chart(:type => 'line', :name => 'Results Chart')
391
- #
392
- # === :embedded
393
- #
394
- # Specifies that the Chart object will be inserted in a worksheet
395
- # via the {Worksheet#insert_chart}[Worksheet.html#insert_chart] method.
396
- # It is an error to try insert a Chart that doesn't have this flag set.
397
- #
398
- # chart = workbook.add_chart(:type => 'line', :embedded => 1)
399
- #
400
- # # Configure the chart.
401
- # ...
402
- #
403
- # # Insert the chart into the a worksheet.
404
- # worksheet.insert_chart('E2', chart)
405
- #
406
- # See Chart[Chart.html] for details on how to configure the chart object
407
- # once it is created. See also the chart_*.rb programs in the examples
408
- # directory of the distro.
236
+ # a worksheet via the insert_chart method.
409
237
  #
410
238
  def add_chart(params = {})
411
239
  # Type must be specified so we can create the required chart instance.
@@ -437,7 +265,7 @@ module Writexlsx
437
265
  end
438
266
 
439
267
  #
440
- # The +add_format+ method can be used to create new Format objects
268
+ # The add_format method can be used to create new Format objects
441
269
  # which are used to apply formatting to a cell. You can either define
442
270
  # the properties at creation time via a hash of property values
443
271
  # or later via method calls.
@@ -445,9 +273,6 @@ module Writexlsx
445
273
  # format1 = workbook.add_format(property_hash) # Set properties at creation
446
274
  # format2 = workbook.add_format # Set properties later
447
275
  #
448
- # See the {Format Class's rdoc}[Format.html] for more details about
449
- # Format properties and how to set them.
450
- #
451
276
  def add_format(property_hash = {})
452
277
  properties = {}
453
278
  if @excel2003_style
@@ -466,236 +291,6 @@ module Writexlsx
466
291
  # The +add_shape+ method can be used to create new shapes that may be
467
292
  # inserted into a worksheet.
468
293
  #
469
- # You can either define the properties at creation time via a hash of
470
- # property values or later via method calls.
471
- #
472
- # # Set properties at creation.
473
- # plus = workbook.add_shape(
474
- # :type => 'plus',
475
- # :id => 3,
476
- # :width => pw,
477
- # :height => ph
478
- # )
479
- #
480
- # # Default rectangle shape. Set properties later.
481
- # rect = workbook.add_shape
482
- #
483
- # See also the shape*.rb programs in the examples directory of the distro.
484
- #
485
- # === Shape Properties
486
- #
487
- # Any shape property can be queried or modified by [ ] like hash.
488
- #
489
- # ellipse = workbook.add_shape(properties)
490
- # ellipse[:type] = 'cross' # No longer an ellipse !
491
- # type = ellipse[:type] # Find out what it really is.
492
- #
493
- # The properties of a shape object that can be defined via add_shape are
494
- # shown below.
495
- #
496
- # ===:name
497
- #
498
- # Defines the name of the shape. This is an optional property and the shape
499
- # will be given a default name if not supplied. The name is generally only
500
- # used by Excel Macros to refer to the object.
501
- #
502
- # ===:type
503
- #
504
- # Defines the type of the object such as +:rect+, +:ellipse+ OR +:triangle+.
505
- #
506
- # ellipse = workbook.add_shape(:type => :ellipse)
507
- #
508
- # The default type is +:rect+.
509
- #
510
- # The full list of available shapes is shown below.
511
- #
512
- # See also the shape_all.rb program in the examples directory of the distro.
513
- # It creates an example workbook with all supported shapes labelled with
514
- # their shape names.
515
- #
516
- # === Basic Shapes
517
- #
518
- # blockArc can chevron cube decagon
519
- # diamond dodecagon donut ellipse funnel
520
- # gear6 gear9 heart heptagon hexagon
521
- # homePlate lightningBolt line lineInv moon
522
- # nonIsoscelesTrapezoid noSmoking octagon parallelogram pentagon
523
- # pie pieWedge plaque rect round1Rect
524
- # round2DiagRect round2SameRect roundRect rtTriangle smileyFace
525
- # snip1Rect snip2DiagRect snip2SameRect snipRoundRect star10
526
- # star12 star16 star24 star32 star4
527
- # star5 star6 star7 star8 sun
528
- # teardrop trapezoid triangle
529
- #
530
- # === Arrow Shapes
531
- #
532
- # bentArrow bentUpArrow circularArrow curvedDownArrow
533
- # curvedLeftArrow curvedRightArrow curvedUpArrow downArrow
534
- # leftArrow leftCircularArrow leftRightArrow leftRightCircularArrow
535
- # leftRightUpArrow leftUpArrow notchedRightArrow quadArrow
536
- # rightArrow stripedRightArrow swooshArrow upArrow
537
- # upDownArrow uturnArrow
538
- #
539
- # === Connector Shapes
540
- #
541
- # bentConnector2 bentConnector3 bentConnector4
542
- # bentConnector5 curvedConnector2 curvedConnector3
543
- # curvedConnector4 curvedConnector5 straightConnector1
544
- #
545
- # === Callout Shapes
546
- #
547
- # accentBorderCallout1 accentBorderCallout2 accentBorderCallout3
548
- # accentCallout1 accentCallout2 accentCallout3
549
- # borderCallout1 borderCallout2 borderCallout3
550
- # callout1 callout2 callout3
551
- # cloudCallout downArrowCallout leftArrowCallout
552
- # leftRightArrowCallout quadArrowCallout rightArrowCallout
553
- # upArrowCallout upDownArrowCallout wedgeEllipseCallout
554
- # wedgeRectCallout wedgeRoundRectCallout
555
- #
556
- # === Flow Chart Shapes
557
- #
558
- # flowChartAlternateProcess flowChartCollate flowChartConnector
559
- # flowChartDecision flowChartDelay flowChartDisplay
560
- # flowChartDocument flowChartExtract flowChartInputOutput
561
- # flowChartInternalStorage flowChartMagneticDisk flowChartMagneticDrum
562
- # flowChartMagneticTape flowChartManualInput flowChartManualOperation
563
- # flowChartMerge flowChartMultidocument flowChartOfflineStorage
564
- # flowChartOffpageConnector flowChartOnlineStorage flowChartOr
565
- # flowChartPredefinedProcess flowChartPreparation flowChartProcess
566
- # flowChartPunchedCard flowChartPunchedTape flowChartSort
567
- # flowChartSummingJunction flowChartTerminator
568
- #
569
- # === Action Shapes
570
- #
571
- # actionButtonBackPrevious actionButtonBeginning actionButtonBlank
572
- # actionButtonDocument actionButtonEnd actionButtonForwardNext
573
- # actionButtonHelp actionButtonHome actionButtonInformation
574
- # actionButtonMovie actionButtonReturn actionButtonSound
575
- #
576
- # === Chart Shapes
577
- #
578
- # Not to be confused with Excel Charts.
579
- #
580
- # chartPlus chartStar chartX
581
- #
582
- # === Math Shapes
583
- #
584
- # mathDivide mathEqual mathMinus mathMultiply mathNotEqual mathPlus
585
- #
586
- # === Starts and Banners
587
- #
588
- # arc bevel bracePair bracketPair chord
589
- # cloud corner diagStripe doubleWave ellipseRibbon
590
- # ellipseRibbon2 foldedCorner frame halfFrame horizontalScroll
591
- # irregularSeal1 irregularSeal2 leftBrace leftBracket leftRightRibbon
592
- # plus ribbon ribbon2 rightBrace rightBracket
593
- # verticalScroll wave
594
- #
595
- # === Tab Shapes
596
- #
597
- # cornerTabs plaqueTabs squareTabs
598
- #
599
- # === :text
600
- #
601
- # This property is used to make the shape act like a text box.
602
- #
603
- # rect = workbook.add_shape(:type => 'rect', :text => "Hello \nWorld")
604
- #
605
- # The Text is super-imposed over the shape. The text can be wrapped using
606
- # the newline character \n.
607
- #
608
- # === :id
609
- #
610
- # Identification number for internal identification. This number will be
611
- # auto-assigned, if not assigned, or if it is a duplicate.
612
- #
613
- # === :format
614
- #
615
- # Workbook format for decorating the shape horizontally and/or vertically.
616
- #
617
- # === :rotation
618
- #
619
- # Shape rotation, in degrees, from 0 to 360
620
- #
621
- # === :line, :fill
622
- #
623
- # Shape color for the outline and fill.
624
- # Colors may be specified as a color index, or in RGB format, i.e. AA00FF.
625
- #
626
- # See COULOURS IN EXCEL in the main documentation for more information.
627
- #
628
- # === :link_type
629
- #
630
- # Line type for shape outline. The default is solid.
631
- # The list of possible values is:
632
- #
633
- # dash, sysDot, dashDot, lgDash, lgDashDot, lgDashDotDot, solid
634
- #
635
- # === :valign, :align
636
- #
637
- # Text alignment within the shape.
638
- #
639
- # Vertical alignment can be:
640
- #
641
- # Setting Meaning
642
- # ======= =======
643
- # t Top
644
- # ctr Centre
645
- # b Bottom
646
- #
647
- # Horizontal alignment can be:
648
- #
649
- # Setting Meaning
650
- # ======= =======
651
- # l Left
652
- # r Right
653
- # ctr Centre
654
- # just Justified
655
- #
656
- # The default is to center both horizontally and vertically.
657
- #
658
- # === :scale_x, :scale_y
659
- #
660
- # Scale factor in x and y dimension, for scaling the shape width and
661
- # height. The default value is 1.
662
- #
663
- # Scaling may be set on the shape object or via insert_shape.
664
- #
665
- # === :adjustments
666
- #
667
- # Adjustment of shape vertices. Most shapes do not use this. For some
668
- # shapes, there is a single adjustment to modify the geometry.
669
- # For instance, the plus shape has one adjustment to control the width
670
- # of the spokes.
671
- #
672
- # Connectors can have a number of adjustments to control the shape
673
- # routing. Typically, a connector will have 3 to 5 handles for routing
674
- # the shape. The adjustment is in percent of the distance from the
675
- # starting shape to the ending shape, alternating between the x and y
676
- # dimension. Adjustments may be negative, to route the shape away
677
- # from the endpoint.
678
- #
679
- # === :stencil
680
- #
681
- # Shapes work in stencil mode by default. That is, once a shape is
682
- # inserted, its connection is separated from its master.
683
- # The master shape may be modified after an instance is inserted,
684
- # and only subsequent insertions will show the modifications.
685
- #
686
- # This is helpful for Org charts, where an employee shape may be
687
- # created once, and then the text of the shape is modified for each
688
- # employee.
689
- #
690
- # The insert_shape method returns a reference to the inserted
691
- # shape (the child).
692
- #
693
- # Stencil mode can be turned off, allowing for shape(s) to be
694
- # modified after insertion. In this case the insert_shape() method
695
- # returns a reference to the inserted shape (the master).
696
- # This is not very useful for inserting multiple shapes,
697
- # since the x/y coordinates also gets modified.
698
- #
699
294
  def add_shape(properties = {})
700
295
  shape = Shape.new(properties)
701
296
  shape.palette = @palette
@@ -709,31 +304,6 @@ module Writexlsx
709
304
  # Create a defined name in Excel. We handle global/workbook level names and
710
305
  # local/worksheet names.
711
306
  #
712
- # This method is used to defined a name that can be used to represent
713
- # a value, a single cell or a range of cells in a workbook.
714
- #
715
- # For example to set a global/workbook name:
716
- #
717
- # # Global/workbook names.
718
- # workbook.define_name('Exchange_rate', '=0.96')
719
- # workbook.define_name('Sales', '=Sheet1!$G$1:$H$10')
720
- #
721
- # It is also possible to define a local/worksheet name by prefixing the name
722
- # with the sheet name using the syntax +sheetname!definedname+:
723
- #
724
- # # Local/worksheet name.
725
- # workbook.define_name('Sheet2!Sales', '=Sheet2!$G$1:$G$10')
726
- #
727
- # If the sheet name contains spaces or special characters
728
- # you must enclose it in single quotes like in Excel:
729
- #
730
- # workbook.define_name("'New Data'!Sales", '=Sheet2!$G$1:$G$10')
731
- #
732
- # See the defined_name.rb program in the examples dir of the distro.
733
- #
734
- # Refer to the following to see Excel's syntax rules for defined names:
735
- # <http://office.microsoft.com/en-001/excel-help/define-and-use-names-in-formulas-HA010147120.aspx#BMsyntax_rules_for_names>
736
- #
737
307
  def define_name(name, formula)
738
308
  sheet_index = nil
739
309
  sheetname = ''
@@ -812,29 +382,6 @@ module Writexlsx
812
382
  # and are also available to external applications that read or index windows
813
383
  # files.
814
384
  #
815
- # The properties should be passed in hash format as follows:
816
- #
817
- # workbook.set_properties(
818
- # :title => 'This is an example spreadsheet',
819
- # :author => 'Hideo NAKAMURA',
820
- # :comments => 'Created with Ruby and WriteXLSX'
821
- # )
822
- #
823
- # The properties that can be set are:
824
- #
825
- # :title
826
- # :subject
827
- # :author
828
- # :manager
829
- # :company
830
- # :category
831
- # :keywords
832
- # :comments
833
- # :status
834
- #
835
- # See also the properties.rb program in the examples directory
836
- # of the distro.
837
- #
838
385
  def set_properties(params)
839
386
  # Ignore if no args were passed.
840
387
  return -1 if params.empty?
@@ -918,27 +465,6 @@ module Writexlsx
918
465
  # WriteXLSX file using a binary VBA project file that has been extracted
919
466
  # from an existing Excel xlsm file.
920
467
  #
921
- # workbook = WriteXLSX.new('file.xlsm')
922
- #
923
- # workbook.add_vba_project('./vbaProject.bin')
924
- #
925
- # The supplied +extract_vba+ utility can be used to extract the required
926
- # +vbaProject.bin+ file from an existing Excel file:
927
- #
928
- # $ extract_vba file.xlsm
929
- # Extracted 'vbaProject.bin' successfully
930
- #
931
- # Macros can be tied to buttons using the worksheet
932
- # {insert_button}[Worksheet.html#method-i-insert_button] method
933
- # (see the "WORKSHEET METHODS" section for details):
934
- #
935
- # worksheet.insert_button('C2', { :macro => 'my_macro' })
936
- #
937
- # Note, Excel uses the file extension xlsm instead of xlsx for files that
938
- # contain macros. It is advisable to follow the same convention.
939
- #
940
- # See also the macros.rb example file.
941
- #
942
468
  def add_vba_project(vba_project)
943
469
  @vba_project = vba_project
944
470
  end
@@ -954,6 +480,13 @@ module Writexlsx
954
480
  end
955
481
  end
956
482
 
483
+ #
484
+ # Set the Excel "Read-only recommended" save option.
485
+ #
486
+ def read_only_recommended
487
+ @read_only = 2
488
+ end
489
+
957
490
  #
958
491
  # set_calc_mode()
959
492
  #
@@ -984,60 +517,6 @@ module Writexlsx
984
517
  #
985
518
  # Change the RGB components of the elements in the colour palette.
986
519
  #
987
- # The set_custom_color method can be used to override one of the built-in
988
- # palette values with a more suitable colour.
989
- #
990
- # The value for +index+ should be in the range 8..63,
991
- # see "COLOURS IN EXCEL".
992
- #
993
- # The default named colours use the following indices:
994
- #
995
- # 8 => black
996
- # 9 => white
997
- # 10 => red
998
- # 11 => lime
999
- # 12 => blue
1000
- # 13 => yellow
1001
- # 14 => magenta
1002
- # 15 => cyan
1003
- # 16 => brown
1004
- # 17 => green
1005
- # 18 => navy
1006
- # 20 => purple
1007
- # 22 => silver
1008
- # 23 => gray
1009
- # 33 => pink
1010
- # 53 => orange
1011
- #
1012
- # A new colour is set using its RGB (red green blue) components. The +red+,
1013
- # +green+ and +blue+ values must be in the range 0..255. You can determine
1014
- # the required values in Excel using the Tools->Options->Colors->Modify
1015
- # dialog.
1016
- #
1017
- # The set_custom_color workbook method can also be used with a HTML style
1018
- # +#rrggbb+ hex value:
1019
- #
1020
- # workbook.set_custom_color(40, 255, 102, 0 ) # Orange
1021
- # workbook.set_custom_color(40, 0xFF, 0x66, 0x00) # Same thing
1022
- # workbook.set_custom_color(40, '#FF6600' ) # Same thing
1023
- #
1024
- # font = workbook.add_format(:color => 40) # Use the modified colour
1025
- #
1026
- # The return value from set_custom_color() is the index of the colour that
1027
- # was changed:
1028
- #
1029
- # ferrari = workbook.set_custom_color(40, 216, 12, 12)
1030
- #
1031
- # format = workbook.add_format(
1032
- # :bg_color => ferrari,
1033
- # :pattern => 1,
1034
- # :border => 1
1035
- # )
1036
- #
1037
- # Note, In the XLSX format the color palette isn't actually confined to 53
1038
- # unique colors. The WriteXLSX gem will be extended at a later stage to
1039
- # support the newer, semi-infinite, palette.
1040
- #
1041
520
  def set_custom_color(index, red = 0, green = 0, blue = 0)
1042
521
  # Match a HTML #xxyyzz style parameter
1043
522
  if red.to_s =~ /^#(\w\w)(\w\w)(\w\w)/
@@ -1109,15 +588,15 @@ module Writexlsx
1109
588
 
1110
589
  def style_properties
1111
590
  [
1112
- @xf_formats,
1113
- @palette,
1114
- @font_count,
1115
- @num_format_count,
1116
- @border_count,
1117
- @fill_count,
1118
- @custom_colors,
1119
- @dxf_formats,
1120
- @has_comments
591
+ @xf_formats,
592
+ @palette,
593
+ @font_count,
594
+ @num_format_count,
595
+ @border_count,
596
+ @fill_count,
597
+ @custom_colors,
598
+ @dxf_formats,
599
+ @has_comments
1121
600
  ]
1122
601
  end
1123
602
 
@@ -1145,6 +624,10 @@ module Writexlsx
1145
624
  @activesheet ||= 0
1146
625
  end
1147
626
 
627
+ def has_metadata?
628
+ @has_metadata
629
+ end
630
+
1148
631
  private
1149
632
 
1150
633
  def filename
@@ -1178,63 +661,63 @@ module Writexlsx
1178
661
  #
1179
662
  def set_color_palette #:nodoc:
1180
663
  @palette = [
1181
- [ 0x00, 0x00, 0x00, 0x00 ], # 8
1182
- [ 0xff, 0xff, 0xff, 0x00 ], # 9
1183
- [ 0xff, 0x00, 0x00, 0x00 ], # 10
1184
- [ 0x00, 0xff, 0x00, 0x00 ], # 11
1185
- [ 0x00, 0x00, 0xff, 0x00 ], # 12
1186
- [ 0xff, 0xff, 0x00, 0x00 ], # 13
1187
- [ 0xff, 0x00, 0xff, 0x00 ], # 14
1188
- [ 0x00, 0xff, 0xff, 0x00 ], # 15
1189
- [ 0x80, 0x00, 0x00, 0x00 ], # 16
1190
- [ 0x00, 0x80, 0x00, 0x00 ], # 17
1191
- [ 0x00, 0x00, 0x80, 0x00 ], # 18
1192
- [ 0x80, 0x80, 0x00, 0x00 ], # 19
1193
- [ 0x80, 0x00, 0x80, 0x00 ], # 20
1194
- [ 0x00, 0x80, 0x80, 0x00 ], # 21
1195
- [ 0xc0, 0xc0, 0xc0, 0x00 ], # 22
1196
- [ 0x80, 0x80, 0x80, 0x00 ], # 23
1197
- [ 0x99, 0x99, 0xff, 0x00 ], # 24
1198
- [ 0x99, 0x33, 0x66, 0x00 ], # 25
1199
- [ 0xff, 0xff, 0xcc, 0x00 ], # 26
1200
- [ 0xcc, 0xff, 0xff, 0x00 ], # 27
1201
- [ 0x66, 0x00, 0x66, 0x00 ], # 28
1202
- [ 0xff, 0x80, 0x80, 0x00 ], # 29
1203
- [ 0x00, 0x66, 0xcc, 0x00 ], # 30
1204
- [ 0xcc, 0xcc, 0xff, 0x00 ], # 31
1205
- [ 0x00, 0x00, 0x80, 0x00 ], # 32
1206
- [ 0xff, 0x00, 0xff, 0x00 ], # 33
1207
- [ 0xff, 0xff, 0x00, 0x00 ], # 34
1208
- [ 0x00, 0xff, 0xff, 0x00 ], # 35
1209
- [ 0x80, 0x00, 0x80, 0x00 ], # 36
1210
- [ 0x80, 0x00, 0x00, 0x00 ], # 37
1211
- [ 0x00, 0x80, 0x80, 0x00 ], # 38
1212
- [ 0x00, 0x00, 0xff, 0x00 ], # 39
1213
- [ 0x00, 0xcc, 0xff, 0x00 ], # 40
1214
- [ 0xcc, 0xff, 0xff, 0x00 ], # 41
1215
- [ 0xcc, 0xff, 0xcc, 0x00 ], # 42
1216
- [ 0xff, 0xff, 0x99, 0x00 ], # 43
1217
- [ 0x99, 0xcc, 0xff, 0x00 ], # 44
1218
- [ 0xff, 0x99, 0xcc, 0x00 ], # 45
1219
- [ 0xcc, 0x99, 0xff, 0x00 ], # 46
1220
- [ 0xff, 0xcc, 0x99, 0x00 ], # 47
1221
- [ 0x33, 0x66, 0xff, 0x00 ], # 48
1222
- [ 0x33, 0xcc, 0xcc, 0x00 ], # 49
1223
- [ 0x99, 0xcc, 0x00, 0x00 ], # 50
1224
- [ 0xff, 0xcc, 0x00, 0x00 ], # 51
1225
- [ 0xff, 0x99, 0x00, 0x00 ], # 52
1226
- [ 0xff, 0x66, 0x00, 0x00 ], # 53
1227
- [ 0x66, 0x66, 0x99, 0x00 ], # 54
1228
- [ 0x96, 0x96, 0x96, 0x00 ], # 55
1229
- [ 0x00, 0x33, 0x66, 0x00 ], # 56
1230
- [ 0x33, 0x99, 0x66, 0x00 ], # 57
1231
- [ 0x00, 0x33, 0x00, 0x00 ], # 58
1232
- [ 0x33, 0x33, 0x00, 0x00 ], # 59
1233
- [ 0x99, 0x33, 0x00, 0x00 ], # 60
1234
- [ 0x99, 0x33, 0x66, 0x00 ], # 61
1235
- [ 0x33, 0x33, 0x99, 0x00 ], # 62
1236
- [ 0x33, 0x33, 0x33, 0x00 ], # 63
1237
- ]
664
+ [ 0x00, 0x00, 0x00, 0x00 ], # 8
665
+ [ 0xff, 0xff, 0xff, 0x00 ], # 9
666
+ [ 0xff, 0x00, 0x00, 0x00 ], # 10
667
+ [ 0x00, 0xff, 0x00, 0x00 ], # 11
668
+ [ 0x00, 0x00, 0xff, 0x00 ], # 12
669
+ [ 0xff, 0xff, 0x00, 0x00 ], # 13
670
+ [ 0xff, 0x00, 0xff, 0x00 ], # 14
671
+ [ 0x00, 0xff, 0xff, 0x00 ], # 15
672
+ [ 0x80, 0x00, 0x00, 0x00 ], # 16
673
+ [ 0x00, 0x80, 0x00, 0x00 ], # 17
674
+ [ 0x00, 0x00, 0x80, 0x00 ], # 18
675
+ [ 0x80, 0x80, 0x00, 0x00 ], # 19
676
+ [ 0x80, 0x00, 0x80, 0x00 ], # 20
677
+ [ 0x00, 0x80, 0x80, 0x00 ], # 21
678
+ [ 0xc0, 0xc0, 0xc0, 0x00 ], # 22
679
+ [ 0x80, 0x80, 0x80, 0x00 ], # 23
680
+ [ 0x99, 0x99, 0xff, 0x00 ], # 24
681
+ [ 0x99, 0x33, 0x66, 0x00 ], # 25
682
+ [ 0xff, 0xff, 0xcc, 0x00 ], # 26
683
+ [ 0xcc, 0xff, 0xff, 0x00 ], # 27
684
+ [ 0x66, 0x00, 0x66, 0x00 ], # 28
685
+ [ 0xff, 0x80, 0x80, 0x00 ], # 29
686
+ [ 0x00, 0x66, 0xcc, 0x00 ], # 30
687
+ [ 0xcc, 0xcc, 0xff, 0x00 ], # 31
688
+ [ 0x00, 0x00, 0x80, 0x00 ], # 32
689
+ [ 0xff, 0x00, 0xff, 0x00 ], # 33
690
+ [ 0xff, 0xff, 0x00, 0x00 ], # 34
691
+ [ 0x00, 0xff, 0xff, 0x00 ], # 35
692
+ [ 0x80, 0x00, 0x80, 0x00 ], # 36
693
+ [ 0x80, 0x00, 0x00, 0x00 ], # 37
694
+ [ 0x00, 0x80, 0x80, 0x00 ], # 38
695
+ [ 0x00, 0x00, 0xff, 0x00 ], # 39
696
+ [ 0x00, 0xcc, 0xff, 0x00 ], # 40
697
+ [ 0xcc, 0xff, 0xff, 0x00 ], # 41
698
+ [ 0xcc, 0xff, 0xcc, 0x00 ], # 42
699
+ [ 0xff, 0xff, 0x99, 0x00 ], # 43
700
+ [ 0x99, 0xcc, 0xff, 0x00 ], # 44
701
+ [ 0xff, 0x99, 0xcc, 0x00 ], # 45
702
+ [ 0xcc, 0x99, 0xff, 0x00 ], # 46
703
+ [ 0xff, 0xcc, 0x99, 0x00 ], # 47
704
+ [ 0x33, 0x66, 0xff, 0x00 ], # 48
705
+ [ 0x33, 0xcc, 0xcc, 0x00 ], # 49
706
+ [ 0x99, 0xcc, 0x00, 0x00 ], # 50
707
+ [ 0xff, 0xcc, 0x00, 0x00 ], # 51
708
+ [ 0xff, 0x99, 0x00, 0x00 ], # 52
709
+ [ 0xff, 0x66, 0x00, 0x00 ], # 53
710
+ [ 0x66, 0x66, 0x99, 0x00 ], # 54
711
+ [ 0x96, 0x96, 0x96, 0x00 ], # 55
712
+ [ 0x00, 0x33, 0x66, 0x00 ], # 56
713
+ [ 0x33, 0x99, 0x66, 0x00 ], # 57
714
+ [ 0x00, 0x33, 0x00, 0x00 ], # 58
715
+ [ 0x33, 0x33, 0x00, 0x00 ], # 59
716
+ [ 0x99, 0x33, 0x00, 0x00 ], # 60
717
+ [ 0x99, 0x33, 0x66, 0x00 ], # 61
718
+ [ 0x33, 0x33, 0x99, 0x00 ], # 62
719
+ [ 0x33, 0x33, 0x33, 0x00 ], # 63
720
+ ]
1238
721
  end
1239
722
 
1240
723
  #
@@ -1298,11 +781,11 @@ module Writexlsx
1298
781
 
1299
782
  def write_file_version #:nodoc:
1300
783
  attributes = [
1301
- ['appName', 'xl'],
1302
- ['lastEdited', 4],
1303
- ['lowestEdited', 4],
1304
- ['rupBuild', 4505]
1305
- ]
784
+ ['appName', 'xl'],
785
+ ['lastEdited', 4],
786
+ ['lowestEdited', 4],
787
+ ['rupBuild', 4505]
788
+ ]
1306
789
 
1307
790
  if @vba_project
1308
791
  attributes << [:codeName, '{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}']
@@ -1311,6 +794,17 @@ module Writexlsx
1311
794
  @writer.empty_tag('fileVersion', attributes)
1312
795
  end
1313
796
 
797
+ #
798
+ # Write the <fileSharing> element.
799
+ #
800
+ def write_file_sharing
801
+ return if !ptrue?(@read_only)
802
+
803
+ attributes = []
804
+ attributes << ['readOnlyRecommended', 1]
805
+ @writer.empty_tag('fileSharing', attributes)
806
+ end
807
+
1314
808
  def write_workbook_pr #:nodoc:
1315
809
  attributes = []
1316
810
  attributes << ['codeName', @vba_codename] if ptrue?(@vba_codename)
@@ -1325,11 +819,11 @@ module Writexlsx
1325
819
 
1326
820
  def write_workbook_view #:nodoc:
1327
821
  attributes = [
1328
- ['xWindow', @x_window],
1329
- ['yWindow', @y_window],
1330
- ['windowWidth', @window_width],
1331
- ['windowHeight', @window_height]
1332
- ]
822
+ ['xWindow', @x_window],
823
+ ['yWindow', @y_window],
824
+ ['windowWidth', @window_width],
825
+ ['windowHeight', @window_height]
826
+ ]
1333
827
  if @tab_ratio != 600
1334
828
  attributes << ['tabRatio', @tab_ratio]
1335
829
  end
@@ -1427,6 +921,9 @@ module Writexlsx
1427
921
  # Prepare the worksheet tables.
1428
922
  prepare_tables
1429
923
 
924
+ # Prepare the metadata file links.
925
+ prepare_metadata
926
+
1430
927
  # Package the workbook.
1431
928
  packager = Package::Packager.new(self)
1432
929
  packager.set_package_dir(tempdir)
@@ -1662,20 +1159,20 @@ module Writexlsx
1662
1159
  # Check for Print Area settings.
1663
1160
  if sheet.autofilter_area
1664
1161
  @defined_names << [
1665
- '_xlnm._FilterDatabase',
1666
- sheet.index,
1667
- sheet.autofilter_area,
1668
- 1
1669
- ]
1162
+ '_xlnm._FilterDatabase',
1163
+ sheet.index,
1164
+ sheet.autofilter_area,
1165
+ 1
1166
+ ]
1670
1167
  end
1671
1168
 
1672
1169
  # Check for Print Area settings.
1673
1170
  if !sheet.print_area.empty?
1674
1171
  @defined_names << [
1675
- '_xlnm.Print_Area',
1676
- sheet.index,
1677
- sheet.print_area
1678
- ]
1172
+ '_xlnm.Print_Area',
1173
+ sheet.index,
1174
+ sheet.print_area
1175
+ ]
1679
1176
  end
1680
1177
 
1681
1178
  # Check for repeat rows/cols. aka, Print Titles.
@@ -1762,6 +1259,18 @@ module Writexlsx
1762
1259
  end
1763
1260
  end
1764
1261
 
1262
+ #
1263
+ # Set the metadata rel link.
1264
+ #
1265
+ def prepare_metadata
1266
+ @worksheets.each do |sheet|
1267
+ if sheet.has_dynamic_arrays?
1268
+ @has_metadata = true
1269
+ break
1270
+ end
1271
+ end
1272
+ end
1273
+
1765
1274
  #
1766
1275
  # Add "cached" data to charts to provide the numCache and strCache data for
1767
1276
  # series and title/axis ranges.
@@ -1918,16 +1427,18 @@ module Writexlsx
1918
1427
  ref_id = 0
1919
1428
  image_ids = {}
1920
1429
  header_image_ids = {}
1430
+ background_ids = {}
1921
1431
  @worksheets.each do |sheet|
1922
1432
  chart_count = sheet.charts.size
1923
1433
  image_count = sheet.images.size
1924
1434
  shape_count = sheet.shapes.size
1925
1435
  header_image_count = sheet.header_images.size
1926
1436
  footer_image_count = sheet.footer_images.size
1927
- has_drawings = false
1437
+ has_background = sheet.background_image.size
1438
+ has_drawings = false
1928
1439
 
1929
1440
  # Check that some image or drawing needs to be processed.
1930
- next if chart_count + image_count + shape_count + header_image_count + footer_image_count == 0
1441
+ next if chart_count + image_count + shape_count + header_image_count + footer_image_count + has_background == 0
1931
1442
 
1932
1443
  # Don't increase the drawing_id header/footer images.
1933
1444
  if chart_count + image_count + shape_count > 0
@@ -1935,6 +1446,23 @@ module Writexlsx
1935
1446
  has_drawings = true
1936
1447
  end
1937
1448
 
1449
+ # Prepare the background images.
1450
+ if ptrue?(has_background)
1451
+ filename = sheet.background_image
1452
+ type, width, height, name, x_dpi, y_dpi, md5 = get_image_properties(filename)
1453
+
1454
+ if background_ids[md5]
1455
+ ref_id = background_ids[md5]
1456
+ else
1457
+ image_ref_id += 1
1458
+ ref_id = image_ref_id
1459
+ background_ids[md5] = ref_id
1460
+ @images << [filename, type]
1461
+ end
1462
+
1463
+ sheet.prepare_background(ref_id, type)
1464
+ end
1465
+
1938
1466
  # Prepare the worksheet images.
1939
1467
  sheet.images.each_with_index do |image, index|
1940
1468
  filename = image[2]
@@ -2042,6 +1570,10 @@ module Writexlsx
2042
1570
  # Test for JPEG files.
2043
1571
  type, width, height, x_dpi, y_dpi = process_jpg(data, filename)
2044
1572
  @image_types[:jpeg] = 1
1573
+ elsif data.unpack('A4')[0] == 'GIF8'
1574
+ # Test for GIFs.
1575
+ type, width, height, x_dpi, y_dpi = process_gif(data, filename)
1576
+ @image_types[:gif] = 1
2045
1577
  elsif data.unpack('A2')[0] == 'BM'
2046
1578
  # Test for BMPs.
2047
1579
  type, width, height = process_bmp(data, filename)
@@ -2146,6 +1678,24 @@ module Writexlsx
2146
1678
  [type, width, height, x_dpi, y_dpi]
2147
1679
  end
2148
1680
 
1681
+ #
1682
+ # Extract width and height information from a GIF file.
1683
+ #
1684
+ def process_gif(data, filename)
1685
+ type = 'gif'
1686
+ x_dpi = 96
1687
+ y_dpi = 96
1688
+
1689
+ width = data[6, 2].unpack("v")[0]
1690
+ height = data[8, 2].unpack("v")[0]
1691
+
1692
+ if height.nil?
1693
+ raise "#{filename}: no size data found in gif image.\n"
1694
+ end
1695
+
1696
+ [type, width, height, x_dpi, y_dpi]
1697
+ end
1698
+
2149
1699
  # Extract width and height information from a BMP file.
2150
1700
  def process_bmp(data, filename) #:nodoc:
2151
1701
  type = 'bmp'