write_xlsx 1.08.2 → 1.09.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/Changes +9 -0
  3. data/README.md +1 -1
  4. data/examples/background.rb +19 -0
  5. data/lib/write_xlsx/chart/axis.rb +3 -3
  6. data/lib/write_xlsx/chart/scatter.rb +0 -15
  7. data/lib/write_xlsx/chart/series.rb +1 -1
  8. data/lib/write_xlsx/chart.rb +28 -28
  9. data/lib/write_xlsx/chartsheet.rb +3 -3
  10. data/lib/write_xlsx/drawing.rb +39 -39
  11. data/lib/write_xlsx/format.rb +11 -179
  12. data/lib/write_xlsx/package/app.rb +2 -2
  13. data/lib/write_xlsx/package/button.rb +8 -8
  14. data/lib/write_xlsx/package/comments.rb +8 -8
  15. data/lib/write_xlsx/package/content_types.rb +18 -9
  16. data/lib/write_xlsx/package/core.rb +5 -5
  17. data/lib/write_xlsx/package/custom.rb +2 -2
  18. data/lib/write_xlsx/package/metadata.rb +159 -0
  19. data/lib/write_xlsx/package/packager.rb +21 -0
  20. data/lib/write_xlsx/package/shared_strings.rb +6 -6
  21. data/lib/write_xlsx/package/styles.rb +11 -11
  22. data/lib/write_xlsx/package/table.rb +23 -23
  23. data/lib/write_xlsx/package/theme.rb +1 -1
  24. data/lib/write_xlsx/package/vml.rb +43 -43
  25. data/lib/write_xlsx/shape.rb +17 -15
  26. data/lib/write_xlsx/sparkline.rb +340 -340
  27. data/lib/write_xlsx/utility.rb +4 -23
  28. data/lib/write_xlsx/version.rb +1 -1
  29. data/lib/write_xlsx/workbook.rb +171 -644
  30. data/lib/write_xlsx/worksheet/cell_data.rb +25 -3
  31. data/lib/write_xlsx/worksheet/data_validation.rb +20 -20
  32. data/lib/write_xlsx/worksheet/hyperlink.rb +4 -4
  33. data/lib/write_xlsx/worksheet/page_setup.rb +12 -12
  34. data/lib/write_xlsx/worksheet.rb +295 -4184
  35. data/test/perl_output/background.xlsx +0 -0
  36. data/test/regression/images/logo.gif +0 -0
  37. data/test/regression/images/logo.jpg +0 -0
  38. data/test/regression/images/red.gif +0 -0
  39. data/test/regression/test_background01.rb +23 -0
  40. data/test/regression/test_background02.rb +23 -0
  41. data/test/regression/test_background03.rb +24 -0
  42. data/test/regression/test_background04.rb +25 -0
  43. data/test/regression/test_background05.rb +25 -0
  44. data/test/regression/test_background06.rb +31 -0
  45. data/test/regression/test_background07.rb +37 -0
  46. data/test/regression/test_chart_axis47.rb +52 -0
  47. data/test/regression/test_chart_axis48.rb +53 -0
  48. data/test/regression/test_dynamic_array01.rb +25 -0
  49. data/test/regression/test_image56.rb +23 -0
  50. data/test/regression/test_image57.rb +23 -0
  51. data/test/regression/test_set_column10.rb +55 -0
  52. data/test/regression/test_set_column11.rb +48 -0
  53. data/test/regression/test_set_row01.rb +35 -0
  54. data/test/regression/test_set_row02.rb +35 -0
  55. data/test/regression/test_set_row03.rb +35 -0
  56. data/test/regression/test_set_row04.rb +35 -0
  57. data/test/regression/xlsx_files/background01.xlsx +0 -0
  58. data/test/regression/xlsx_files/background02.xlsx +0 -0
  59. data/test/regression/xlsx_files/background03.xlsx +0 -0
  60. data/test/regression/xlsx_files/background04.xlsx +0 -0
  61. data/test/regression/xlsx_files/background05.xlsx +0 -0
  62. data/test/regression/xlsx_files/background06.xlsx +0 -0
  63. data/test/regression/xlsx_files/background07.xlsx +0 -0
  64. data/test/regression/xlsx_files/chart_axis47.xlsx +0 -0
  65. data/test/regression/xlsx_files/chart_axis48.xlsx +0 -0
  66. data/test/regression/xlsx_files/dynamic_array01.xlsx +0 -0
  67. data/test/regression/xlsx_files/image56.xlsx +0 -0
  68. data/test/regression/xlsx_files/image57.xlsx +0 -0
  69. data/test/regression/xlsx_files/set_row01.xlsx +0 -0
  70. data/test/regression/xlsx_files/set_row03.xlsx +0 -0
  71. data/test/test_example_match.rb +12 -0
  72. data/test/worksheet/test_pixels_to_row_col.rb +46 -0
  73. metadata +78 -2
@@ -19,82 +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:
55
- attr_reader :read_only # :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:
56
40
 
