thinreports 0.8.0 → 0.8.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +10 -2
- data/examples/palleted_png/palleted_png.png +0 -0
- data/examples/palleted_png/palleted_png.rb +9 -0
- data/examples/palleted_png/palleted_png.tlf +1 -0
- data/lib/thinreports/config.rb +14 -0
- data/lib/thinreports/generator/pdf/document/draw_shape.rb +3 -2
- data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +3 -2
- data/lib/thinreports/generator/pdf/document/graphics/image.rb +114 -19
- data/lib/thinreports/generator/pdf/document/parse_svg.rb +3 -2
- data/lib/thinreports/report/base.rb +0 -3
- data/lib/thinreports/report/internal.rb +14 -5
- data/lib/thinreports/version.rb +1 -1
- data/test/data/image_normal.jpg +0 -0
- data/test/data/image_normal.png +0 -0
- data/test/data/image_normal_jpg_noext +0 -0
- data/test/data/image_normal_png_noext +0 -0
- data/test/data/image_pallete_based.png +0 -0
- data/test/test_helper.rb +5 -0
- data/test/unit/generator/pdf/document/graphics/test_attributes.rb +25 -25
- data/test/unit/generator/pdf/document/graphics/test_image.rb +150 -0
- data/test/unit/test_config.rb +8 -0
- data/thinreports.gemspec +1 -0
- metadata +32 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84effddcf79a2fdea2e5fbaa87f1f8fb5e170c47
|
4
|
+
data.tar.gz: e4e954c45566cc49b69fd0bb7a46700e5970ac93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f542af1a90cdcb26fb7ba24cb94fad484367b5e9dba8f6ebf527b5c5307a3fca546dd25b6e9f71ec32c0c37a2e93ea9c71a2baefa3641c60d46f47316a43e7c
|
7
|
+
data.tar.gz: dfad16c6e2cf3afae658344c6dbd20817a77408c3cc4d81e51fef0d520a20ec95050bc2141117bbdae8cc59a49d2fad28ced5f5a9935c9e0e56177477293373a
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 0.8.1
|
2
|
+
|
3
|
+
### Add OPTIONAL feature for converting a palette-based PNG w. transparency
|
4
|
+
|
5
|
+
This feature is **DISABLED** by default. Please see [PR#32](https://github.com/thinreports/thinreports-generator/pull/32) for further details.
|
6
|
+
|
1
7
|
## 0.8.0
|
2
8
|
|
3
9
|
This release is a stepping stone to next major version 1.0.0 release.
|
@@ -113,11 +119,13 @@ See [Issue #18](https://github.com/thinreports/thinreports-generator/issues/18)
|
|
113
119
|
# New setter, same as `page.item(:text_block).value = 'tblock value'`
|
114
120
|
page[:text_block] = 'tblock value'
|
115
121
|
# New getter, same as `page.item(:text_block).value`
|
116
|
-
page[:text_block] # =>
|
122
|
+
page[:text_block] # => <Tblock>
|
123
|
+
page[:text_block].value # => "tblock value"
|
117
124
|
page.item(:text_block).value # => "tblock value"
|
118
125
|
|
119
126
|
page[:image_block] = '/path/to/image.png'
|
120
|
-
page[:image_block] # => "/path/to/image.png"
|
127
|
+
page[:image_block].src # => "/path/to/image.png"
|
128
|
+
page.item(:image_block).src # => "/path/to/image.png"
|
121
129
|
```
|
122
130
|
|
123
131
|
See [Issue #22](https://github.com/thinreports/thinreports-generator/issues/22) for further details.
|
Binary file
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
example :palleted_png, 'Rendering a palleted PNG with transparency' do |t|
|
4
|
+
report = Thinreports::Report.new layout: t.layout_filename
|
5
|
+
report.start_new_page do |page|
|
6
|
+
page.item(:image).src = t.resource('palleted_png.png')
|
7
|
+
end
|
8
|
+
report.generate filename: t.output_filename
|
9
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":"0.8.2","config":{"title":"","option":{},"page":{"paper-type":"A4","orientation":"portrait","margin-top":"20","margin-bottom":"20","margin-left":"20","margin-right":"20"}},"svg":"<svg width=\"595.2\" height=\"841.8\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" preserveAspectRatio=\"none\" viewBox=\"0 0 595.2 841.8\"><g class=\"canvas\"><image image-rendering=\"optimizeQuality\" preserveAspectRatio=\"none\" class=\"s-image\" x-display=\"true\" x-id=\"\" id=\"goog_604222137\" x=\"20\" y=\"20\" x-natural-width=\"200\" x-natural-height=\"200\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xlink:href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAD1BMVEX/AAD/AAD/AAD/AAD////Icf73AAAAA3RSTlO/fz8qtTX3AAAAAWJLR0QEj2jZUQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAMtJREFUeNrtzwERgEAAw7AH/HtGBr2RKGjPM+J8HWDESJyRGiM1RmqM1BipMVJjpMZIjZEaIzVGaozUGKkxUmOkxkiNkRojNUZqjNQYqTFSszMCAAAAAAAAAAAA/3SNMFJjpMZIjZEaIzVGaozUGKkxUmOkxkiNkRojNUZqjNQYqTFSY6TGSI2RGiM1RmqM1Bip2Rm5RxipMVJjpMZIjZEaIzVGaozUGKkxUmOkxkiNkRojNUZqjNQYqTFSY6TGSI2RGiM1RmqM1MyMvMkE6mEsuD8jAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE0LTEwLTA5VDEwOjM1OjI1KzAyOjAwxhRVNQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNC0xMC0wOVQxMDozNToyNSswMjowMLdJ7YkAAAAASUVORK5CYII=\" width=\"200\" height=\"200\"/><!--SHAPE{\"type\":\"s-iblock\",\"id\":\"image\",\"display\":\"true\",\"desc\":null,\"box\":{\"x\":278.2,\"y\":20,\"width\":266.7,\"height\":223.7},\"position-x\":\"left\",\"position-y\":\"top\",\"svg\":{\"tag\":\"image\",\"attrs\":{\"x\":278.2,\"y\":20,\"width\":266.7,\"height\":223.7}}}SHAPE--><!--LAYOUT<g xmlns=\"http://www.w3.org/2000/svg\" class=\"s-iblock\" x-display=\"true\" id=\"goog_604222139\" x-id=\"image\" x-width=\"266.7\" x-height=\"223.7\" x-left=\"278.2\" x-top=\"20\"><rect class=\"s-iblock-box\" stroke=\"none\" fill=\"#0096fd\" fill-opacity=\"0.2\" width=\"266.7\" height=\"223.7\" x=\"278.2\" y=\"20\"/><image width=\"16\" height=\"16\" class=\"s-iblock-mark\" opacity=\"0.5\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xlink:href=\"assets/icons/x-image-mark.svg\" display=\"inline\" x=\"403.2\" y=\"123\"/><text class=\"s-iblock-id\" font-size=\"10.5\" font-family=\"Helvetica\" font-weight=\"normal\" font-style=\"normal\" text-decoration=\"none\" text-anchor=\"start\" kerning=\"auto\" stroke=\"none\" fill=\"#0096fd\" fill-opacity=\"1\" x=\"282.2\" y=\"31\">image</text></g>LAYOUT--></g></svg>","state":{"layout-guide":[]}}
|
data/lib/thinreports/config.rb
CHANGED
@@ -15,6 +15,7 @@ module Thinreports
|
|
15
15
|
class Configuration
|
16
16
|
def initialize
|
17
17
|
@fallback_fonts = []
|
18
|
+
@convert_palleted_transparency_png = false
|
18
19
|
end
|
19
20
|
|
20
21
|
# @return [Array<String>]
|
@@ -33,6 +34,19 @@ module Thinreports
|
|
33
34
|
@fallback_fonts = font_names.is_a?(Array) ? font_names : [font_names]
|
34
35
|
end
|
35
36
|
|
37
|
+
# @return [Boolean]
|
38
|
+
# @see https://github.com/thinreports/thinreports-generator/pull/32
|
39
|
+
attr_reader :convert_palleted_transparency_png
|
40
|
+
|
41
|
+
# @param [Boolean]
|
42
|
+
# @example
|
43
|
+
# config.convert_palleted_transparency_png = true
|
44
|
+
# config.convert_palleted_transparency_png = false # default
|
45
|
+
# @see https://github.com/thinreports/thinreports-generator/pull/32
|
46
|
+
def convert_palleted_transparency_png=(enable)
|
47
|
+
@convert_palleted_transparency_png = enable
|
48
|
+
end
|
49
|
+
|
36
50
|
# @return [Thinreports::Generator::Configuration]
|
37
51
|
def generator
|
38
52
|
@generator ||= Thinreports::Generator::Configuration.new
|
@@ -30,8 +30,9 @@ module Thinreports
|
|
30
30
|
# @param [Thinreports::Core::Shape::Basic::Internal] shape
|
31
31
|
def draw_shape_image(shape)
|
32
32
|
x, y, w, h = shape.style.svg_attrs.values_at('x', 'y', 'width', 'height')
|
33
|
-
|
34
|
-
|
33
|
+
|
34
|
+
image_type, image_data = extract_base64_string(shape.style.svg_attrs['xlink:href'])
|
35
|
+
base64image(image_type, image_data, x, y, w, h)
|
35
36
|
end
|
36
37
|
|
37
38
|
# @param [Thinreports::Core::Shape::ImageBlock::Internal] shape
|
@@ -116,9 +116,10 @@ module Thinreports
|
|
116
116
|
end
|
117
117
|
|
118
118
|
# @param [String] xlink
|
119
|
-
# @return [
|
119
|
+
# @return [Array<string>] returns ['image/png', '<base64 data>']
|
120
120
|
def extract_base64_string(xlink)
|
121
|
-
xlink.
|
121
|
+
_, type, data = xlink.match(%r|^data:(image/[a-z]+?);base64,(.+)|).to_a
|
122
|
+
[type, data]
|
122
123
|
end
|
123
124
|
end
|
124
125
|
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'tempfile'
|
4
4
|
require 'base64'
|
5
|
+
require 'digest/md5'
|
6
|
+
require 'chunky_png'
|
5
7
|
|
6
8
|
module Thinreports
|
7
9
|
module Generator
|
@@ -17,14 +19,15 @@ module Thinreports
|
|
17
19
|
pdf.image(filename, at: pos(x, y), width: w, height: h)
|
18
20
|
end
|
19
21
|
|
22
|
+
# @param [String] image_type Mime-type of image
|
20
23
|
# @param [String] base64
|
21
24
|
# @param [Numeric, Strng] x
|
22
25
|
# @param [Numeric, Strng] y
|
23
26
|
# @param [Numeric, Strng] w
|
24
27
|
# @param [Numeric, Strng] h
|
25
|
-
def base64image(
|
26
|
-
|
27
|
-
image(
|
28
|
+
def base64image(image_type, base64_data, x, y, w, h)
|
29
|
+
image_path = normalize_image_from_base64(image_type, base64_data)
|
30
|
+
image(image_path, x, y, w, h)
|
28
31
|
end
|
29
32
|
|
30
33
|
# @param file (see Prawn#image)
|
@@ -36,34 +39,126 @@ module Thinreports
|
|
36
39
|
# @option options [:left, :center, :right] :position_x (:left)
|
37
40
|
# @option options [:top, :center, :bottom] :position_y (:top)
|
38
41
|
def image_box(file, x, y, w, h, options = {})
|
42
|
+
image_path = normalize_image_from_file(file)
|
43
|
+
|
39
44
|
w, h = s2f(w, h)
|
40
45
|
pdf.bounding_box(pos(x, y), width: w, height: h) do
|
41
|
-
pdf.image(
|
42
|
-
|
43
|
-
|
46
|
+
pdf.image(image_path, position: options[:position_x] || :left,
|
47
|
+
vposition: options[:position_y] || :top,
|
48
|
+
auto_fit: [w, h])
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
47
|
-
|
52
|
+
def normalize_image_from_base64(image_type, base64_string)
|
53
|
+
raw_image_data = Base64.decode64(base64_string)
|
54
|
+
|
55
|
+
image_data = if png_conversion_enabled? && image_type == 'image/png'
|
56
|
+
png_normalizer = PNGNormalizer.load_blob(raw_image_data)
|
57
|
+
|
58
|
+
if png_normalizer.need_normalize?
|
59
|
+
png_normalizer.normalize
|
60
|
+
else
|
61
|
+
raw_image_data
|
62
|
+
end
|
63
|
+
else
|
64
|
+
raw_image_data
|
65
|
+
end
|
66
|
+
|
67
|
+
image_id = Digest::MD5.hexdigest(base64_string)
|
68
|
+
create_temp_imagefile(image_id, image_data)
|
69
|
+
end
|
70
|
+
|
71
|
+
def normalize_image_from_file(filename)
|
72
|
+
extname = File.extname(filename)
|
73
|
+
|
74
|
+
return filename unless png_conversion_enabled?
|
75
|
+
return filename unless extname.downcase == '.png' || extname.empty?
|
76
|
+
|
77
|
+
return temp_image_registry[filename] if temp_image_registry.key?(filename)
|
78
|
+
|
79
|
+
png_normalizer = PNGNormalizer.load_file(filename)
|
80
|
+
|
81
|
+
# Returns the original filename when the image is not PNG.
|
82
|
+
return filename if png_normalizer.nil?
|
83
|
+
return filename unless png_normalizer.need_normalize?
|
84
|
+
|
85
|
+
image_id = filename
|
86
|
+
image_data = png_normalizer.normalize
|
87
|
+
|
88
|
+
create_temp_imagefile(image_id, image_data)
|
89
|
+
end
|
48
90
|
|
49
91
|
def clean_temp_images
|
50
|
-
temp_image_registry.
|
92
|
+
temp_image_registry.each_value do |image_path|
|
93
|
+
File.delete(image_path) if File.exists?(image_path)
|
94
|
+
end
|
51
95
|
end
|
52
96
|
|
53
97
|
def temp_image_registry
|
54
|
-
@temp_image_registry ||=
|
98
|
+
@temp_image_registry ||= {}
|
55
99
|
end
|
56
100
|
|
57
|
-
# @param [String]
|
58
|
-
# @
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
101
|
+
# @param [String] image_id
|
102
|
+
# @param [String] image_data
|
103
|
+
# @return [String] imagefile path
|
104
|
+
def create_temp_imagefile(image_id, image_data)
|
105
|
+
temp_image_registry[image_id] ||= begin
|
106
|
+
file = Tempfile.new('temp-image')
|
107
|
+
file.binmode
|
108
|
+
file.write(image_data)
|
109
|
+
file.path
|
110
|
+
ensure
|
111
|
+
file.close
|
112
|
+
end
|
113
|
+
temp_image_registry[image_id]
|
114
|
+
end
|
115
|
+
|
116
|
+
def png_conversion_enabled?
|
117
|
+
Thinreports.config.convert_palleted_transparency_png
|
118
|
+
end
|
119
|
+
|
120
|
+
class PNGNormalizer
|
121
|
+
def self.load_file(filename)
|
122
|
+
image = ChunkyPNG::Image.from_file(filename)
|
123
|
+
datastream = ChunkyPNG::Datastream.from_file(filename)
|
124
|
+
self.new image, datastream
|
125
|
+
rescue ChunkyPNG::SignatureMismatch
|
126
|
+
# Returns nil if image is not PNG.
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.load_blob(data)
|
131
|
+
image = ChunkyPNG::Image.from_blob(data)
|
132
|
+
datastream = ChunkyPNG::Datastream.from_blob(data)
|
133
|
+
self.new image, datastream
|
134
|
+
rescue ChunkyPNG::SignatureMismatch
|
135
|
+
# Returns nil if image is not PNG.
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
|
139
|
+
def initialize(image, datastream)
|
140
|
+
@image = image
|
141
|
+
@datastream = datastream
|
142
|
+
end
|
143
|
+
|
144
|
+
def need_normalize?
|
145
|
+
pallete_based? && transparency_chunk?
|
146
|
+
end
|
147
|
+
|
148
|
+
def normalize
|
149
|
+
@image.to_blob(color_mode: ChunkyPNG::COLOR_TRUECOLOR_ALPHA)
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def pallete_based?
|
155
|
+
color_mode, depth = @image.palette.best_color_settings
|
156
|
+
color_mode == ChunkyPNG::COLOR_INDEXED
|
157
|
+
end
|
158
|
+
|
159
|
+
def transparency_chunk?
|
160
|
+
!@datastream.transparency_chunk.nil?
|
161
|
+
end
|
67
162
|
end
|
68
163
|
end
|
69
164
|
|
@@ -78,8 +78,9 @@ module Thinreports
|
|
78
78
|
# @see #draw_svg_rect
|
79
79
|
def draw_svg_image(elm)
|
80
80
|
x, y, w, h = element_attributes_values_at(elm, 'x', 'y', 'width', 'height')
|
81
|
-
|
82
|
-
|
81
|
+
|
82
|
+
image_type, image_data = extract_base64_string(elm.attributes['xlink:href'])
|
83
|
+
base64image(image_type, image_data, x, y, w, h)
|
83
84
|
end
|
84
85
|
|
85
86
|
# @param [Hash] attributes
|
@@ -12,7 +12,6 @@ module Thinreports
|
|
12
12
|
attr_reader :events
|
13
13
|
|
14
14
|
attr_accessor :page_create_handler
|
15
|
-
attr_accessor :generate_handler
|
16
15
|
|
17
16
|
# @param [Thinreports::Report::Base] report
|
18
17
|
# @param options (see Thinreports::Report::Base#initialize)
|
@@ -28,7 +27,6 @@ module Thinreports
|
|
28
27
|
@page_count = 0
|
29
28
|
|
30
29
|
@page_create_handler = nil
|
31
|
-
@generate_handler = nil
|
32
30
|
|
33
31
|
@events = Report::Events.new
|
34
32
|
end
|
@@ -63,11 +61,22 @@ module Thinreports
|
|
63
61
|
finalize_current_page
|
64
62
|
@finalized = true
|
65
63
|
|
66
|
-
# [DEPRECATION]
|
64
|
+
# [DEPRECATION] You can do the same implements as the :generate Event
|
65
|
+
# with the following code:
|
66
|
+
#
|
67
|
+
# report = Thinreports::Report.new layout: 'foo.tlf'
|
68
|
+
# report.start_new_page do |page|
|
69
|
+
# page.item(:price).value = 100000
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# report.pages.each do |page|
|
73
|
+
# page[:title] = 'Common Title'
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# report.generate filename: 'foo.pdf'
|
77
|
+
#
|
67
78
|
events.dispatch(Report::Events::Event.new(:generate,
|
68
79
|
@report, nil, pages))
|
69
|
-
|
70
|
-
@generate_handler.call(pages) if @generate_handler
|
71
80
|
end
|
72
81
|
end
|
73
82
|
|
data/lib/thinreports/version.rb
CHANGED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/test/test_helper.rb
CHANGED
@@ -8,6 +8,7 @@ require 'mocha/mini_test'
|
|
8
8
|
|
9
9
|
require 'digest/sha1'
|
10
10
|
require 'pathname'
|
11
|
+
require 'chunky_png'
|
11
12
|
require 'thinreports'
|
12
13
|
|
13
14
|
module Thinreports::TestHelper
|
@@ -48,6 +49,10 @@ module Thinreports::TestHelper
|
|
48
49
|
ROOT.join('data', filename).to_s
|
49
50
|
end
|
50
51
|
|
52
|
+
def read_data_file(filename)
|
53
|
+
File.read(data_file(filename))
|
54
|
+
end
|
55
|
+
|
51
56
|
def temp_file(extname = 'pdf')
|
52
57
|
filename = (('a'..'z').to_a + (0..9).to_a).shuffle[0, 8].join + ".#{extname}"
|
53
58
|
temp_path.join(filename).to_s
|
@@ -4,11 +4,11 @@ require 'test_helper'
|
|
4
4
|
|
5
5
|
class Thinreports::Generator::PDF::Graphics::TestAttributes < Minitest::Test
|
6
6
|
include Thinreports::TestHelper
|
7
|
-
|
7
|
+
|
8
8
|
def setup
|
9
9
|
@pdf = Thinreports::Generator::PDF::Document.new
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def test_common_graphic_attrs_should_return_converted_Hash_as_attributes
|
13
13
|
result = @pdf.common_graphic_attrs('stroke' => '#ff0000',
|
14
14
|
'stroke-width' => '1',
|
@@ -16,41 +16,41 @@ class Thinreports::Generator::PDF::Graphics::TestAttributes < Minitest::Test
|
|
16
16
|
assert_equal result.values_at(:stroke, :stroke_width, :fill),
|
17
17
|
['#ff0000', '1', '#0000ff']
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def test_common_graphic_attrs_should_return_the_stroke_dash_attribute_into_an_array
|
21
21
|
result = @pdf.common_graphic_attrs('stroke-dasharray' => '3,5')
|
22
22
|
assert_equal result[:stroke_dash], %w( 3 5 )
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def test_common_graphic_attrs_should_return_nil_as_a_value_of_stroke_dash_attribute_when_value_is_none
|
26
26
|
result = @pdf.common_graphic_attrs('stroke-dasharray' => 'none')
|
27
27
|
assert_nil result[:stroke_dash]
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def test_common_graphic_attrs_should_return_nil_as_a_value_of_stroke_dash_attribute_when_value_is_empty
|
31
31
|
result = @pdf.common_graphic_attrs({})
|
32
32
|
assert_nil result[:stroke_dash]
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def test_common_graphic_attrs_should_set_0_as_a_value_of_stroke_width_attribute_when_opacity_is_0
|
36
36
|
result = @pdf.common_graphic_attrs('stroke-width' => '1',
|
37
37
|
'stroke-opacity' => '0')
|
38
38
|
assert_equal result[:stroke_width], 0
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def test_common_graphic_attrs_with_block
|
42
42
|
result = @pdf.common_graphic_attrs('stroke' => '#ff0000') do |attrs|
|
43
43
|
attrs[:stroke].gsub!(/0/, 'f')
|
44
44
|
end
|
45
45
|
assert_equal result[:stroke], '#ffffff'
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def test_text_align_should_return_converted_value_type_of_Symbol
|
49
49
|
aligns = ['start', 'middle', 'end', nil]
|
50
50
|
assert_equal aligns.map {|a| @pdf.text_align(a) },
|
51
51
|
[:left, :center, :right, :left]
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
def test_text_valign_should_return_converted_value_type_of_Symbol
|
55
55
|
valigns = ['top', 'center', 'bottom', nil]
|
56
56
|
assert_equal valigns.map {|a| @pdf.text_valign(a) },
|
@@ -62,76 +62,76 @@ class Thinreports::Generator::PDF::Graphics::TestAttributes < Minitest::Test
|
|
62
62
|
assert_equal @pdf.text_word_wrap('none'), :none
|
63
63
|
assert_equal @pdf.text_word_wrap(''), :none
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
def test_extract_base64_string
|
67
67
|
base64 = 'data:image/png;base64,iVBORw0KGg1+/AAy/plYlzil'
|
68
68
|
assert_equal @pdf.extract_base64_string(base64),
|
69
|
-
'iVBORw0KGg1+/AAy/plYlzil'
|
69
|
+
['image/png', 'iVBORw0KGg1+/AAy/plYlzil']
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
def test_font_styles_should_return_bold_style_when_font_weight_is_bold
|
73
73
|
assert_equal @pdf.font_styles('font-weight' => 'bold'), [:bold]
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
def test_font_styles_should_return_italic_style_when_font_style_is_italic
|
77
77
|
assert_equal @pdf.font_styles('font-style' => 'italic'), [:italic]
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
def test_font_styles_should_return_underline_and_strikethrough_style_via_text_decoration
|
81
81
|
assert_equal @pdf.font_styles('text-decoration' => 'underline line-through'),
|
82
82
|
[:underline, :strikethrough]
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
def test_common_text_attrs_should_return_the_value_of_font_family_as_font
|
86
86
|
result = @pdf.common_text_attrs('font-family' => 'IPAMincho')
|
87
87
|
assert_equal result[:font], 'IPAMincho'
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
def test_common_text_attrs_should_return_the_value_of_font_size_as_size
|
91
91
|
result = @pdf.common_text_attrs('font-size' => '12')
|
92
92
|
assert_equal result[:size], '12'
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
def test_common_text_attrs_should_return_the_value_of_fill_color_as_color
|
96
96
|
result = @pdf.common_text_attrs('fill' => '#000000')
|
97
97
|
assert_equal result[:color], '#000000'
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
def test_common_text_attrs_should_return_the_value_of_text_anchor_as_align
|
101
101
|
result = @pdf.common_text_attrs('text-anchor' => 'middle')
|
102
102
|
assert_equal result[:align], :center
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
def test_common_text_attrs_should_return_the_value_of_text_styles_as_styles
|
106
106
|
result = @pdf.common_text_attrs('font-weight' => 'bold')
|
107
107
|
assert_equal result[:styles], [:bold]
|
108
108
|
end
|
109
|
-
|
109
|
+
|
110
110
|
def test_common_text_attrs_should_return_the_value_of_letter_spacing_as_letter_spacing
|
111
111
|
result = @pdf.common_text_attrs('letter-spacing' => '5')
|
112
112
|
assert_equal result[:letter_spacing], '5'
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
def test_common_text_attrs_should_return_the_value_of_kerning_as_letter_spacing
|
116
116
|
result = @pdf.common_text_attrs('kerning' => '10')
|
117
117
|
assert_equal result[:letter_spacing], '10'
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
def test_common_text_attrs_with_block
|
121
121
|
result = @pdf.common_text_attrs('fill' => '#000000') do |attrs|
|
122
122
|
attrs[:color].gsub!(/0/, 'f')
|
123
123
|
end
|
124
124
|
assert_equal result[:color], '#ffffff'
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
def test_text_letter_spacing_should_return_raw_value
|
128
128
|
assert_equal @pdf.text_letter_spacing('10'), '10'
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
def test_text_letter_spacing_should_return_nil_when_value_is_normal
|
132
132
|
assert_nil @pdf.text_letter_spacing('normal')
|
133
133
|
end
|
134
|
-
|
134
|
+
|
135
135
|
def test_text_letter_spacing_should_return_nil_when_value_is_auto
|
136
136
|
assert_nil @pdf.text_letter_spacing('auto')
|
137
137
|
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
require 'base64'
|
6
|
+
require 'digest/md5'
|
7
|
+
|
8
|
+
class Thinreports::Generator::PDF::Graphics::TestImage < Minitest::Test
|
9
|
+
include Thinreports::TestHelper
|
10
|
+
|
11
|
+
class TestImage
|
12
|
+
include Thinreports::Generator::PDF::Graphics
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_normalize_image_from_base64_in_disabled
|
16
|
+
Thinreports.config.convert_palleted_transparency_png = false
|
17
|
+
|
18
|
+
test_image = TestImage.new
|
19
|
+
base64_image = Base64.encode64(read_data_file('image_normal.png'))
|
20
|
+
|
21
|
+
# Should not be normalized
|
22
|
+
TestImage::PNGNormalizer.stubs(:load_blob).never
|
23
|
+
test_image.normalize_image_from_base64('image/png', base64_image)
|
24
|
+
|
25
|
+
image_registry = test_image.temp_image_registry
|
26
|
+
assert_equal 1, image_registry.count
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_normalize_image_from_file_in_disabled
|
30
|
+
Thinreports.config.convert_palleted_transparency_png = false
|
31
|
+
|
32
|
+
original_image_path = data_file('image_pallete_based.png')
|
33
|
+
|
34
|
+
test_image = TestImage.new
|
35
|
+
returned_image_path = test_image.normalize_image_from_file(original_image_path)
|
36
|
+
|
37
|
+
# Should not be normalized
|
38
|
+
assert_empty test_image.temp_image_registry
|
39
|
+
assert_same original_image_path, returned_image_path
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_normalize_image_from_base64_with_normal_images
|
43
|
+
Thinreports.config.convert_palleted_transparency_png = true
|
44
|
+
|
45
|
+
[
|
46
|
+
['image/png', 'image_normal.png'],
|
47
|
+
['image/jpeg', 'image_normal.jpg']
|
48
|
+
]
|
49
|
+
.each do |(image_type, image_file)|
|
50
|
+
base64_normal_image = Base64.encode64(read_data_file(image_file))
|
51
|
+
|
52
|
+
test_image = TestImage.new
|
53
|
+
|
54
|
+
normalized_image_path = test_image.normalize_image_from_base64(image_type, base64_normal_image)
|
55
|
+
|
56
|
+
image_registry = test_image.temp_image_registry
|
57
|
+
assert_equal 1, image_registry.count
|
58
|
+
|
59
|
+
image_id = Digest::MD5.hexdigest(base64_normal_image)
|
60
|
+
assert_includes image_registry.keys, image_id
|
61
|
+
assert_equal normalized_image_path, image_registry[image_id]
|
62
|
+
|
63
|
+
assert equal_image(data_file(image_file), normalized_image_path)
|
64
|
+
|
65
|
+
assert_same normalized_image_path,
|
66
|
+
test_image.normalize_image_from_base64(image_type, base64_normal_image)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_normalize_image_from_base64_with_palette_transparency_png
|
71
|
+
Thinreports.config.convert_palleted_transparency_png = true
|
72
|
+
|
73
|
+
base64_palleted_png = Base64.encode64(read_data_file('image_pallete_based.png'))
|
74
|
+
|
75
|
+
test_image = TestImage.new
|
76
|
+
|
77
|
+
normalized_image_path = test_image.normalize_image_from_base64('image/png', base64_palleted_png)
|
78
|
+
|
79
|
+
image_registry = test_image.temp_image_registry
|
80
|
+
assert_equal 1, image_registry.count
|
81
|
+
|
82
|
+
image_id = Digest::MD5.hexdigest(base64_palleted_png)
|
83
|
+
assert_includes image_registry.keys, image_id
|
84
|
+
assert_equal normalized_image_path, image_registry[image_id]
|
85
|
+
|
86
|
+
refute equal_image(data_file('image_pallete_based.png'), normalized_image_path)
|
87
|
+
|
88
|
+
assert_not_palette_based_transparency_png File.read(normalized_image_path)
|
89
|
+
|
90
|
+
# 2nd time
|
91
|
+
assert_same normalized_image_path,
|
92
|
+
test_image.normalize_image_from_base64('image/png', base64_palleted_png)
|
93
|
+
assert_equal 1, test_image.temp_image_registry.count
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_normalize_image_from_file_with_normal_images
|
97
|
+
Thinreports.config.convert_palleted_transparency_png = true
|
98
|
+
|
99
|
+
[
|
100
|
+
data_file('image_normal.png'),
|
101
|
+
data_file('iamge_normal.jpg'),
|
102
|
+
data_file('image_normal_png_noext'),
|
103
|
+
data_file('image_normal_jpg_noext')
|
104
|
+
]
|
105
|
+
.each do |original_image_path|
|
106
|
+
test_image = TestImage.new
|
107
|
+
image_path = test_image.normalize_image_from_file(original_image_path)
|
108
|
+
|
109
|
+
assert_equal original_image_path, image_path
|
110
|
+
assert_empty test_image.temp_image_registry
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_normalize_image_from_file_with_palette_transparency_png
|
115
|
+
Thinreports.config.convert_palleted_transparency_png = true
|
116
|
+
|
117
|
+
original_image_path = data_file('image_pallete_based.png')
|
118
|
+
|
119
|
+
test_image = TestImage.new
|
120
|
+
|
121
|
+
normalized_image_path = test_image.normalize_image_from_file(original_image_path)
|
122
|
+
image_registry = test_image.temp_image_registry
|
123
|
+
|
124
|
+
assert_equal 1, image_registry.count
|
125
|
+
assert_includes image_registry.keys, original_image_path
|
126
|
+
|
127
|
+
refute equal_image(original_image_path, normalized_image_path)
|
128
|
+
|
129
|
+
assert_not_palette_based_transparency_png File.read(normalized_image_path)
|
130
|
+
|
131
|
+
# It should never called in 2nd time or subsequent.
|
132
|
+
TestImage::PNGNormalizer.stubs(:load_file).never
|
133
|
+
assert_same normalized_image_path,
|
134
|
+
test_image.normalize_image_from_file(original_image_path)
|
135
|
+
end
|
136
|
+
|
137
|
+
def assert_not_palette_based_transparency_png(data)
|
138
|
+
image_data = ChunkyPNG::Image.from_blob(data)
|
139
|
+
datastream = ChunkyPNG::Datastream.from_blob(data)
|
140
|
+
|
141
|
+
assert_equal ChunkyPNG::COLOR_INDEXED, image_data.palette.best_color_settings.first
|
142
|
+
assert_equal nil, datastream.transparency_chunk
|
143
|
+
end
|
144
|
+
|
145
|
+
def equal_image(expect_path, actual_path)
|
146
|
+
expect_image = File.binread(expect_path)
|
147
|
+
actual_image = File.binread(actual_path)
|
148
|
+
expect_image == actual_image
|
149
|
+
end
|
150
|
+
end
|
data/test/unit/test_config.rb
CHANGED
@@ -20,6 +20,14 @@ class Thinreports::TestConfig < Minitest::Test
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_convert_palleted_transparency_png
|
24
|
+
config = Thinreports::Configuration.new
|
25
|
+
assert_equal false, config.convert_palleted_transparency_png
|
26
|
+
|
27
|
+
config.convert_palleted_transparency_png = true
|
28
|
+
assert_equal true, config.convert_palleted_transparency_png
|
29
|
+
end
|
30
|
+
|
23
31
|
def test_fallback_fonts
|
24
32
|
config = Thinreports::Configuration.new
|
25
33
|
|
data/thinreports.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thinreports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matsukei Co.,Ltd.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: prawn
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.3.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: chunky_png
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -133,6 +147,9 @@ files:
|
|
133
147
|
- examples/list_page_number/list_page_number.tlf
|
134
148
|
- examples/page_number/page_number.rb
|
135
149
|
- examples/page_number/page_number.tlf
|
150
|
+
- examples/palleted_png/palleted_png.png
|
151
|
+
- examples/palleted_png/palleted_png.rb
|
152
|
+
- examples/palleted_png/palleted_png.tlf
|
136
153
|
- examples/password_setting/password_setting.rb
|
137
154
|
- examples/password_setting/password_setting.tlf
|
138
155
|
- examples/report_callbacks/report_callbacks.rb
|
@@ -248,6 +265,11 @@ files:
|
|
248
265
|
- lib/thinreports/report/page.rb
|
249
266
|
- lib/thinreports/version.rb
|
250
267
|
- test/data/font.ttf
|
268
|
+
- test/data/image_normal.jpg
|
269
|
+
- test/data/image_normal.png
|
270
|
+
- test/data/image_normal_jpg_noext
|
271
|
+
- test/data/image_normal_png_noext
|
272
|
+
- test/data/image_pallete_based.png
|
251
273
|
- test/data/layout_block.tlf
|
252
274
|
- test/data/layout_list.tlf
|
253
275
|
- test/data/layout_list_noheader.tlf
|
@@ -301,6 +323,7 @@ files:
|
|
301
323
|
- test/unit/core/test_shape.rb
|
302
324
|
- test/unit/core/test_utils.rb
|
303
325
|
- test/unit/generator/pdf/document/graphics/test_attributes.rb
|
326
|
+
- test/unit/generator/pdf/document/graphics/test_image.rb
|
304
327
|
- test/unit/generator/pdf/document/graphics/test_text.rb
|
305
328
|
- test/unit/generator/pdf/document/test_draw_shape.rb
|
306
329
|
- test/unit/generator/pdf/document/test_font.rb
|
@@ -345,12 +368,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
345
368
|
version: '0'
|
346
369
|
requirements: []
|
347
370
|
rubyforge_project:
|
348
|
-
rubygems_version: 2.4.
|
371
|
+
rubygems_version: 2.4.5
|
349
372
|
signing_key:
|
350
373
|
specification_version: 4
|
351
374
|
summary: An open source report generation tool for Ruby.
|
352
375
|
test_files:
|
353
376
|
- test/data/font.ttf
|
377
|
+
- test/data/image_normal.jpg
|
378
|
+
- test/data/image_normal.png
|
379
|
+
- test/data/image_normal_jpg_noext
|
380
|
+
- test/data/image_normal_png_noext
|
381
|
+
- test/data/image_pallete_based.png
|
354
382
|
- test/data/layout_block.tlf
|
355
383
|
- test/data/layout_list.tlf
|
356
384
|
- test/data/layout_list_noheader.tlf
|
@@ -404,6 +432,7 @@ test_files:
|
|
404
432
|
- test/unit/core/test_shape.rb
|
405
433
|
- test/unit/core/test_utils.rb
|
406
434
|
- test/unit/generator/pdf/document/graphics/test_attributes.rb
|
435
|
+
- test/unit/generator/pdf/document/graphics/test_image.rb
|
407
436
|
- test/unit/generator/pdf/document/graphics/test_text.rb
|
408
437
|
- test/unit/generator/pdf/document/test_draw_shape.rb
|
409
438
|
- test/unit/generator/pdf/document/test_font.rb
|