thinreports 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|