57
- #
58
- # A new Excel workbook is created using the +new+ constructor
59
- # which accepts either a filename or an IO object as a parameter.
60
- # The following example creates a new Excel file based on a filename:
61
- #
62
- # workbook = WriteXLSX.new('filename.xlsx')
63
- # worksheet = workbook.add_worksheet
64
- # worksheet.write(0, 0, 'Hi Excel!')
65
- # workbook.close
66
- #
67
- # Here are some other examples of using +new+ with filenames:
68
- #
69
- # workbook1 = WriteXLSX.new(filename)
70
- # workbook2 = WriteXLSX.new('/tmp/filename.xlsx')
71
- # workbook3 = WriteXLSX.new("c:\\tmp\\filename.xlsx")
72
- # workbook4 = WriteXLSX.new('c:\tmp\filename.xlsx')
73
- #
74
- # The last two examples demonstrates how to create a file on DOS or Windows
75
- # where it is necessary to either escape the directory separator \
76
- # or to use single quotes to ensure that it isn't interpolated.
77
- #
78
- # It is recommended that the filename uses the extension .xlsx
79
- # rather than .xls since the latter causes an Excel warning
80
- # when used with the XLSX format.
81
- #
82
- # The +new+ constructor returns a WriteXLSX object that you can use to
83
- # add worksheets and store data.
84
- #
85
- # You can also pass a valid IO object to the +new+ constructor.
86
- #
87
- # xlsx = StringIO.new
88
- # workbook = WriteXLSX.new(xlsx)
89
- # ....
90
- # workbook.close
91
- # # you can get XLSX binary data as xlsx.string
92
- #
93
- # And you can pass default_formats parameter like this:
94
- #
95
- # formats = { :font => 'Arial', :size => 10.5 }
96
- # workbook = WriteXLSX.new('file.xlsx', formats)
97
- #
98
41
  def initialize(file, *option_params)
99
42
  options, default_formats = process_workbook_options(*option_params)
100
43
  @writer = Package::XMLWriterSimple.new
@@ -135,6 +78,7 @@ module Writexlsx
135
78
  @max_url_length = 2079
136
79
  @has_comments = false
137
80
  @read_only = 0
81
+ @has_metadata = false
138
82
  if options[:max_url_length]
139
83
  @max_url_length = options[:max_url_length]
140
84
 
@@ -149,8 +93,13 @@ module Writexlsx
149
93
  @calc_on_load = true
150
94
 
151
95
  if @excel2003_style
152
- add_format(default_formats
153
- .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
+ ))
154
103
  else
155
104
  add_format(default_formats.merge(:xf_index => 0))
156
105
  end
@@ -164,13 +113,6 @@ module Writexlsx
164
113
  #
165
114
  # The close method is used to close an Excel file.
166
115
  #
167
- # An explicit close is required if the file must be closed prior to performing
168
- # some external action on it such as copying it, reading its size or attaching
169
- # it to an email.
170
- #
171
- # In general, if you create a file with a size of 0 bytes or you fail to create
172
- # a file you need to call close.
173
- #
174
116
  def close
175
117
  # In case close() is called twice.
176
118
  return if @fileclosed
@@ -186,32 +128,6 @@ module Writexlsx
186
128
  # sheets -> array of all Wordsheet object
187
129
  # sheets(1, 3, 4) -> array of spcified Worksheet object.
188
130
  #
189
- # The sheets method returns a array, or a sliced array, of the worksheets
190
- # in a workbook.
191
- #
192
- # If no arguments are passed the method returns a list of all the worksheets
193
- # in the workbook. This is useful if you want to repeat an operation on each
194
- # worksheet:
195
- #
196
- # workbook.sheets.each do |worksheet|
197
- # print worksheet.get_name
198
- # end
199
- #
200
- # You can also specify a slice list to return one or more worksheet objects:
201
- #
202
- # worksheet = workbook.sheets(0)
203
- # worksheet.write('A1', 'Hello')
204
- #
205
- # you can write the above example as:
206
- #
207
- # workbook.sheets(0).write('A1', 'Hello')
208
- #
209
- # The following example returns the first and last worksheet in a workbook:
210
- #
211
- # workbook.sheets(0, -1).each do |sheet|
212
- # # Do something
213
- # end
214
- #
215
131
  def sheets(*args)
216
132
  if args.empty?
217
133
  @worksheets
@@ -231,20 +147,6 @@ module Writexlsx
231
147
  #
232
148
  # Set the date system: false = 1900 (the default), true = 1904
233
149
  #
234
- # Excel stores dates as real numbers where the integer part stores
235
- # the number of days since the epoch and the fractional part stores
236
- # the percentage of the day. The epoch can be either 1900 or 1904.
237
- # Excel for Windows uses 1900 and Excel for Macintosh uses 1904.
238
- # However, Excel on either platform will convert automatically between
239
- # one system and the other.
240
- #
241
- # WriteXLSX stores dates in the 1900 format by default. If you wish to
242
- # change this you can call the set_1904 workbook method.
243
- # You can query the current value by calling the get_1904 workbook method.
244
- # This returns false for 1900 and true for 1904.
245
- #
246
- # In general you probably won't need to use set_1904.
247
- #
248
150
  def set_1904(mode = true)
249
151
  unless sheets.empty?
