write_xlsx 1.11.2 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,83 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'write_xlsx/package/xml_writer_simple'
5
+ require 'write_xlsx/utility'
6
+
7
+ module Writexlsx
8
+ module Package
9
+ #
10
+ # RichValueStructure - A class for writing the Excel XLSX rdrichvaluestructure.xml
11
+ # file.
12
+ #
13
+ # Used in conjunction with Excel::Writer::XLSX
14
+ #
15
+ # Copyright 2000-2024, John McNamara, jmcnamara@cpan.org
16
+ #
17
+ # Convert to Ruby by Hideo NAKAMURA, nakamura.hideo@gmail.com
18
+ #
19
+ class RichValueStructure
20
+ include Writexlsx::Utility
21
+
22
+ attr_writer :has_embedded_descriptions
23
+
24
+ def initialize
25
+ @writer = Package::XMLWriterSimple.new
26
+ @has_embedded_descriptions = false
27
+ end
28
+
29
+ def set_xml_writer(filename)
30
+ @writer.set_xml_writer(filename)
31
+ end
32
+
33
+ def assemble_xml_file
34
+ write_xml_declaration do
35
+ write_rv_structures
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ #
42
+ # Write the <rvStructures> element.
43
+ #
44
+ def write_rv_structures
45
+ xmlns = 'http://schemas.microsoft.com/office/spreadsheetml/2017/richdata'
46
+
47
+ attributes = [
48
+ ['xmlns', xmlns],
49
+ ['count', 1]
50
+ ]
51
+
52
+ @writer.tag_elements('rvStructures', attributes) do
53
+ write_s
54
+ end
55
+ end
56
+
57
+ #
58
+ # Write the <s> element.
59
+ #
60
+ def write_s
61
+ attributes = [%w[t _localImage]]
62
+
63
+ @writer.tag_elements('s', attributes) do
64
+ write_k('_rvRel:LocalImageIdentifier', 'i')
65
+ write_k('CalcOrigin', 'i')
66
+ write_k('Text', 's') if @has_embedded_descriptions
67
+ end
68
+ end
69
+
70
+ #
71
+ # Write the <k> element.
72
+ #
73
+ def write_k(n, t)
74
+ attributes = [
75
+ ['n', n],
76
+ ['t', t]
77
+ ]
78
+
79
+ @writer.empty_tag('k', attributes)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ require 'write_xlsx/package/xml_writer_simple'
5
+ require 'write_xlsx/utility'
6
+
7
+ module Writexlsx
8
+ module Package
9
+ #
10
+ # RichValueTypes - A class for writing the Excel XLSX rdRichValueTypes.xml file.
11
+ #
12
+ # Used in conjunction with Excel::Writer::XLSX
13
+ #
14
+ # Copyright 2000-2024, John McNamara, jmcnamara@cpan.org
15
+ #
16
+ # Convert to Ruby by Hideo NAKAMURA, nakamura.hideo@gmail.com
17
+ #
18
+ class RichValueTypes
19
+ include Writexlsx::Utility
20
+
21
+ def initialize
22
+ @writer = Package::XMLWriterSimple.new
23
+ end
24
+
25
+ def set_xml_writer(filename)
26
+ @writer.set_xml_writer(filename)
27
+ end
28
+
29
+ def assemble_xml_file
30
+ write_xml_declaration do
31
+ write_rv_types_info
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ #
38
+ # Write the <rvTypesInfo> element.
39
+ #
40
+ def write_rv_types_info
41
+ xmlns = 'http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2'
42
+ xmlns_mc = 'http://schemas.openxmlformats.org/markup-compatibility/2006'
43
+ xmlns_x = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'
44
+
45
+ attributes = [
46
+ ['xmlns', xmlns],
47
+ ['xmlns:mc', xmlns_mc],
48
+ ['mc:Ignorable', 'x'],
49
+ ['xmlns:x', xmlns_x]
50
+ ]
51
+
52
+ key_flags = [
53
+ ['_Self', %w[ExcludeFromFile ExcludeFromCalcComparison]],
54
+ ['_DisplayString', ['ExcludeFromCalcComparison']],
55
+ ['_Flags', ['ExcludeFromCalcComparison']],
56
+ ['_Format', ['ExcludeFromCalcComparison']],
57
+ ['_SubLabel', ['ExcludeFromCalcComparison']],
58
+ ['_Attribution', ['ExcludeFromCalcComparison']],
59
+ ['_Icon', ['ExcludeFromCalcComparison']],
60
+ ['_Display', ['ExcludeFromCalcComparison']],
61
+ ['_CanonicalPropertyNames', ['ExcludeFromCalcComparison']],
62
+ ['_ClassificationId', ['ExcludeFromCalcComparison']]
63
+ ]
64
+
65
+ @writer.tag_elements('rvTypesInfo', attributes) do
66
+ @writer.tag_elements('global') do
67
+ @writer.tag_elements('keyFlags') do
68
+ # Write the keyFlags element.
69
+ key_flags.each do |key_flag|
70
+ write_key(key_flag[0], key_flag[1])
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ #
78
+ # Write the <key> element.
79
+ #
80
+ def write_key(name, flags = [])
81
+ attributes = [['name', name]]
82
+
83
+ @writer.tag_elements('key', attributes) do
84
+ flags.each do |flag|
85
+ write_flag(flag)
86
+ end
87
+ end
88
+ end
89
+
90
+ #
91
+ # Write the <flag> element.
92
+ #
93
+ def write_flag(name)
94
+ attributes = [
95
+ ['name', name],
96
+ ['value', 1]
97
+ ]
98
+
99
+ @writer.empty_tag('flag', attributes)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -988,6 +988,178 @@ module Writexlsx
988
988
  def write_a_end_para_rpr # :nodoc:
989
989
  @writer.empty_tag('a:endParaRPr', [%w[lang en-US]])
990
990
  end
991
+
992
+ #
993
+ # Extract information from the image file such as dimension, type, filename,
994
+ # and extension. Also keep track of previously seen images to optimise out
995
+ # any duplicates.
996
+ #
997
+ def get_image_properties(filename)
998
+ # Note the image_id, and previous_images mechanism isn't currently used.
999
+ x_dpi = 96
1000
+ y_dpi = 96
1001
+
1002
+ workbook = @workbook || self
1003
+
1004
+ # Open the image file and import the data.
1005
+ data = File.binread(filename)
1006
+ md5 = Digest::MD5.hexdigest(data)
1007
+ if data.unpack1('x A3') == 'PNG'
1008
+ # Test for PNGs.
1009
+ type, width, height, x_dpi, y_dpi = process_png(data)
1010
+ workbook.image_types[:png] = 1
1011
+ elsif data.unpack1('n') == 0xFFD8
1012
+ # Test for JPEG files.
1013
+ type, width, height, x_dpi, y_dpi = process_jpg(data, filename)
1014
+ workbook.image_types[:jpeg] = 1
1015
+ elsif data.unpack1('A4') == 'GIF8'
1016
+ # Test for GIFs.
1017
+ type, width, height, x_dpi, y_dpi = process_gif(data, filename)
1018
+ workbook.image_types[:gif] = 1
1019
+ elsif data.unpack1('A2') == 'BM'
1020
+ # Test for BMPs.
1021
+ type, width, height = process_bmp(data, filename)
1022
+ workbook.image_types[:bmp] = 1
1023
+ else
1024
+ # TODO. Add Image::Size to support other types.
1025
+ raise "Unsupported image format for file: #{filename}\n"
1026
+ end
1027
+
1028
+ # Set a default dpi for images with 0 dpi.
1029
+ x_dpi = 96 if x_dpi == 0
1030
+ y_dpi = 96 if y_dpi == 0
1031
+
1032
+ [type, width, height, File.basename(filename), x_dpi, y_dpi, md5]
1033
+ end
1034
+
1035
+ #
1036
+ # Extract width and height information from a PNG file.
1037
+ #
1038
+ def process_png(data)
1039
+ type = 'png'
1040
+ width = 0
1041
+ height = 0
1042
+ x_dpi = 96
1043
+ y_dpi = 96
1044
+
1045
+ offset = 8
1046
+ data_length = data.size
1047
+
1048
+ # Search through the image data to read the height and width in th the
1049
+ # IHDR element. Also read the DPI in the pHYs element.
1050
+ while offset < data_length
1051
+
1052
+ length = data[offset + 0, 4].unpack1("N")
1053
+ png_type = data[offset + 4, 4].unpack1("A4")
1054
+
1055
+ case png_type
1056
+ when "IHDR"
1057
+ width = data[offset + 8, 4].unpack1("N")
1058
+ height = data[offset + 12, 4].unpack1("N")
1059
+ when "pHYs"
1060
+ x_ppu = data[offset + 8, 4].unpack1("N")
1061
+ y_ppu = data[offset + 12, 4].unpack1("N")
1062
+ units = data[offset + 16, 1].unpack1("C")
1063
+
1064
+ if units == 1
1065
+ x_dpi = x_ppu * 0.0254
1066
+ y_dpi = y_ppu * 0.0254
1067
+ end
1068
+ end
1069
+
1070
+ offset = offset + length + 12
1071
+
1072
+ break if png_type == "IEND"
1073
+ end
1074
+ raise "#{filename}: no size data found in png image.\n" unless height
1075
+
1076
+ [type, width, height, x_dpi, y_dpi]
1077
+ end
1078
+
1079
+ def process_jpg(data, filename)
1080
+ type = 'jpeg'
1081
+ x_dpi = 96
1082
+ y_dpi = 96
1083
+
1084
+ offset = 2
1085
+ data_length = data.bytesize
1086
+
1087
+ # Search through the image data to read the JPEG markers.
1088
+ while offset < data_length
1089
+ marker = data[offset + 0, 2].unpack1("n")
1090
+ length = data[offset + 2, 2].unpack1("n")
1091
+
1092
+ # Read the height and width in the 0xFFCn elements
1093
+ # (Except C4, C8 and CC which aren't SOF markers).
1094
+ if (marker & 0xFFF0) == 0xFFC0 &&
1095
+ marker != 0xFFC4 && marker != 0xFFCC
1096
+ height = data[offset + 5, 2].unpack1("n")
1097
+ width = data[offset + 7, 2].unpack1("n")
1098
+ end
1099
+
1100
+ # Read the DPI in the 0xFFE0 element.
1101
+ if marker == 0xFFE0
1102
+ units = data[offset + 11, 1].unpack1("C")
1103
+ x_density = data[offset + 12, 2].unpack1("n")
1104
+ y_density = data[offset + 14, 2].unpack1("n")
1105
+
1106
+ if units == 1
1107
+ x_dpi = x_density
1108
+ y_dpi = y_density
1109
+ elsif units == 2
1110
+ x_dpi = x_density * 2.54
1111
+ y_dpi = y_density * 2.54
1112
+ end
1113
+ end
1114
+
1115
+ offset += length + 2
1116
+ break if marker == 0xFFDA
1117
+ end
1118
+
1119
+ raise "#{filename}: no size data found in jpeg image.\n" unless height
1120
+
1121
+ [type, width, height, x_dpi, y_dpi]
1122
+ end
1123
+
1124
+ #
1125
+ # Extract width and height information from a GIF file.
1126
+ #
1127
+ def process_gif(data, filename)
1128
+ type = 'gif'
1129
+ x_dpi = 96
1130
+ y_dpi = 96
1131
+
1132
+ width = data[6, 2].unpack1("v")
1133
+ height = data[8, 2].unpack1("v")
1134
+
1135
+ raise "#{filename}: no size data found in gif image.\n" if height.nil?
1136
+
1137
+ [type, width, height, x_dpi, y_dpi]
1138
+ end
1139
+
1140
+ # Extract width and height information from a BMP file.
1141
+ def process_bmp(data, filename) # :nodoc:
1142
+ type = 'bmp'
1143
+
1144
+ # Check that the file is big enough to be a bitmap.
1145
+ raise "#{filename} doesn't contain enough data." if data.bytesize <= 0x36
1146
+
1147
+ # Read the bitmap width and height. Verify the sizes.
1148
+ width, height = data.unpack("x18 V2")
1149
+ raise "#{filename}: largest image width #{width} supported is 65k." if width > 0xFFFF
1150
+ raise "#{filename}: largest image height supported is 65k." if height > 0xFFFF
1151
+
1152
+ # Read the bitmap planes and bpp data. Verify them.
1153
+ planes, bitcount = data.unpack("x26 v2")
1154
+ raise "#{filename} isn't a 24bit true color bitmap." unless bitcount == 24
1155
+ raise "#{filename}: only 1 plane supported in bitmap image." unless planes == 1
1156
+
1157
+ # Read the bitmap compression. Verify compression.
1158
+ compression = data.unpack1("x30 V")
1159
+ raise "#{filename}: compression not supported in bitmap image." unless compression == 0
1160
+
1161
+ [type, width, height]
1162
+ end
991
1163
  end
