ricardoo27-writeexcel 0.6.12.1
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.
- data/.document +5 -0
- data/.gitattributes +1 -0
- data/README.rdoc +136 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/charts/chartex.rb +316 -0
- data/charts/demo1.rb +46 -0
- data/charts/demo101.bin +0 -0
- data/charts/demo2.rb +65 -0
- data/charts/demo201.bin +0 -0
- data/charts/demo3.rb +117 -0
- data/charts/demo301.bin +0 -0
- data/charts/demo4.rb +119 -0
- data/charts/demo401.bin +0 -0
- data/charts/demo5.rb +48 -0
- data/charts/demo501.bin +0 -0
- data/examples/a_simple.rb +43 -0
- data/examples/autofilter.rb +265 -0
- data/examples/bigfile.rb +30 -0
- data/examples/chart_area.rb +121 -0
- data/examples/chart_bar.rb +120 -0
- data/examples/chart_column.rb +120 -0
- data/examples/chart_line.rb +120 -0
- data/examples/chart_pie.rb +108 -0
- data/examples/chart_scatter.rb +121 -0
- data/examples/chart_stock.rb +148 -0
- data/examples/chess.rb +142 -0
- data/examples/colors.rb +129 -0
- data/examples/comments1.rb +27 -0
- data/examples/comments2.rb +352 -0
- data/examples/copyformat.rb +52 -0
- data/examples/data_validate.rb +279 -0
- data/examples/date_time.rb +87 -0
- data/examples/defined_name.rb +32 -0
- data/examples/demo.rb +124 -0
- data/examples/diag_border.rb +36 -0
- data/examples/formats.rb +490 -0
- data/examples/formula_result.rb +30 -0
- data/examples/header.rb +137 -0
- data/examples/hide_sheet.rb +29 -0
- data/examples/hyperlink.rb +43 -0
- data/examples/images.rb +63 -0
- data/examples/indent.rb +31 -0
- data/examples/merge1.rb +40 -0
- data/examples/merge2.rb +45 -0
- data/examples/merge3.rb +66 -0
- data/examples/merge4.rb +83 -0
- data/examples/merge5.rb +80 -0
- data/examples/merge6.rb +67 -0
- data/examples/outline.rb +255 -0
- data/examples/outline_collapsed.rb +209 -0
- data/examples/panes.rb +113 -0
- data/examples/password_protection.rb +33 -0
- data/examples/properties.rb +34 -0
- data/examples/properties_jp.rb +33 -0
- data/examples/protection.rb +47 -0
- data/examples/regions.rb +53 -0
- data/examples/repeat.rb +43 -0
- data/examples/republic.png +0 -0
- data/examples/right_to_left.rb +27 -0
- data/examples/row_wrap.rb +53 -0
- data/examples/set_first_sheet.rb +14 -0
- data/examples/stats.rb +74 -0
- data/examples/stocks.rb +81 -0
- data/examples/store_formula.rb +15 -0
- data/examples/tab_colors.rb +31 -0
- data/examples/utf8.rb +15 -0
- data/examples/write_arrays.rb +83 -0
- data/html/en/doc_en.html +5946 -0
- data/html/images/a_simple.jpg +0 -0
- data/html/images/area1.jpg +0 -0
- data/html/images/bar1.jpg +0 -0
- data/html/images/chart_area.xls +0 -0
- data/html/images/column1.jpg +0 -0
- data/html/images/data_validation.jpg +0 -0
- data/html/images/line1.jpg +0 -0
- data/html/images/pie1.jpg +0 -0
- data/html/images/regions.jpg +0 -0
- data/html/images/scatter1.jpg +0 -0
- data/html/images/stats.jpg +0 -0
- data/html/images/stock1.jpg +0 -0
- data/html/images/stocks.jpg +0 -0
- data/html/index.html +16 -0
- data/html/style.css +433 -0
- data/lib/writeexcel.rb +1159 -0
- data/lib/writeexcel/biffwriter.rb +223 -0
- data/lib/writeexcel/caller_info.rb +12 -0
- data/lib/writeexcel/cell_range.rb +332 -0
- data/lib/writeexcel/chart.rb +1968 -0
- data/lib/writeexcel/charts/area.rb +154 -0
- data/lib/writeexcel/charts/bar.rb +177 -0
- data/lib/writeexcel/charts/column.rb +156 -0
- data/lib/writeexcel/charts/external.rb +66 -0
- data/lib/writeexcel/charts/line.rb +154 -0
- data/lib/writeexcel/charts/pie.rb +169 -0
- data/lib/writeexcel/charts/scatter.rb +192 -0
- data/lib/writeexcel/charts/stock.rb +213 -0
- data/lib/writeexcel/col_info.rb +87 -0
- data/lib/writeexcel/colors.rb +68 -0
- data/lib/writeexcel/comments.rb +460 -0
- data/lib/writeexcel/compatibility.rb +65 -0
- data/lib/writeexcel/convert_date_time.rb +117 -0
- data/lib/writeexcel/data_validations.rb +370 -0
- data/lib/writeexcel/debug_info.rb +41 -0
- data/lib/writeexcel/embedded_chart.rb +35 -0
- data/lib/writeexcel/excelformula.y +139 -0
- data/lib/writeexcel/excelformulaparser.rb +587 -0
- data/lib/writeexcel/format.rb +1575 -0
- data/lib/writeexcel/formula.rb +987 -0
- data/lib/writeexcel/helper.rb +78 -0
- data/lib/writeexcel/image.rb +218 -0
- data/lib/writeexcel/olewriter.rb +305 -0
- data/lib/writeexcel/outline.rb +24 -0
- data/lib/writeexcel/properties.rb +242 -0
- data/lib/writeexcel/shared_string_table.rb +153 -0
- data/lib/writeexcel/storage_lite.rb +984 -0
- data/lib/writeexcel/workbook.rb +2478 -0
- data/lib/writeexcel/worksheet.rb +6925 -0
- data/lib/writeexcel/worksheets.rb +25 -0
- data/lib/writeexcel/write_file.rb +63 -0
- data/test/excelfile/Chart1.xls +0 -0
- data/test/excelfile/Chart2.xls +0 -0
- data/test/excelfile/Chart3.xls +0 -0
- data/test/excelfile/Chart4.xls +0 -0
- data/test/excelfile/Chart5.xls +0 -0
- data/test/helper.rb +31 -0
- data/test/perl_output/Chart1.xls.data +0 -0
- data/test/perl_output/Chart2.xls.data +0 -0
- data/test/perl_output/Chart3.xls.data +0 -0
- data/test/perl_output/Chart4.xls.data +0 -0
- data/test/perl_output/Chart5.xls.data +0 -0
- data/test/perl_output/README +31 -0
- data/test/perl_output/a_simple.xls +0 -0
- data/test/perl_output/autofilter.xls +0 -0
- data/test/perl_output/biff_add_continue_testdata +0 -0
- data/test/perl_output/chart_area.xls +0 -0
- data/test/perl_output/chart_bar.xls +0 -0
- data/test/perl_output/chart_column.xls +0 -0
- data/test/perl_output/chart_line.xls +0 -0
- data/test/perl_output/chess.xls +0 -0
- data/test/perl_output/colors.xls +0 -0
- data/test/perl_output/comments0.xls +0 -0
- data/test/perl_output/comments1.xls +0 -0
- data/test/perl_output/comments2.xls +0 -0
- data/test/perl_output/data_validate.xls +0 -0
- data/test/perl_output/date_time.xls +0 -0
- data/test/perl_output/defined_name.xls +0 -0
- data/test/perl_output/demo.xls +0 -0
- data/test/perl_output/demo101.bin +0 -0
- data/test/perl_output/demo201.bin +0 -0
- data/test/perl_output/demo301.bin +0 -0
- data/test/perl_output/demo401.bin +0 -0
- data/test/perl_output/demo501.bin +0 -0
- data/test/perl_output/diag_border.xls +0 -0
- data/test/perl_output/f_font_biff +0 -0
- data/test/perl_output/f_font_key +1 -0
- data/test/perl_output/f_xf_biff +0 -0
- data/test/perl_output/file_font_biff +0 -0
- data/test/perl_output/file_font_key +1 -0
- data/test/perl_output/file_xf_biff +0 -0
- data/test/perl_output/formula_result.xls +0 -0
- data/test/perl_output/headers.xls +0 -0
- data/test/perl_output/hidden.xls +0 -0
- data/test/perl_output/hide_zero.xls +0 -0
- data/test/perl_output/hyperlink.xls +0 -0
- data/test/perl_output/images.xls +0 -0
- data/test/perl_output/indent.xls +0 -0
- data/test/perl_output/merge1.xls +0 -0
- data/test/perl_output/merge2.xls +0 -0
- data/test/perl_output/merge3.xls +0 -0
- data/test/perl_output/merge4.xls +0 -0
- data/test/perl_output/merge5.xls +0 -0
- data/test/perl_output/merge6.xls +0 -0
- data/test/perl_output/ole_write_header +0 -0
- data/test/perl_output/outline.xls +0 -0
- data/test/perl_output/outline_collapsed.xls +0 -0
- data/test/perl_output/panes.xls +0 -0
- data/test/perl_output/password_protection.xls +0 -0
- data/test/perl_output/protection.xls +0 -0
- data/test/perl_output/regions.xls +0 -0
- data/test/perl_output/right_to_left.xls +0 -0
- data/test/perl_output/set_first_sheet.xls +0 -0
- data/test/perl_output/stats.xls +0 -0
- data/test/perl_output/stocks.xls +0 -0
- data/test/perl_output/store_formula.xls +0 -0
- data/test/perl_output/tab_colors.xls +0 -0
- data/test/perl_output/unicode_cyrillic.xls +0 -0
- data/test/perl_output/utf8.xls +0 -0
- data/test/perl_output/workbook1.xls +0 -0
- data/test/perl_output/workbook2.xls +0 -0
- data/test/perl_output/ws_colinfo +1 -0
- data/test/perl_output/ws_store_colinfo +0 -0
- data/test/perl_output/ws_store_dimensions +0 -0
- data/test/perl_output/ws_store_filtermode +0 -0
- data/test/perl_output/ws_store_filtermode_off +0 -0
- data/test/perl_output/ws_store_filtermode_on +0 -0
- data/test/perl_output/ws_store_selection +0 -0
- data/test/perl_output/ws_store_window2 +1 -0
- data/test/republic.png +0 -0
- data/test/test_00_IEEE_double.rb +13 -0
- data/test/test_01_add_worksheet.rb +10 -0
- data/test/test_02_merge_formats.rb +49 -0
- data/test/test_04_dimensions.rb +388 -0
- data/test/test_05_rows.rb +175 -0
- data/test/test_06_extsst.rb +74 -0
- data/test/test_11_date_time.rb +475 -0
- data/test/test_12_date_only.rb +525 -0
- data/test/test_13_date_seconds.rb +477 -0
- data/test/test_21_escher.rb +624 -0
- data/test/test_22_mso_drawing_group.rb +741 -0
- data/test/test_23_note.rb +57 -0
- data/test/test_24_txo.rb +74 -0
- data/test/test_25_position_object.rb +80 -0
- data/test/test_26_autofilter.rb +309 -0
- data/test/test_27_autofilter.rb +126 -0
- data/test/test_28_autofilter.rb +156 -0
- data/test/test_29_process_jpg.rb +670 -0
- data/test/test_30_validation_dval.rb +74 -0
- data/test/test_31_validation_dv_strings.rb +123 -0
- data/test/test_32_validation_dv_formula.rb +203 -0
- data/test/test_40_property_types.rb +188 -0
- data/test/test_41_properties.rb +235 -0
- data/test/test_42_set_properties.rb +434 -0
- data/test/test_50_name_stored.rb +295 -0
- data/test/test_51_name_print_area.rb +353 -0
- data/test/test_52_name_print_titles.rb +450 -0
- data/test/test_53_autofilter.rb +199 -0
- data/test/test_60_chart_generic.rb +574 -0
- data/test/test_61_chart_subclasses.rb +84 -0
- data/test/test_62_chart_formats.rb +268 -0
- data/test/test_63_chart_area_formats.rb +645 -0
- data/test/test_biff.rb +71 -0
- data/test/test_big_workbook.rb +17 -0
- data/test/test_compatibility.rb +12 -0
- data/test/test_example_match.rb +3246 -0
- data/test/test_format.rb +1189 -0
- data/test/test_formula.rb +61 -0
- data/test/test_ole.rb +102 -0
- data/test/test_storage_lite.rb +116 -0
- data/test/test_workbook.rb +146 -0
- data/test/test_worksheet.rb +106 -0
- data/utils/add_magic_comment.rb +80 -0
- data/writeexcel.gemspec +278 -0
- data/writeexcel.rdoc +1425 -0
- metadata +292 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# helper.rb
|
|
4
|
+
#
|
|
5
|
+
# Convert to US_ASCII encoding if ascii characters only.
|
|
6
|
+
def convert_to_ascii_if_ascii(str)
|
|
7
|
+
return nil if str.nil?
|
|
8
|
+
ruby_18 do
|
|
9
|
+
unless str =~ /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]\{\}^` ~\0\n]/
|
|
10
|
+
str = String.new(str)
|
|
11
|
+
end
|
|
12
|
+
end ||
|
|
13
|
+
ruby_19 do
|
|
14
|
+
if str.ascii_only?
|
|
15
|
+
str = [str].pack('a*')
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
str
|
|
19
|
+
end
|
|
20
|
+
private :convert_to_ascii_if_ascii
|
|
21
|
+
|
|
22
|
+
def utf16be_to_16le(utf16be)
|
|
23
|
+
utf16be.unpack('n*').pack('v*')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def utf8_to_16be(utf8)
|
|
27
|
+
ruby_18 { NKF.nkf('-w16B0 -m0 -W', utf8) } ||
|
|
28
|
+
ruby_19 do
|
|
29
|
+
utf16be = NKF.nkf('-w16B0 -m0 -W', utf8)
|
|
30
|
+
utf16be.force_encoding('UTF-16BE')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
private :utf8_to_16be
|
|
34
|
+
|
|
35
|
+
def utf8_to_16le(utf8)
|
|
36
|
+
ruby_18 { NKF.nkf('-w16L0 -m0 -W', utf8) } ||
|
|
37
|
+
ruby_19 do
|
|
38
|
+
utf16le = NKF.nkf('-w16L0 -m0 -W', utf8)
|
|
39
|
+
utf16le.force_encoding('UTF-16LE')
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
private :utf8_to_16le
|
|
43
|
+
|
|
44
|
+
def ascii_to_16be(ascii)
|
|
45
|
+
ascii.unpack("C*").pack("n*")
|
|
46
|
+
ruby_19 { ascii.force_encoding('UTF-16BE') }
|
|
47
|
+
ascii
|
|
48
|
+
end
|
|
49
|
+
private :ascii_to_16be
|
|
50
|
+
|
|
51
|
+
def store_simple(record, length, *args)
|
|
52
|
+
header = [record, length].pack('vv')
|
|
53
|
+
data = args.collect { |arg| [arg].pack('v') }.join('')
|
|
54
|
+
|
|
55
|
+
append(header, data)
|
|
56
|
+
end
|
|
57
|
+
private :store_simple
|
|
58
|
+
|
|
59
|
+
# Convert base26 column string to a number.
|
|
60
|
+
# All your Base are belong to us.
|
|
61
|
+
def chars_to_col(chars)
|
|
62
|
+
expn = 0
|
|
63
|
+
col = 0
|
|
64
|
+
while (!chars.empty?)
|
|
65
|
+
char = chars.pop # LS char first
|
|
66
|
+
col += (char.ord - "A".ord + 1) * (26 ** expn)
|
|
67
|
+
expn += 1
|
|
68
|
+
end
|
|
69
|
+
col
|
|
70
|
+
end
|
|
71
|
+
private :chars_to_col
|
|
72
|
+
|
|
73
|
+
NonAscii = /[^!"#\$%&'\(\)\*\+,\-\.\/\:\;<=>\?@0-9A-Za-z_\[\\\]\{\}^` ~\0\n]/
|
|
74
|
+
|
|
75
|
+
def is_utf8?(str)
|
|
76
|
+
ruby_18 { str =~ NonAscii } ||
|
|
77
|
+
ruby_19 { str.encoding == Encoding::UTF_8 }
|
|
78
|
+
end
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# -*- coding:utf-8 -*-
|
|
2
|
+
require 'digest/md5'
|
|
3
|
+
|
|
4
|
+
module Writeexcel
|
|
5
|
+
class Image
|
|
6
|
+
attr_reader :row, :col, :filename, :x_offset, :y_offset, :scale_x, :scale_y
|
|
7
|
+
attr_reader :data, :size, :checksum1, :checksum2
|
|
8
|
+
attr_accessor :id, :type, :width, :height, :ref_count
|
|
9
|
+
|
|
10
|
+
def initialize(worksheet, row, col, filename, x_offset = 0, y_offset = 0, scale_x = 1, scale_y = 1)
|
|
11
|
+
@worksheet = worksheet
|
|
12
|
+
@row = row
|
|
13
|
+
@col = col
|
|
14
|
+
@filename = filename
|
|
15
|
+
@x_offset = x_offset
|
|
16
|
+
@y_offset = y_offset
|
|
17
|
+
@scale_x = scale_x
|
|
18
|
+
@scale_y = scale_y
|
|
19
|
+
get_checksum_method
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def import
|
|
23
|
+
File.open(@filename, "rb") do |fh|
|
|
24
|
+
raise "Couldn't import #{@filename}: #{$!}" unless fh
|
|
25
|
+
@data = fh.read
|
|
26
|
+
end
|
|
27
|
+
@size = data.bytesize
|
|
28
|
+
@checksum1 = image_checksum(@data)
|
|
29
|
+
@checksum2 = @checksum1
|
|
30
|
+
process
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def store_image_record(i, num_images, num_charts, num_filters, num_comments, spid)
|
|
34
|
+
image_width = width
|
|
35
|
+
image_height = height
|
|
36
|
+
|
|
37
|
+
image_width = width * scale_x unless scale_x == 0
|
|
38
|
+
image_height = height * scale_y unless scale_y == 0
|
|
39
|
+
|
|
40
|
+
# Calculate the positions of image object.
|
|
41
|
+
vertices = @worksheet.position_object(col, row, x_offset, y_offset, image_width, image_height)
|
|
42
|
+
|
|
43
|
+
if (i == 0)
|
|
44
|
+
data = images_parent_msodrawing_record(num_images, num_charts, num_filters, num_comments, spid, id, vertices)
|
|
45
|
+
else
|
|
46
|
+
data = images_child_msodrawing_record(spid, id, vertices)
|
|
47
|
+
end
|
|
48
|
+
record = 0x00EC # Record identifier
|
|
49
|
+
length = 0x0000 # Bytes to follow
|
|
50
|
+
|
|
51
|
+
length = data.bytesize
|
|
52
|
+
header = [record, length].pack("vv")
|
|
53
|
+
|
|
54
|
+
append(header, data)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
# Process the image and extract dimensions.
|
|
60
|
+
def process
|
|
61
|
+
case filetype
|
|
62
|
+
when 'PNG'
|
|
63
|
+
process_png(@data)
|
|
64
|
+
when 'JPG'
|
|
65
|
+
process_jpg(@data)
|
|
66
|
+
when 'BMP'
|
|
67
|
+
process_bmp(@data)
|
|
68
|
+
# The 14 byte header of the BMP is stripped off.
|
|
69
|
+
@data[0, 13] = ''
|
|
70
|
+
# A checksum of the new image data is also required.
|
|
71
|
+
@checksum2 = image_checksum(@data, @id, @id)
|
|
72
|
+
# Adjust size -14 (header) + 16 (extra checksum).
|
|
73
|
+
@size += 2
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def filetype
|
|
78
|
+
return 'PNG' if @data.unpack('x A3')[0] == 'PNG'
|
|
79
|
+
return 'BMP' if @data.unpack('A2')[0] == 'BM'
|
|
80
|
+
if data.unpack('n')[0] == 0xFFD8
|
|
81
|
+
return 'JPG' if @data.unpack('x6 A4')[0] == 'JFIF' || @data.unpack('x6 A4')[0] == 'Exif'
|
|
82
|
+
else
|
|
83
|
+
raise "Unsupported image format for file: #{@filename}\n"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Extract width and height information from a PNG file.
|
|
88
|
+
def process_png(data)
|
|
89
|
+
@type = 6 # Excel Blip type (MSOBLIPTYPE).
|
|
90
|
+
@width = data[16, 4].unpack("N")[0]
|
|
91
|
+
@height = data[20, 4].unpack("N")[0]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Extract width and height information from a BMP file.
|
|
95
|
+
def process_bmp(data) #:nodoc:
|
|
96
|
+
@type = 7 # Excel Blip type (MSOBLIPTYPE).
|
|
97
|
+
# Read the bitmap width and height. Verify the sizes.
|
|
98
|
+
@width, @height = data.unpack("x18 V2")
|
|
99
|
+
check_verify(data)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def check_verify(data)
|
|
103
|
+
# Check that the file is big enough to be a bitmap.
|
|
104
|
+
raise "#{@filename} doesn't contain enough data." if data.bytesize <= 0x36
|
|
105
|
+
raise "#{@filename}: largest image width #{width} supported is 65k." if @width > 0xFFFF
|
|
106
|
+
raise "#{@filename}: largest image height supported is 65k." if @height > 0xFFFF
|
|
107
|
+
|
|
108
|
+
# Read the bitmap planes and bpp data. Verify them.
|
|
109
|
+
planes, bitcount = data.unpack("x26 v2")
|
|
110
|
+
raise "#{@filename} isn't a 24bit true color bitmap." unless bitcount == 24
|
|
111
|
+
raise "#{@filename}: only 1 plane supported in bitmap image." unless planes == 1
|
|
112
|
+
|
|
113
|
+
# Read the bitmap compression. Verify compression.
|
|
114
|
+
compression = data.unpack("x30 V")
|
|
115
|
+
raise "#{@filename}: compression not supported in bitmap image." unless compression == 0
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Extract width and height information from a JPEG file.
|
|
119
|
+
def process_jpg(data)
|
|
120
|
+
@type = 5 # Excel Blip type (MSOBLIPTYPE).
|
|
121
|
+
|
|
122
|
+
offset = 2
|
|
123
|
+
data_length = data.bytesize
|
|
124
|
+
|
|
125
|
+
# Search through the image data to find the 0xFFC0 marker. The height and
|
|
126
|
+
# width are contained in the data for that sub element.
|
|
127
|
+
while offset < data_length
|
|
128
|
+
marker = data[offset, 2].unpack("n")
|
|
129
|
+
marker = marker[0]
|
|
130
|
+
length = data[offset+2, 2].unpack("n")
|
|
131
|
+
length = length[0]
|
|
132
|
+
|
|
133
|
+
if marker == 0xFFC0 || marker == 0xFFC2
|
|
134
|
+
height = data[offset+5, 2].unpack("n")
|
|
135
|
+
@height = height[0]
|
|
136
|
+
width = data[offset+7, 2].unpack("n")
|
|
137
|
+
@width = width[0]
|
|
138
|
+
break
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
offset += length + 2
|
|
142
|
+
break if marker == 0xFFDA
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
raise "#{@filename}: no size data found in jpeg image.\n" unless @height
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
#
|
|
149
|
+
# Generate a checksum for the image using whichever module is available. The
|
|
150
|
+
# available modules are checked in get_checksum_method(). Excel uses an MD4
|
|
151
|
+
# checksum but any other will do. In the event of no checksum module being
|
|
152
|
+
# available we simulate a checksum using the image index.
|
|
153
|
+
#
|
|
154
|
+
# index1 and index2 is not used.
|
|
155
|
+
#
|
|
156
|
+
def image_checksum(data, index1 = 0, index2 = 0) #:nodoc:
|
|
157
|
+
case @checksum_method
|
|
158
|
+
when 3
|
|
159
|
+
Digest::MD5.hexdigest(data)
|
|
160
|
+
when 1
|
|
161
|
+
# Digest::MD4
|
|
162
|
+
# return Digest::MD4::md4_hex($data);
|
|
163
|
+
when 2
|
|
164
|
+
# Digest::Perl::MD4
|
|
165
|
+
# return Digest::Perl::MD4::md4_hex($data);
|
|
166
|
+
else
|
|
167
|
+
# Default
|
|
168
|
+
# return sprintf('%016X%016X', index2, index1)
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
#
|
|
173
|
+
# Check for modules available to calculate image checksum. Excel uses MD4 but
|
|
174
|
+
# MD5 will also work.
|
|
175
|
+
#
|
|
176
|
+
# ------- cxn03651 add -------
|
|
177
|
+
# md5 can use in ruby. so, @checksum_method is always 3.
|
|
178
|
+
|
|
179
|
+
def get_checksum_method #:nodoc:
|
|
180
|
+
@checksum_method = 3
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def images_parent_msodrawing_record(num_images, charts_size, num_filters, num_comments, spid, image_id, vertices)
|
|
184
|
+
dg_length = 156 + 84*(num_images - 1)
|
|
185
|
+
spgr_length = 132 + 84*(num_images - 1)
|
|
186
|
+
|
|
187
|
+
dg_length += 120 * charts_size
|
|
188
|
+
spgr_length += 120 * charts_size
|
|
189
|
+
|
|
190
|
+
dg_length += 96 * num_filters
|
|
191
|
+
spgr_length += 96 * num_filters
|
|
192
|
+
|
|
193
|
+
dg_length += 128 * num_comments
|
|
194
|
+
spgr_length += 128 * num_comments
|
|
195
|
+
|
|
196
|
+
data = @worksheet.store_parent_mso_record(dg_length, spgr_length, spid)
|
|
197
|
+
spid += 1
|
|
198
|
+
data += @worksheet.store_mso_sp_container(76)
|
|
199
|
+
data += @worksheet.store_mso_sp(75, spid, 0x0A00)
|
|
200
|
+
spid += 1
|
|
201
|
+
data += @worksheet.store_mso_opt_image(image_id)
|
|
202
|
+
data += @worksheet.store_mso_client_anchor(2, *vertices)
|
|
203
|
+
data += @worksheet.store_mso_client_data
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def images_child_msodrawing_record(spid, image_id, vertices)
|
|
207
|
+
data = @worksheet.store_mso_sp_container(76) + @worksheet.store_mso_sp(75, spid, 0x0A00)
|
|
208
|
+
spid = spid + 1
|
|
209
|
+
data += @worksheet.store_mso_opt_image(image_id) +
|
|
210
|
+
@worksheet.store_mso_client_anchor(2, *vertices) +
|
|
211
|
+
@worksheet.store_mso_client_data
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def append(*args)
|
|
215
|
+
@worksheet.append(*args)
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
###############################################################################
|
|
3
|
+
#
|
|
4
|
+
# BIFFwriter - An abstract base class for Excel workbooks and worksheets.
|
|
5
|
+
#
|
|
6
|
+
#
|
|
7
|
+
# Used in conjunction with WriteExcel
|
|
8
|
+
#
|
|
9
|
+
# Copyright 2000-2010, John McNamara, jmcnamara@cpan.org
|
|
10
|
+
#
|
|
11
|
+
# original written in Perl by John McNamara
|
|
12
|
+
# converted to Ruby by Hideo Nakamura, cxn03651@msj.biglobe.ne.jp
|
|
13
|
+
#
|
|
14
|
+
class MaxSizeError < StandardError; end #:nodoc:
|
|
15
|
+
|
|
16
|
+
class OLEWriter #:nodoc:
|
|
17
|
+
|
|
18
|
+
# Not meant for public consumption
|
|
19
|
+
MaxSize = 7087104 # Use WriteExcel::Big to exceed this
|
|
20
|
+
BlockSize = 4096
|
|
21
|
+
BlockDiv = 512
|
|
22
|
+
ListBlocks = 127
|
|
23
|
+
|
|
24
|
+
attr_reader :biff_size, :book_size, :big_blocks, :list_blocks
|
|
25
|
+
attr_reader :root_start, :size_allowed
|
|
26
|
+
attr_accessor :biff_only, :internal_fh
|
|
27
|
+
|
|
28
|
+
# Accept an IO or IO-like object or a filename (as a String)
|
|
29
|
+
def initialize(arg)
|
|
30
|
+
if arg.respond_to?(:to_str)
|
|
31
|
+
@io = File.open(arg, "w")
|
|
32
|
+
else
|
|
33
|
+
@io = arg
|
|
34
|
+
end
|
|
35
|
+
@io.binmode if @io.respond_to?(:binmode)
|
|
36
|
+
|
|
37
|
+
@filehandle = ""
|
|
38
|
+
@fileclosed = false
|
|
39
|
+
@internal_fh = 0
|
|
40
|
+
@biff_only = 0
|
|
41
|
+
@size_allowed = true
|
|
42
|
+
@biff_size = 0
|
|
43
|
+
@book_size = 0
|
|
44
|
+
@big_blocks = 0
|
|
45
|
+
@list_blocks = 0
|
|
46
|
+
@root_start = 0
|
|
47
|
+
@block_count = 4
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Imitate IO.open behavior
|
|
51
|
+
|
|
52
|
+
###############################################################################
|
|
53
|
+
#
|
|
54
|
+
# _initialize()
|
|
55
|
+
#
|
|
56
|
+
# Create a new filehandle or use the provided filehandle.
|
|
57
|
+
#
|
|
58
|
+
def _initialize
|
|
59
|
+
olefile = @olefilename
|
|
60
|
+
|
|
61
|
+
# If the filename is a reference it is assumed that it is a valid
|
|
62
|
+
# filehandle, if not we create a filehandle.
|
|
63
|
+
#
|
|
64
|
+
|
|
65
|
+
# Create a new file, open for writing
|
|
66
|
+
fh = open(olefile, "wb")
|
|
67
|
+
|
|
68
|
+
# Workbook.pm also checks this but something may have happened since
|
|
69
|
+
# then.
|
|
70
|
+
raise "Can't open olefile. It may be in use or protected.\n" unless fh
|
|
71
|
+
|
|
72
|
+
@internal_fh = 1
|
|
73
|
+
|
|
74
|
+
# Store filehandle
|
|
75
|
+
@filehandle = fh
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def self.open(arg)
|
|
79
|
+
if block_given?
|
|
80
|
+
ole = self.new(arg)
|
|
81
|
+
result = yield(ole)
|
|
82
|
+
ole.close
|
|
83
|
+
result
|
|
84
|
+
else
|
|
85
|
+
self.new(arg)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
###############################################################################
|
|
90
|
+
#
|
|
91
|
+
# write($data)
|
|
92
|
+
#
|
|
93
|
+
# Write BIFF data to OLE file.
|
|
94
|
+
#
|
|
95
|
+
def write(data)
|
|
96
|
+
@io.write(data)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
###############################################################################
|
|
100
|
+
#
|
|
101
|
+
# set_size(biffsize)
|
|
102
|
+
#
|
|
103
|
+
# Set the size of the data to be written to the OLE stream
|
|
104
|
+
#
|
|
105
|
+
# $big_blocks = (109 depot block x (128 -1 marker word)
|
|
106
|
+
# - (1 x end words)) = 13842
|
|
107
|
+
# $maxsize = $big_blocks * 512 bytes = 7087104
|
|
108
|
+
#
|
|
109
|
+
def set_size(size = BlockSize)
|
|
110
|
+
if size > MaxSize
|
|
111
|
+
return @size_allowed = false
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
@biff_size = size
|
|
115
|
+
@book_size = [size, BlockSize].max
|
|
116
|
+
@size_allowed = true
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
###############################################################################
|
|
120
|
+
#
|
|
121
|
+
# _calculate_sizes()
|
|
122
|
+
#
|
|
123
|
+
# Calculate various sizes needed for the OLE stream
|
|
124
|
+
#
|
|
125
|
+
def calculate_sizes
|
|
126
|
+
@big_blocks = (@book_size.to_f/BlockDiv.to_f).ceil
|
|
127
|
+
@list_blocks = (@big_blocks / ListBlocks) + 1
|
|
128
|
+
@root_start = @big_blocks
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
###############################################################################
|
|
132
|
+
#
|
|
133
|
+
# close()
|
|
134
|
+
#
|
|
135
|
+
# Write root entry, big block list and close the filehandle.
|
|
136
|
+
# This routine is used to explicitly close the open filehandle without
|
|
137
|
+
# having to wait for DESTROY.
|
|
138
|
+
#
|
|
139
|
+
def close
|
|
140
|
+
if @size_allowed == true
|
|
141
|
+
write_padding if @biff_only == 0
|
|
142
|
+
write_property_storage if @biff_only == 0
|
|
143
|
+
write_big_block_depot if @biff_only == 0
|
|
144
|
+
end
|
|
145
|
+
@io.close
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
###############################################################################
|
|
149
|
+
#
|
|
150
|
+
# write_header()
|
|
151
|
+
#
|
|
152
|
+
# Write OLE header block.
|
|
153
|
+
#
|
|
154
|
+
def write_header
|
|
155
|
+
return if @biff_only == 1
|
|
156
|
+
calculate_sizes
|
|
157
|
+
root_start = @root_start
|
|
158
|
+
num_lists = @list_blocks
|
|
159
|
+
|
|
160
|
+
id = [0xD0CF11E0, 0xA1B11AE1].pack("NN")
|
|
161
|
+
unknown1 = [0x00, 0x00, 0x00, 0x00].pack("VVVV")
|
|
162
|
+
unknown2 = [0x3E, 0x03].pack("vv")
|
|
163
|
+
unknown3 = [-2].pack("v")
|
|
164
|
+
unknown4 = [0x09].pack("v")
|
|
165
|
+
unknown5 = [0x06, 0x00, 0x00].pack("VVV")
|
|
166
|
+
num_bbd_blocks = [num_lists].pack("V")
|
|
167
|
+
root_startblock = [root_start].pack("V")
|
|
168
|
+
unknown6 = [0x00, 0x1000].pack("VV")
|
|
169
|
+
sbd_startblock = [-2].pack("V")
|
|
170
|
+
unknown7 = [0x00, -2 ,0x00].pack("VVV")
|
|
171
|
+
|
|
172
|
+
write(id)
|
|
173
|
+
write(unknown1)
|
|
174
|
+
write(unknown2)
|
|
175
|
+
write(unknown3)
|
|
176
|
+
write(unknown4)
|
|
177
|
+
write(unknown5)
|
|
178
|
+
write(num_bbd_blocks)
|
|
179
|
+
write(root_startblock)
|
|
180
|
+
write(unknown6)
|
|
181
|
+
write(sbd_startblock)
|
|
182
|
+
write(unknown7)
|
|
183
|
+
|
|
184
|
+
unused = [-1].pack("V")
|
|
185
|
+
|
|
186
|
+
1.upto(num_lists){
|
|
187
|
+
root_start += 1
|
|
188
|
+
write([root_start].pack("V"))
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
num_lists.upto(108){
|
|
192
|
+
write(unused)
|
|
193
|
+
}
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
###############################################################################
|
|
197
|
+
#
|
|
198
|
+
# _write_big_block_depot()
|
|
199
|
+
#
|
|
200
|
+
# Write big block depot.
|
|
201
|
+
#
|
|
202
|
+
def write_big_block_depot
|
|
203
|
+
num_blocks = @big_blocks
|
|
204
|
+
num_lists = @list_blocks
|
|
205
|
+
total_blocks = num_lists * 128
|
|
206
|
+
used_blocks = num_blocks + num_lists + 2
|
|
207
|
+
|
|
208
|
+
marker = [-3].pack("V")
|
|
209
|
+
end_of_chain = [-2].pack("V")
|
|
210
|
+
unused = [-1].pack("V")
|
|
211
|
+
|
|
212
|
+
1.upto(num_blocks-1){|n|
|
|
213
|
+
write([n].pack("V"))
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
write end_of_chain
|
|
217
|
+
write end_of_chain
|
|
218
|
+
|
|
219
|
+
1.upto(num_lists){ write(marker) }
|
|
220
|
+
|
|
221
|
+
used_blocks.upto(total_blocks){ write(unused) }
|
|
222
|
+
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
###############################################################################
|
|
226
|
+
#
|
|
227
|
+
# _write_property_storage()
|
|
228
|
+
#
|
|
229
|
+
# Write property storage. TODO: add summary sheets
|
|
230
|
+
#
|
|
231
|
+
def write_property_storage
|
|
232
|
+
|
|
233
|
+
######### name type dir start size
|
|
234
|
+
write_pps('Root Entry', 0x05, 1, -2, 0x00)
|
|
235
|
+
write_pps('Workbook', 0x02, -1, 0x00, @book_size)
|
|
236
|
+
write_pps("", 0x00, -1, 0x00, 0x0000)
|
|
237
|
+
write_pps("", 0x00, -1, 0x00, 0x0000)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
###############################################################################
|
|
241
|
+
#
|
|
242
|
+
# _write_pps()
|
|
243
|
+
#
|
|
244
|
+
# Write property sheet in property storage
|
|
245
|
+
#
|
|
246
|
+
def write_pps(name, type, dir, start, size)
|
|
247
|
+
length = 0
|
|
248
|
+
ord_name = []
|
|
249
|
+
unless name.empty?
|
|
250
|
+
name = name + "\0"
|
|
251
|
+
ord_name = name.unpack("c*")
|
|
252
|
+
length = name.bytesize * 2
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
rawname = ord_name.pack("v*")
|
|
256
|
+
zero = [0].pack("C")
|
|
257
|
+
|
|
258
|
+
pps_sizeofname = [length].pack("v") #0x40
|
|
259
|
+
pps_type = [type].pack("v") #0x42
|
|
260
|
+
pps_prev = [-1].pack("V") #0x44
|
|
261
|
+
pps_next = [-1].pack("V") #0x48
|
|
262
|
+
pps_dir = [dir].pack("V") #0x4c
|
|
263
|
+
|
|
264
|
+
unknown = [0].pack("V")
|
|
265
|
+
|
|
266
|
+
pps_ts1s = [0].pack("V") #0x64
|
|
267
|
+
pps_ts1d = [0].pack("V") #0x68
|
|
268
|
+
pps_ts2s = [0].pack("V") #0x6c
|
|
269
|
+
pps_ts2d = [0].pack("V") #0x70
|
|
270
|
+
pps_sb = [start].pack("V") #0x74
|
|
271
|
+
pps_size = [size].pack("V") #0x78
|
|
272
|
+
|
|
273
|
+
write(rawname)
|
|
274
|
+
write(zero * (64 - length)) if 64 - length >= 1
|
|
275
|
+
write(pps_sizeofname)
|
|
276
|
+
write(pps_type)
|
|
277
|
+
write(pps_prev)
|
|
278
|
+
write(pps_next)
|
|
279
|
+
write(pps_dir)
|
|
280
|
+
write(unknown * 5)
|
|
281
|
+
write(pps_ts1s)
|
|
282
|
+
write(pps_ts1d)
|
|
283
|
+
write(pps_ts2s)
|
|
284
|
+
write(pps_ts2d)
|
|
285
|
+
write(pps_sb)
|
|
286
|
+
write(pps_size)
|
|
287
|
+
write(unknown)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
###############################################################################
|
|
291
|
+
#
|
|
292
|
+
# _write_padding()
|
|
293
|
+
#
|
|
294
|
+
# Pad the end of the file
|
|
295
|
+
#
|
|
296
|
+
def write_padding
|
|
297
|
+
min_size = 512
|
|
298
|
+
min_size = BlockSize if @biff_size < BlockSize
|
|
299
|
+
|
|
300
|
+
if @biff_size % min_size != 0
|
|
301
|
+
padding = min_size - (@biff_size % min_size)
|
|
302
|
+
write("\0" * padding)
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
end
|