250
152
  raise "set_1904() must be called before add_worksheet()"
@@ -321,20 +223,6 @@ module Writexlsx
321
223
  #
322
224
  # At least one worksheet should be added to a new workbook. A worksheet is used to write data into cells:
323
225
  #
324
- # worksheet1 = workbook.add_worksheet # Sheet1
325
- # worksheet2 = workbook.add_worksheet('Foglio2') # Foglio2
326
- # worksheet3 = workbook.add_worksheet('Data') # Data
327
- # worksheet4 = workbook.add_worksheet # Sheet4
328
- # If name is not specified the default Excel convention will be followed, i.e. Sheet1, Sheet2, etc.
329
- #
330
- # The worksheet name must be a valid Excel worksheet name,
331
- # i.e. it cannot contain any of the following characters,
332
- # [ ] : * ? / \
333
- #
334
- # and it must be less than 32 characters.
335
- # In addition, you cannot use the same, case insensitive,
336
- # sheetname for more than one worksheet.
337
- #
338
226
  def add_worksheet(name = '')
339
227
  name = check_sheetname(name)
340
228
  worksheet = Worksheet.new(self, @worksheets.size, name)
@@ -345,72 +233,7 @@ module Writexlsx
345
233
  #
346
234
  # This method is use to create a new chart either as a standalone worksheet
347
235
  # (the default) or as an embeddable object that can be inserted into
348
- # a worksheet via the
349
- # {Worksheet#insert_chart}[Worksheet.html#method-i-insert_chart] method.
350
- #
351
- # chart = workbook.add_chart(:type => 'column')
352
- #
353
- # The properties that can be set are:
354
- #
355
- # :type (required)
356
- # :subtype (optional)
357
- # :name (optional)
358
- # :embedded (optional)
359
- #
360
- # === :type
361
- #
362
- # This is a required parameter.
363
- # It defines the type of chart that will be created.
364
- #
365
- # chart = workbook.add_chart(:type => 'line')
366
- #
367
- # The available types are:
368
- #
369
- # area
370
- # bar
371
- # column
372
- # line
373
- # pie
374
- # scatter
375
- # stock
376
- #
377
- # === :subtype
378
- #
379
- # Used to define a chart subtype where available.
380
- #
381
- # chart = workbook.add_chart(:type => 'bar', :subtype => 'stacked')
382
- #
383
- # Currently only Bar and Column charts support subtypes
384
- # (stacked and percent_stacked). See the documentation for those chart
385
- # types.
386
- #
387
- # === :name
388
- #
389
- # Set the name for the chart sheet. The name property is optional and
390
- # if it isn't supplied will default to Chart1 .. n. The name must be
391
- # a valid Excel worksheet name. See add_worksheet
392
- # for more details on valid sheet names. The name property can be
393
- # omitted for embedded charts.
394
- #
395
- # chart = workbook.add_chart(:type => 'line', :name => 'Results Chart')
396
- #
397
- # === :embedded
398
- #
399
- # Specifies that the Chart object will be inserted in a worksheet
400
- # via the {Worksheet#insert_chart}[Worksheet.html#insert_chart] method.
401
- # It is an error to try insert a Chart that doesn't have this flag set.
402
- #
403
- # chart = workbook.add_chart(:type => 'line', :embedded => 1)
404
- #
405
- # # Configure the chart.
406
- # ...
407
- #
408
- # # Insert the chart into the a worksheet.
409
- # worksheet.insert_chart('E2', chart)
410
- #
411
- # See Chart[Chart.html] for details on how to configure the chart object
412
- # once it is created. See also the chart_*.rb programs in the examples
413
- # directory of the distro.
236
+ # a worksheet via the insert_chart method.
414
237
  #
415
238
  def add_chart(params = {})
416
239
  # Type must be specified so we can create the required chart instance.
@@ -442,7 +265,7 @@ module Writexlsx
442
265
  end
443
266
 
444
267
  #
445
- # 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
446
269
  # which are used to apply formatting to a cell. You can either define
447
270
  # the properties at creation time via a hash of property values
448
271
  # or later via method calls.
@@ -450,9 +273,6 @@ module Writexlsx
450
273
  # format1 = workbook.add_format(property_hash) # Set properties at creation
451
274
  # format2 = workbook.add_format # Set properties later
452
275
  #
453
- # See the {Format Class's rdoc}[Format.html] for more details about
454
- # Format properties and how to set them.
455
- #
456
276
  def add_format(property_hash = {})
457
277
  properties = {}
458
278
  if @excel2003_style
@@ -471,236 +291,6 @@ module Writexlsx
471
291
  # The +add_shape+ method can be used to create new shapes that may be
472
292
  # inserted into a worksheet.
473
293
  #
