write_xlsx 1.08.2 → 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 (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'