write_xlsx 1.07.0 → 1.09.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.
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'