474
- # You can either define the properties at creation time via a hash of
475
- # property values or later via method calls.
476
- #
477
- # # Set properties at creation.
478
- # plus = workbook.add_shape(
479
- # :type => 'plus',
480
- # :id => 3,
481
- # :width => pw,
482
- # :height => ph
483
- # )
484
- #
485
- # # Default rectangle shape. Set properties later.
486
- # rect = workbook.add_shape
487
- #
488
- # See also the shape*.rb programs in the examples directory of the distro.
489
- #
490
- # === Shape Properties
491
- #
492
- # Any shape property can be queried or modified by [ ] like hash.
493
- #
494
- # ellipse = workbook.add_shape(properties)
495
- # ellipse[:type] = 'cross' # No longer an ellipse !
496
- # type = ellipse[:type] # Find out what it really is.
497
- #
498
- # The properties of a shape object that can be defined via add_shape are
499
- # shown below.
500
- #
501
- # ===:name
502
- #
503
- # Defines the name of the shape. This is an optional property and the shape
504
- # will be given a default name if not supplied. The name is generally only
505
- # used by Excel Macros to refer to the object.
506
- #
507
- # ===:type
508
- #
509
- # Defines the type of the object such as +:rect+, +:ellipse+ OR +:triangle+.
510
- #
511
- # ellipse = workbook.add_shape(:type => :ellipse)
512
- #
513
- # The default type is +:rect+.
514
- #
515
- # The full list of available shapes is shown below.
516
- #
517
- # See also the shape_all.rb program in the examples directory of the distro.
518
- # It creates an example workbook with all supported shapes labelled with
519
- # their shape names.
520
- #
521
- # === Basic Shapes
522
- #
523
- # blockArc can chevron cube decagon
524
- # diamond dodecagon donut ellipse funnel
525
- # gear6 gear9 heart heptagon hexagon
526
- # homePlate lightningBolt line lineInv moon
527
- # nonIsoscelesTrapezoid noSmoking octagon parallelogram pentagon
528
- # pie pieWedge plaque rect round1Rect
529
- # round2DiagRect round2SameRect roundRect rtTriangle smileyFace
530
- # snip1Rect snip2DiagRect snip2SameRect snipRoundRect star10
531
- # star12 star16 star24 star32 star4
532
- # star5 star6 star7 star8 sun
533
- # teardrop trapezoid triangle
534
- #
535
- # === Arrow Shapes
536
- #
537
- # bentArrow bentUpArrow circularArrow curvedDownArrow
538
- # curvedLeftArrow curvedRightArrow curvedUpArrow downArrow
539
- # leftArrow leftCircularArrow leftRightArrow leftRightCircularArrow
540
- # leftRightUpArrow leftUpArrow notchedRightArrow quadArrow
541
- # rightArrow stripedRightArrow swooshArrow upArrow
542
- # upDownArrow uturnArrow
543
- #
544
- # === Connector Shapes
545
- #
546
- # bentConnector2 bentConnector3 bentConnector4
547
- # bentConnector5 curvedConnector2 curvedConnector3
548
- # curvedConnector4 curvedConnector5 straightConnector1
549
- #
550
- # === Callout Shapes
551
- #
552
- # accentBorderCallout1 accentBorderCallout2 accentBorderCallout3
553
- # accentCallout1 accentCallout2 accentCallout3
554
- # borderCallout1 borderCallout2 borderCallout3
555
- # callout1 callout2 callout3
556
- # cloudCallout downArrowCallout leftArrowCallout
557
- # leftRightArrowCallout quadArrowCallout rightArrowCallout
558
- # upArrowCallout upDownArrowCallout wedgeEllipseCallout
559
- # wedgeRectCallout wedgeRoundRectCallout
560
- #
561
- # === Flow Chart Shapes
562
- #
563
- # flowChartAlternateProcess flowChartCollate flowChartConnector
564
- # flowChartDecision flowChartDelay flowChartDisplay
565
- # flowChartDocument flowChartExtract flowChartInputOutput
566
- # flowChartInternalStorage flowChartMagneticDisk flowChartMagneticDrum
567
- # flowChartMagneticTape flowChartManualInput flowChartManualOperation
568
- # flowChartMerge flowChartMultidocument flowChartOfflineStorage
569
- # flowChartOffpageConnector flowChartOnlineStorage flowChartOr
570
- # flowChartPredefinedProcess flowChartPreparation flowChartProcess
571
- # flowChartPunchedCard flowChartPunchedTape flowChartSort
572
- # flowChartSummingJunction flowChartTerminator
573
- #
574
- # === Action Shapes
575
- #
576
- # actionButtonBackPrevious actionButtonBeginning actionButtonBlank
577
- # actionButtonDocument actionButtonEnd actionButtonForwardNext
578
- # actionButtonHelp actionButtonHome actionButtonInformation
579
- # actionButtonMovie actionButtonReturn actionButtonSound
580
- #
581
- # === Chart Shapes
582
- #
583
- # Not to be confused with Excel Charts.
584
- #
585
- # chartPlus chartStar chartX
586
- #
587
- # === Math Shapes
588
- #
589
- # mathDivide mathEqual mathMinus mathMultiply mathNotEqual mathPlus
590
- #
591
- # === Starts and Banners
592
- #
593
- # arc bevel bracePair bracketPair chord
594
- # cloud corner diagStripe doubleWave ellipseRibbon
595
- # ellipseRibbon2 foldedCorner frame halfFrame horizontalScroll
596
- # irregularSeal1 irregularSeal2 leftBrace leftBracket leftRightRibbon
597
- # plus ribbon ribbon2 rightBrace rightBracket
598
- # verticalScroll wave
599
- #
600
- # === Tab Shapes
601
- #
602
- # cornerTabs plaqueTabs squareTabs
603
- #
604
- # === :text
605
- #
606
- # This property is used to make the shape act like a text box.
607
- #
608
- # rect = workbook.add_shape(:type => 'rect', :text => "Hello \nWorld")
609
- #
610
- # The Text is super-imposed over the shape. The text can be wrapped using
611
- # the newline character \n.
612
- #
613
- # === :id
614
- #
615
- # Identification number for internal identification. This number will be
616
- # auto-assigned, if not assigned, or if it is a duplicate.
617
- #
618
- # === :format
619
- #
620
- # Workbook format for decorating the shape horizontally and/or vertically.
621
- #
622
- # === :rotation
623
- #
624
- # Shape rotation, in degrees, from 0 to 360
625
- #
626
- # === :line, :fill
627
- #
628
- # Shape color for the outline and fill.
629
- # Colors may be specified as a color index, or in RGB format, i.e. AA00FF.
630
- #
631
- # See COULOURS IN EXCEL in the main documentation for more information.
632
- #
633
- # === :link_type
634
- #
635
- # Line type for shape outline. The default is solid.
636
- # The list of possible values is:
637
- #
638
- # dash, sysDot, dashDot, lgDash, lgDashDot, lgDashDotDot, solid
639
- #
640
- # === :valign, :align
641
- #
642
- # Text alignment within the shape.
643
- #
644
- # Vertical alignment can be:
645
- #
646
- # Setting Meaning
647
- # ======= =======
648
- # t Top
649
- # ctr Centre
650
- # b Bottom
651
- #
652
- # Horizontal alignment can be:
653
- #
654
- # Setting Meaning
655
- # ======= =======
656
- # l Left
657
- # r Right
658
- # ctr Centre
659
- # just Justified
660
- #
661
- # The default is to center both horizontally and vertically.
662
- #
663
- # === :scale_x, :scale_y
664
- #
665
- # Scale factor in x and y dimension, for scaling the shape width and
666
- # height. The default value is 1.
667
- #
668
- # Scaling may be set on the shape object or via insert_shape.
669
- #
670
- # === :adjustments
671
- #
672
- # Adjustment of shape vertices. Most shapes do not use this. For some
673
- # shapes, there is a single adjustment to modify the geometry.
674
- # For instance, the plus shape has one adjustment to control the width
675
- # of the spokes.
676
- #
677
- # Connectors can have a number of adjustments to control the shape
678
- # routing. Typically, a connector will have 3 to 5 handles for routing
679
- # the shape. The adjustment is in percent of the distance from the
680
- # starting shape to the ending shape, alternating between the x and y
681
- # dimension. Adjustments may be negative, to route the shape away
682
- # from the endpoint.
683
- #
684
- # === :stencil
685
- #
686
- # Shapes work in stencil mode by default. That is, once a shape is
687
- # inserted, its connection is separated from its master.
688
- # The master shape may be modified after an instance is inserted,
689
- # and only subsequent insertions will show the modifications.
690
- #
691
- # This is helpful for Org charts, where an employee shape may be
692
- # created once, and then the text of the shape is modified for each
693
- # employee.
694
- #
695
- # The insert_shape method returns a reference to the inserted
696
- # shape (the child).
697
- #
698
- # Stencil mode can be turned off, allowing for shape(s) to be
699
- # modified after insertion. In this case the insert_shape() method
700
- # returns a reference to the inserted shape (the master).
701
- # This is not very useful for inserting multiple shapes,
702
- # since the x/y coordinates also gets modified.
703
- #
704
294
  def add_shape(properties = {})