992
1164
 
993
1165
  module WriteDPtPoint
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- WriteXLSX_VERSION = "1.11.2"
3
+ WriteXLSX_VERSION = "1.12.0"
@@ -35,6 +35,9 @@ module Writexlsx
35
35
  attr_reader :max_url_length # :nodoc:
36
36
  attr_reader :strings_to_urls # :nodoc:
37
37
  attr_reader :read_only # :nodoc:
38
+ attr_reader :embedded_image_indexes # :nodec:
39
+ attr_reader :embedded_images # :nodoc:
40
+ attr_reader :embedded_descriptions # :nodoc:
38
41
 
39
42
  def initialize(file, *option_params)
40
43
  options, default_formats = process_workbook_options(*option_params)
@@ -80,6 +83,9 @@ module Writexlsx
80
83
  @has_comments = false
81
84
  @read_only = 0
82
85
  @has_metadata = false
86
+ @has_embedded_images = false
87
+ @has_embedded_descriptions = false
88
+
83
89
  if options[:max_url_length]
84
90
  @max_url_length = options[:max_url_length]
85
91
 
@@ -88,6 +94,10 @@ module Writexlsx
88
94
  # Structures for the shared strings data.
89
95
  @shared_strings = Package::SharedStrings.new
90
96
 
97
+ # Structures for embedded images.
98
+ @embedded_image_indexes = {}
99
+ @embedded_images = []
100
+
91
101
  # Formula calculation default settings.
92
102
  @calc_id = 124519
93
103
  @calc_mode = 'auto'
@@ -530,6 +540,10 @@ module Writexlsx
530
540
  !!@date_1904
531
541
  end
532
542
 
543
+ def has_dynamic_functions?
544
+ @has_dynamic_functions
545
+ end
546
+
533
547
  #
534
548
  # Add a string to the shared string table, if it isn't already there, and
535
549
  # return the string index.
@@ -597,6 +611,14 @@ module Writexlsx
597
611
  @has_metadata
598
612
  end
599
613
 
614
+ def has_embedded_images?
615
+ @has_embedded_images
616
+ end
617
+
618
+ def has_embedded_descriptions?
619
+ @has_embedded_descriptions
620
+ end
621
+
600
622
  private
601
623
 
602
624
  def filename
@@ -1226,10 +1248,11 @@ module Writexlsx
1226
1248
  #
1227
1249
  def prepare_metadata
1228
1250
  @worksheets.each do |sheet|
1229
- if sheet.has_dynamic_arrays?
1230
- @has_metadata = true
1231
- break
1232
- end
1251
+ next unless sheet.has_dynamic_functions? || sheet.has_embedded_images?
1252
+
1253
+ @has_metadata = true
1254
+ @has_dynamic_functions ||= sheet.has_dynamic_functions?
1255
+ @has_embedded_images ||= sheet.has_embedded_images?
1233
1256
  end
1234
1257
  end
1235
1258
 
@@ -1380,12 +1403,22 @@ module Writexlsx
1380
1403
  #
1381
1404
  def prepare_drawings # :nodoc:
1382
1405
  chart_ref_id = 0
1383
- image_ref_id = 0
1384
1406
  drawing_id = 0
1385
1407
  ref_id = 0
1386
1408
  image_ids = {}
1387
1409
  header_image_ids = {}
1388
1410
  background_ids = {}
1411
+
1412
+ # Store the image types for any embedded images.
1413
+ @embedded_images.each do |image_data|
1414
+ store_image_types(image_data[1])
1415
+
1416
+ @has_embedded_descriptions = true if ptrue?(image_data[2])
1417
+ end
1418
+
1419
+ # The image IDs start from after the embedded images.
1420
+ image_ref_id = @embedded_images.size
1421
+
1389
1422
  @worksheets.each do |sheet|
1390
1423
  chart_count = sheet.charts.size
1391
1424
  image_count = sheet.images.size