705
295
  shape = Shape.new(properties)
706
296
  shape.palette = @palette
@@ -714,31 +304,6 @@ module Writexlsx
714
304
  # Create a defined name in Excel. We handle global/workbook level names and
715
305
  # local/worksheet names.
716
306
  #
717
- # This method is used to defined a name that can be used to represent
718
- # a value, a single cell or a range of cells in a workbook.
719
- #
720
- # For example to set a global/workbook name:
721
- #
722
- # # Global/workbook names.
723
- # workbook.define_name('Exchange_rate', '=0.96')
724
- # workbook.define_name('Sales', '=Sheet1!$G$1:$H$10')
725
- #
726
- # It is also possible to define a local/worksheet name by prefixing the name
727
- # with the sheet name using the syntax +sheetname!definedname+:
728
- #
729
- # # Local/worksheet name.
730
- # workbook.define_name('Sheet2!Sales', '=Sheet2!$G$1:$G$10')
731
- #
732
- # If the sheet name contains spaces or special characters
733
- # you must enclose it in single quotes like in Excel:
734
- #
735
- # workbook.define_name("'New Data'!Sales", '=Sheet2!$G$1:$G$10')
736
- #
737
- # See the defined_name.rb program in the examples dir of the distro.
738
- #
739
- # Refer to the following to see Excel's syntax rules for defined names:
740
- # <http://office.microsoft.com/en-001/excel-help/define-and-use-names-in-formulas-HA010147120.aspx#BMsyntax_rules_for_names>
741
- #
742
307
  def define_name(name, formula)
743
308
  sheet_index = nil
744
309
  sheetname = ''
@@ -817,29 +382,6 @@ module Writexlsx
817
382
  # and are also available to external applications that read or index windows
818
383
  # files.
819
384
  #
820
- # The properties should be passed in hash format as follows:
821
- #
822
- # workbook.set_properties(
823
- # :title => 'This is an example spreadsheet',
824
- # :author => 'Hideo NAKAMURA',
825
- # :comments => 'Created with Ruby and WriteXLSX'
826
- # )
827
- #
828
- # The properties that can be set are:
829
- #
830
- # :title
831
- # :subject
832
- # :author
833
- # :manager
834
- # :company
835
- # :category
836
- # :keywords
837
- # :comments
838
- # :status
839
- #
840
- # See also the properties.rb program in the examples directory
841
- # of the distro.
842
- #
843
385
  def set_properties(params)
844
386
  # Ignore if no args were passed.
845
387
  return -1 if params.empty?
@@ -923,27 +465,6 @@ module Writexlsx
923
465
  # WriteXLSX file using a binary VBA project file that has been extracted
924
466
  # from an existing Excel xlsm file.
925
467
  #
926
- # workbook = WriteXLSX.new('file.xlsm')
927
- #
928
- # workbook.add_vba_project('./vbaProject.bin')
929
- #
930
- # The supplied +extract_vba+ utility can be used to extract the required
931
- # +vbaProject.bin+ file from an existing Excel file:
932
- #
933
- # $ extract_vba file.xlsm
934
- # Extracted 'vbaProject.bin' successfully
935
- #
936
- # Macros can be tied to buttons using the worksheet
937
- # {insert_button}[Worksheet.html#method-i-insert_button] method
938
- # (see the "WORKSHEET METHODS" section for details):
939
- #
940
- # worksheet.insert_button('C2', { :macro => 'my_macro' })
941
- #
942
- # Note, Excel uses the file extension xlsm instead of xlsx for files that
943
- # contain macros. It is advisable to follow the same convention.
944
- #
945
- # See also the macros.rb example file.
946
- #
947
468
  def add_vba_project(vba_project)
948
469
  @vba_project = vba_project
949
470
  end
@@ -996,60 +517,6 @@ module Writexlsx
996
517
  #
997
518
  # Change the RGB components of the elements in the colour palette.
998
519
  #
999
- # The set_custom_color method can be used to override one of the built-in
1000
- # palette values with a more suitable colour.
1001
- #
1002
- # The value for +index+ should be in the range 8..63,
1003
- # see "COLOURS IN EXCEL".
1004
- #
1005
- # The default named colours use the following indices:
1006
- #
1007
- # 8 => black
1008
- # 9 => white
1009
- # 10 => red
1010
- # 11 => lime
1011
- # 12 => blue
1012
- # 13 => yellow
1013
- # 14 => magenta
1014
- # 15 => cyan
1015
- # 16 => brown
1016
- # 17 => green
1017
- # 18 => navy
1018
- # 20 => purple
1019
- # 22 => silver
1020
- # 23 => gray
1021
- # 33 => pink
1022
- # 53 => orange
1023
- #
1024
- # A new colour is set using its RGB (red green blue) components. The +red+,
1025
- # +green+ and +blue+ values must be in the range 0..255. You can determine
1026
- # the required values in Excel using the Tools->Options->Colors->Modify
1027
- # dialog.
1028
- #
1029
- # The set_custom_color workbook method can also be used with a HTML style
1030
- # +#rrggbb+ hex value:
1031
- #
1032
- # workbook.set_custom_color(40, 255, 102, 0 ) # Orange
1033
- # workbook.set_custom_color(40, 0xFF, 0x66, 0x00) # Same thing
1034
- # workbook.set_custom_color(40, '#FF6600' ) # Same thing
1035
- #
1036
- # font = workbook.add_format(:color => 40) # Use the modified colour
1037
- #
1038
- # The return value from set_custom_color() is the index of the colour that
1039
- # was changed:
1040
- #
1041
- # ferrari = workbook.set_custom_color(40, 216, 12, 12)
1042
- #
1043
- # format = workbook.add_format(
1044
- # :bg_color => ferrari,
1045
- # :pattern => 1,
1046
- # :border => 1
1047
- # )
1048
- #
1049
- # Note, In the XLSX format the color palette isn't actually confined to 53
1050
- # unique colors. The WriteXLSX gem will be extended at a later stage to
1051
- # support the newer, semi-infinite, palette.
1052
- #
1053
520
  def set_custom_color(index, red = 0, green = 0, blue = 0)
1054
521
  # Match a HTML #xxyyzz style parameter
1055
522
  if red.to_s =~ /^#(\w\w)(\w\w)(\w\w)/
@@ -1121,15 +588,15 @@ module Writexlsx
1121
588
 
1122
589
  def style_properties