@@ -1508,173 +1541,20 @@ module Writexlsx
1508
1541
  end
1509
1542
 
1510
1543
  #
1511
- # Extract information from the image file such as dimension, type, filename,
1512
- # and extension. Also keep track of previously seen images to optimise out
1513
- # any duplicates.
1544
+ # Store the image types (PNG/JPEG/etc) used in the workbook to use in these
1545
+ # Content_Types file.
1514
1546
  #
1515
- def get_image_properties(filename)
1516
- # Note the image_id, and previous_images mechanism isn't currently used.
1517
- x_dpi = 96
1518
- y_dpi = 96
1519
-
1520
- # Open the image file and import the data.
1521
- data = File.binread(filename)
1522
- md5 = Digest::MD5.hexdigest(data)
1523
- if data.unpack1('x A3') == 'PNG'
1524
- # Test for PNGs.
1525
- type, width, height, x_dpi, y_dpi = process_png(data)
1547
+ def store_image_types(type)
1548
+ case type
1549
+ when 'png'
1526
1550
  @image_types[:png] = 1
1527
- elsif data.unpack1('n') == 0xFFD8
1528
- # Test for JPEG files.
1529
- type, width, height, x_dpi, y_dpi = process_jpg(data, filename)
1551
+ when 'jpeg'
1530
1552
  @image_types[:jpeg] = 1
1531
- elsif data.unpack1('A4') == 'GIF8'
1532
- # Test for GIFs.
1533
- type, width, height, x_dpi, y_dpi = process_gif(data, filename)
1553
+ when 'gif'
1534
1554
  @image_types[:gif] = 1
1535
- elsif data.unpack1('A2') == 'BM'
1536
- # Test for BMPs.
1537
- type, width, height = process_bmp(data, filename)
1555
+ when 'bmp'
1538
1556
  @image_types[:bmp] = 1
1539
- else
1540
- # TODO. Add Image::Size to support other types.
1541
- raise "Unsupported image format for file: #{filename}\n"
1542
1557
  end