1123
590
  [
1124
- @xf_formats,
1125
- @palette,
1126
- @font_count,
1127
- @num_format_count,
1128
- @border_count,
1129
- @fill_count,
1130
- @custom_colors,
1131
- @dxf_formats,
1132
- @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
1133
600
  ]
1134
601
  end
1135
602
 
@@ -1157,6 +624,10 @@ module Writexlsx
1157
624
  @activesheet ||= 0
1158
625
  end
1159
626
 
627
+ def has_metadata?
628
+ @has_metadata
629
+ end
630
+
1160
631
  private
1161
632
 
1162
633
  def filename
@@ -1190,63 +661,63 @@ module Writexlsx
1190
661
  #
1191
662
  def set_color_palette #:nodoc:
1192
663
  @palette = [
1193
- [ 0x00, 0x00, 0x00, 0x00 ], # 8
1194
- [ 0xff, 0xff, 0xff, 0x00 ], # 9
1195
- [ 0xff, 0x00, 0x00, 0x00 ], # 10
1196
- [ 0x00, 0xff, 0x00, 0x00 ], # 11
1197
- [ 0x00, 0x00, 0xff, 0x00 ], # 12
1198
- [ 0xff, 0xff, 0x00, 0x00 ], # 13
1199
- [ 0xff, 0x00, 0xff, 0x00 ], # 14
1200
- [ 0x00, 0xff, 0xff, 0x00 ], # 15
1201
- [ 0x80, 0x00, 0x00, 0x00 ], # 16
1202
- [ 0x00, 0x80, 0x00, 0x00 ], # 17
1203
- [ 0x00, 0x00, 0x80, 0x00 ], # 18
1204
- [ 0x80, 0x80, 0x00, 0x00 ], # 19
1205
- [ 0x80, 0x00, 0x80, 0x00 ], # 20
1206
- [ 0x00, 0x80, 0x80, 0x00 ], # 21
1207
- [ 0xc0, 0xc0, 0xc0, 0x00 ], # 22
1208
- [ 0x80, 0x80, 0x80, 0x00 ], # 23
1209
- [ 0x99, 0x99, 0xff, 0x00 ], # 24
1210
- [ 0x99, 0x33, 0x66, 0x00 ], # 25
1211
- [ 0xff, 0xff, 0xcc, 0x00 ], # 26
1212
- [ 0xcc, 0xff, 0xff, 0x00 ], # 27
1213
- [ 0x66, 0x00, 0x66, 0x00 ], # 28
1214
- [ 0xff, 0x80, 0x80, 0x00 ], # 29
1215
- [ 0x00, 0x66, 0xcc, 0x00 ], # 30
1216
- [ 0xcc, 0xcc, 0xff, 0x00 ], # 31
1217
- [ 0x00, 0x00, 0x80, 0x00 ], # 32
1218
- [ 0xff, 0x00, 0xff, 0x00 ], # 33
1219
- [ 0xff, 0xff, 0x00, 0x00 ], # 34
1220
- [ 0x00, 0xff, 0xff, 0x00 ], # 35
1221
- [ 0x80, 0x00, 0x80, 0x00 ], # 36
1222
- [ 0x80, 0x00, 0x00, 0x00 ], # 37
1223
- [ 0x00, 0x80, 0x80, 0x00 ], # 38
1224
- [ 0x00, 0x00, 0xff, 0x00 ], # 39
1225
- [ 0x00, 0xcc, 0xff, 0x00 ], # 40
1226
- [ 0xcc, 0xff, 0xff, 0x00 ], # 41
1227
- [ 0xcc, 0xff, 0xcc, 0x00 ], # 42
1228
- [ 0xff, 0xff, 0x99, 0x00 ], # 43
1229
- [ 0x99, 0xcc, 0xff, 0x00 ], # 44
1230
- [ 0xff, 0x99, 0xcc, 0x00 ], # 45
1231
- [ 0xcc, 0x99, 0xff, 0x00 ], # 46
1232
- [ 0xff, 0xcc, 0x99, 0x00 ], # 47
1233
- [ 0x33, 0x66, 0xff, 0x00 ], # 48
1234
- [ 0x33, 0xcc, 0xcc, 0x00 ], # 49
1235
- [ 0x99, 0xcc, 0x00, 0x00 ], # 50
1236
- [ 0xff, 0xcc, 0x00, 0x00 ], # 51
1237
- [ 0xff, 0x99, 0x00, 0x00 ], # 52
1238
- [ 0xff, 0x66, 0x00, 0x00 ], # 53
1239
- [ 0x66, 0x66, 0x99, 0x00 ], # 54
1240
- [ 0x96, 0x96, 0x96, 0x00 ], # 55
1241
- [ 0x00, 0x33, 0x66, 0x00 ], # 56
1242
- [ 0x33, 0x99, 0x66, 0x00 ], # 57
1243
- [ 0x00, 0x33, 0x00, 0x00 ], # 58
1244
- [ 0x33, 0x33, 0x00, 0x00 ], # 59
1245
- [ 0x99, 0x33, 0x00, 0x00 ], # 60
1246
- [ 0x99, 0x33, 0x66, 0x00 ], # 61
1247
- [ 0x33, 0x33, 0x99, 0x00 ], # 62
1248
- [ 0x33, 0x33, 0x33, 0x00 ], # 63
1249
- ]
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
+ ]
1250
721
  end
1251
722
 
1252
723
  #
@@ -1310,11 +781,11 @@ module Writexlsx
1310
781
 
1311
782
  def write_file_version #:nodoc:
1312
783
  attributes = [
1313
- ['appName', 'xl'],
1314
- ['lastEdited', 4],
1315
- ['lowestEdited', 4],
1316
- ['rupBuild', 4505]
1317
- ]
784
+ ['appName', 'xl'],
785
+ ['lastEdited', 4],
786
+ ['lowestEdited', 4],
787
+ ['rupBuild', 4505]
788
+ ]
1318
789
 
1319
790
  if @vba_project
1320
791
  attributes << [:codeName, '{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}']
@@ -1348,11 +819,11 @@ module Writexlsx
1348
819
 
1349
820
  def write_workbook_view #:nodoc:
1350
821
  attributes = [
1351
- ['xWindow', @x_window],
1352
- ['yWindow', @y_window],
1353
- ['windowWidth', @window_width],
1354
- ['windowHeight', @window_height]
1355
- ]
822
+ ['xWindow', @x_window],
823
+ ['yWindow', @y_window],
824
+ ['windowWidth', @window_width],
825
+ ['windowHeight', @window_height]
826
+ ]
1356
827
  if @tab_ratio != 600
1357
828
  attributes << ['tabRatio', @tab_ratio]
1358
829
  end
@@ -1450,6 +921,9 @@ module Writexlsx
1450
921
  # Prepare the worksheet tables.
1451
922
  prepare_tables
1452
923
 
924
+ # Prepare the metadata file links.
925
+ prepare_metadata
926
+
1453
927
  # Package the workbook.
1454
928
  packager = Package::Packager.new(self)
1455
929
  packager.set_package_dir(tempdir)
@@ -1685,20 +1159,20 @@ module Writexlsx
1685
1159
  # Check for Print Area settings.
1686
1160
  if sheet.autofilter_area
1687
1161
  @defined_names << [
1688
- '_xlnm._FilterDatabase',
1689
- sheet.index,
1690
- sheet.autofilter_area,
1691
- 1
1692
- ]
1162
+ '_xlnm._FilterDatabase',
1163
+ sheet.index,
1164
+ sheet.autofilter_area,
1165
+ 1
1166
+ ]
1693
1167
  end
1694
1168
 
1695
1169
  # Check for Print Area settings.
1696
1170
  if !sheet.print_area.empty?
1697
1171
  @defined_names << [
1698
- '_xlnm.Print_Area',
1699
- sheet.index,
1700
- sheet.print_area
1701
- ]
1172
+ '_xlnm.Print_Area',
1173
+ sheet.index,
1174
+ sheet.print_area
1175
+ ]
1702
1176
  end
1703
1177
 
1704
1178
  # Check for repeat rows/cols. aka, Print Titles.
@@ -1785,6 +1259,18 @@ module Writexlsx
1785
1259
  end
1786
1260
  end
1787
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
+
1788
1274
  #
1789
1275
  # Add "cached" data to charts to provide the numCache and strCache data for
1790
1276
  # series and title/axis ranges.
@@ -1941,16 +1427,18 @@ module Writexlsx
1941
1427
  ref_id = 0
1942
1428
  image_ids = {}
1943
1429
  header_image_ids = {}
1430
+ background_ids = {}
1944
1431
  @worksheets.each do |sheet|
1945
1432
  chart_count = sheet.charts.size
1946
1433
  image_count = sheet.images.size
1947
1434
  shape_count = sheet.shapes.size
1948
1435
  header_image_count = sheet.header_images.size
1949
1436
  footer_image_count = sheet.footer_images.size
1950
- has_drawings = false
1437
+ has_background = sheet.background_image.size
1438
+ has_drawings = false
1951
1439
 
1952
1440
  # Check that some image or drawing needs to be processed.
1953
- 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
1954
1442
 
1955
1443
  # Don't increase the drawing_id header/footer images.
1956
1444
  if chart_count + image_count + shape_count > 0
@@ -1958,6 +1446,23 @@ module Writexlsx
1958
1446
  has_drawings = true
1959
1447
  end
1960
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
+
1961
1466
  # Prepare the worksheet images.
1962
1467
  sheet.images.each_with_index do |image, index|
1963
1468
  filename = image[2]
@@ -2065,6 +1570,10 @@ module Writexlsx
2065
1570
  # Test for JPEG files.
2066
1571
  type, width, height, x_dpi, y_dpi = process_jpg(data, filename)
2067
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
2068
1577
  elsif data.unpack('A2')[0] == 'BM'
2069
1578
  # Test for BMPs.
2070
1579
  type, width, height = process_bmp(data, filename)
@@ -2169,6 +1678,24 @@ module Writexlsx
2169
1678
  [type, width, height, x_dpi, y_dpi]
2170
1679
  end
2171
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
+
2172
1699
  # Extract width and height information from a BMP file.
2173
1700
  def process_bmp(data, filename) #:nodoc:
2174
1701
  type = 'bmp'