1543
-
1544
- # Set a default dpi for images with 0 dpi.
1545
- x_dpi = 96 if x_dpi == 0
1546
- y_dpi = 96 if y_dpi == 0
1547
-
1548
- [type, width, height, File.basename(filename), x_dpi, y_dpi, md5]
1549
- end
1550
-
1551
- #
1552
- # Extract width and height information from a PNG file.
1553
- #
1554
- def process_png(data)
1555
- type = 'png'
1556
- width = 0
1557
- height = 0
1558
- x_dpi = 96
1559
- y_dpi = 96
1560
-
1561
- offset = 8
1562
- data_length = data.size
1563
-
1564
- # Search through the image data to read the height and width in th the
1565
- # IHDR element. Also read the DPI in the pHYs element.
1566
- while offset < data_length
1567
-
1568
- length = data[offset + 0, 4].unpack1("N")
1569
- png_type = data[offset + 4, 4].unpack1("A4")
1570
-
1571
- case png_type
1572
- when "IHDR"
1573
- width = data[offset + 8, 4].unpack1("N")
1574
- height = data[offset + 12, 4].unpack1("N")
1575
- when "pHYs"
1576
- x_ppu = data[offset + 8, 4].unpack1("N")
1577
- y_ppu = data[offset + 12, 4].unpack1("N")
1578
- units = data[offset + 16, 1].unpack1("C")
1579
-
1580
- if units == 1
1581
- x_dpi = x_ppu * 0.0254
1582
- y_dpi = y_ppu * 0.0254
1583
- end
1584
- end
1585
-
1586
- offset = offset + length + 12
1587
-
1588
- break if png_type == "IEND"
1589
- end
1590
- raise "#{filename}: no size data found in png image.\n" unless height
1591
-
1592
- [type, width, height, x_dpi, y_dpi]
1593
- end
1594
-
1595
- def process_jpg(data, filename)
1596
- type = 'jpeg'
1597
- x_dpi = 96
1598
- y_dpi = 96
1599
-
1600
- offset = 2
1601
- data_length = data.bytesize
1602
-
1603
- # Search through the image data to read the JPEG markers.
1604
- while offset < data_length
1605
- marker = data[offset + 0, 2].unpack1("n")
1606
- length = data[offset + 2, 2].unpack1("n")
1607
-
1608
- # Read the height and width in the 0xFFCn elements
1609
- # (Except C4, C8 and CC which aren't SOF markers).
1610
- if (marker & 0xFFF0) == 0xFFC0 &&
1611
- marker != 0xFFC4 && marker != 0xFFCC
1612
- height = data[offset + 5, 2].unpack1("n")
1613
- width = data[offset + 7, 2].unpack1("n")
1614
- end
1615
-
1616
- # Read the DPI in the 0xFFE0 element.
1617
- if marker == 0xFFE0
1618
- units = data[offset + 11, 1].unpack1("C")
1619
- x_density = data[offset + 12, 2].unpack1("n")
1620
- y_density = data[offset + 14, 2].unpack1("n")
1621
-
1622
- if units == 1
1623
- x_dpi = x_density
1624
- y_dpi = y_density
1625
- elsif units == 2
1626
- x_dpi = x_density * 2.54
1627
- y_dpi = y_density * 2.54
1628
- end
1629
- end
1630
-
1631
- offset += length + 2
1632
- break if marker == 0xFFDA
1633
- end
1634
-
1635
- raise "#{filename}: no size data found in jpeg image.\n" unless height
1636
-
1637
- [type, width, height, x_dpi, y_dpi]
1638
- end
1639
-
1640
- #
1641
- # Extract width and height information from a GIF file.
1642
- #
1643
- def process_gif(data, filename)
1644
- type = 'gif'
1645
- x_dpi = 96
1646
- y_dpi = 96
1647
-
1648
- width = data[6, 2].unpack1("v")
1649
- height = data[8, 2].unpack1("v")
1650
-
1651
- raise "#{filename}: no size data found in gif image.\n" if height.nil?
1652
-
1653
- [type, width, height, x_dpi, y_dpi]
1654
- end
1655
-
1656
- # Extract width and height information from a BMP file.
1657
- def process_bmp(data, filename) # :nodoc:
1658
- type = 'bmp'
1659
-
1660
- # Check that the file is big enough to be a bitmap.
1661
- raise "#{filename} doesn't contain enough data." if data.bytesize <= 0x36
1662
-
1663
- # Read the bitmap width and height. Verify the sizes.
1664
- width, height = data.unpack("x18 V2")
1665
- raise "#{filename}: largest image width #{width} supported is 65k." if width > 0xFFFF
1666
- raise "#{filename}: largest image height supported is 65k." if height > 0xFFFF
1667
-
1668
- # Read the bitmap planes and bpp data. Verify them.
1669
- planes, bitcount = data.unpack("x26 v2")
1670
- raise "#{filename} isn't a 24bit true color bitmap." unless bitcount == 24
1671
- raise "#{filename}: only 1 plane supported in bitmap image." unless planes == 1
1672
-
1673
- # Read the bitmap compression. Verify compression.
1674
- compression = data.unpack1("x30 V")
1675
- raise "#{filename}: compression not supported in bitmap image." unless compression == 0
1676
-
1677
- [type, width, height]
1678
1558
  end
1679
1559
  end
1680
1560
  end
@@ -206,5 +206,24 @@ module Writexlsx
206
206
  worksheet.writer.empty_tag('c', cell_attributes(worksheet, row, row_name, col))
207
207
  end
208
208
  end
209
+
210
+ class EmbedImageCellData < CellData # :nodoc:
211
+ def initialize(image_index, xf)
212
+ @image_index = image_index
213
+ @xf = xf
214
+ end
215
+
216
+ def write_cell(worksheet, row, row_name, col)
217
+ attributes = cell_attributes(worksheet, row, row_name, col)
218
+
219
+ # Write a error value (mainly for embedded images).
220
+ attributes << %w[t e]
221
+ attributes << ['vm', @image_index]
222
+
223
+ worksheet.writer.tag_elements('c', attributes) do
224
+ worksheet.write_cell_value('#VALUE!')
225
+ end
226
+ end
227
+ end
209
228
  end
210
229
  end
@@ -58,7 +58,8 @@ module Writexlsx
58
58
  end
59
59
 
60
60
  def display_on
61
- @display = @url_str
61
+ # @display = @url_str
62
+ @display = @str
62
63
  end
63
64
  end
64
65