cartocss_helper 1.2.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/cartocss_helper.rb +56 -71
- data/lib/cartocss_helper/configuration.rb +84 -37
- data/lib/cartocss_helper/data_file_handling.rb +32 -35
- data/lib/cartocss_helper/git.rb +17 -27
- data/lib/cartocss_helper/heuristic.rb +39 -41
- data/lib/cartocss_helper/image_generator.rb +36 -38
- data/lib/cartocss_helper/notes_downloader.rb +46 -0
- data/lib/cartocss_helper/overpass_downloader.rb +42 -0
- data/lib/cartocss_helper/overpass_query_generator.rb +248 -0
- data/lib/cartocss_helper/renderer_handler.rb +116 -0
- data/lib/cartocss_helper/style_specific/default_osm_style.rb +722 -546
- data/lib/cartocss_helper/style_specific/style_specific.rb +4 -3
- data/lib/cartocss_helper/tag_lister.rb +136 -112
- data/lib/cartocss_helper/util/filehelper.rb +1 -1
- data/lib/cartocss_helper/util/generic_cached_downloader.rb +49 -0
- data/lib/cartocss_helper/util/generic_downloader.rb +65 -0
- data/lib/cartocss_helper/util/logger.rb +30 -0
- data/lib/cartocss_helper/util/rest-client_wrapper.rb +53 -0
- data/lib/cartocss_helper/util/systemhelper.rb +55 -0
- data/lib/cartocss_helper/validator.rb +142 -81
- data/lib/cartocss_helper/visualise_changes_diff_from_images.rb +36 -34
- data/lib/cartocss_helper/visualise_changes_image_generation.rb +72 -100
- data/lib/data/testing_locations.rb +17 -15
- data/readme.md +34 -9
- metadata +140 -39
- data/lib/cartocss_helper/downloader.rb +0 -301
- data/lib/cartocss_helper/tilemill_handler.rb +0 -38
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Log
|
4
|
+
@@_logger_ = Logger.new(STDOUT)
|
5
|
+
|
6
|
+
def self.logger
|
7
|
+
@@_logger_
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.info(message = '')
|
11
|
+
logger.info(message)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.warn(message = '')
|
15
|
+
logger.warn(message)
|
16
|
+
end
|
17
|
+
|
18
|
+
@@_logger_.formatter = proc do |_severity, _datetime, _progname, msg|
|
19
|
+
fileLine = ''
|
20
|
+
caller.each do |clr|
|
21
|
+
unless /\/logger.rb:/ =~ clr
|
22
|
+
fileLine = clr
|
23
|
+
break
|
24
|
+
end
|
25
|
+
end
|
26
|
+
fileLine = fileLine.split(':in `', 2)[0]
|
27
|
+
fileLine.sub!(/:(\d)/, '(\1')
|
28
|
+
"#{fileLine}) : #{msg}\n"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require_relative 'generic_downloader.rb'
|
3
|
+
|
4
|
+
class RestClientWrapper
|
5
|
+
def initialize
|
6
|
+
@last_url_fetched = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def fetch_data_from_url(url, request_timeout)
|
10
|
+
wait if url == @last_url_fetched
|
11
|
+
@last_url_fetched = url
|
12
|
+
return execute_fetch_data_from_url(url, request_timeout)
|
13
|
+
# http://www.rubydoc.info/gems/rest-client/1.8.0/RestClient/Exception
|
14
|
+
rescue RestClient::RequestTimeout => e
|
15
|
+
raise RequestTimeout, e.to_s
|
16
|
+
rescue RestClient::ExceptionWithResponse => e
|
17
|
+
raise_exception_about_returned_response(e)
|
18
|
+
rescue RestClient::MaxRedirectsReached, RestClient::SSLCertificateNotVerified, RestClient::ServerBrokeConnection, SocketError, URI::InvalidURIError
|
19
|
+
raise ExceptionWithoutResponse.new(e), e.to_s
|
20
|
+
rescue ArgumentError => e
|
21
|
+
raise_issue_359_exception(e)
|
22
|
+
rescue => e
|
23
|
+
puts 'unhandled exception! It is a clear bug!'
|
24
|
+
puts "<#{e.class} error happened>"
|
25
|
+
raise e, e.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute_fetch_data_from_url(url, request_timeout)
|
29
|
+
data = RestClient::Request.execute(method: :get, url: url, timeout: request_timeout)
|
30
|
+
# see https://github.com/rest-client/rest-client/issues/370, will be fixed in 2.0
|
31
|
+
# published versions listed on https://rubygems.org/gems/rest-client/versions/
|
32
|
+
return String.new(data)
|
33
|
+
end
|
34
|
+
|
35
|
+
def raise_issue_359_exception(e)
|
36
|
+
raise BuggyRestClient, "ArgumentError from rest-client, most likely caused by https://github.com/rest-client/rest-client/issues/359 (requesting GBs of data) [#{e}]"
|
37
|
+
end
|
38
|
+
|
39
|
+
def raise_exception_about_returned_response(e)
|
40
|
+
failure = ExceptionWithResponse.new(e)
|
41
|
+
failure.http_code = e.http_code
|
42
|
+
failure.response = e.response
|
43
|
+
raise failure, e.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def wait
|
47
|
+
progressbar = ProgressBar.create
|
48
|
+
100.times do
|
49
|
+
sleep 4
|
50
|
+
progressbar.increment
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class FailedCommandException < StandardError
|
2
|
+
end
|
3
|
+
|
4
|
+
module SystemHelper
|
5
|
+
def check_error_code(command, stderr, status, allowed_return_codes)
|
6
|
+
returned = status.exitstatus
|
7
|
+
return if status.success?
|
8
|
+
return if allowed_return_codes.include?(returned)
|
9
|
+
explanation = "failed command #{command} due to error code #{returned}. stderr was #{stderr}"
|
10
|
+
raise FailedCommandException.new(explanation)
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_stderr(command, stderr, status, ignore_stderr_presence)
|
14
|
+
return if ignore_stderr_presence
|
15
|
+
return if stderr == ''
|
16
|
+
returned = status.exitstatus
|
17
|
+
explanation = "failed command #{command} due to < #{stderr}> on stderr. return code was #{returned}"
|
18
|
+
raise FailedCommandException.new(explanation)
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute_command(command, debug = false, allowed_return_codes: [], ignore_stderr_presence: false)
|
22
|
+
puts command if debug
|
23
|
+
stdout, stderr, status = Open3.capture3(command)
|
24
|
+
|
25
|
+
check_error_code(command, stderr, status, allowed_return_codes)
|
26
|
+
check_stderr(command, stderr, status, ignore_stderr_presence)
|
27
|
+
|
28
|
+
return stderr + stdout
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.not_enough_free_space
|
32
|
+
minimum_gb = 2
|
33
|
+
available_gb = get_available_space_for_cache_in_gb
|
34
|
+
if available_gb < minimum_gb
|
35
|
+
puts "get_available_space_for_cache_in_gb: #{available_gb}, minimum_gb: #{minimum_gb}"
|
36
|
+
return true
|
37
|
+
else
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_available_space_for_cache_in_gb
|
43
|
+
stat = Sys::Filesystem.stat(CartoCSSHelper::Configuration.get_path_to_folder_for_cache)
|
44
|
+
return stat.block_size * stat.blocks_available / 1024 / 1024 / 1024
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete_file(filename, reason)
|
48
|
+
open(CartoCSSHelper::Configuration.get_path_to_folder_for_output + 'deleting_files_log.txt', 'a') do |file|
|
49
|
+
message = "deleting #{filename}, #{File.size(filename) / 1024 / 1024}MB - #{reason}"
|
50
|
+
puts message
|
51
|
+
file.puts(message)
|
52
|
+
File.delete(filename)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -10,15 +10,32 @@ include CartoCSSHelper::Configuration
|
|
10
10
|
module CartoCSSHelper
|
11
11
|
module Validator
|
12
12
|
def run_tests(git_branch)
|
13
|
-
run_expected_rendering_test(git_branch)
|
14
13
|
run_dy_test(git_branch)
|
14
|
+
run_missing_name_test(git_branch)
|
15
|
+
run_expected_rendering_test(git_branch, true)
|
15
16
|
run_closed_way_test(git_branch)
|
17
|
+
run_expected_rendering_test(git_branch)
|
18
|
+
run_unwanted_name_test(git_branch)
|
16
19
|
end
|
17
20
|
|
18
|
-
def run_expected_rendering_test(git_branch)
|
21
|
+
def run_expected_rendering_test(git_branch, quick_and_more_prone_to_errors = false)
|
19
22
|
Git.checkout git_branch
|
20
23
|
puts 'unexpectedly rendered/unrendered keys:'
|
21
|
-
compare_expected_with_real_rendering
|
24
|
+
compare_expected_with_real_rendering(quick_and_more_prone_to_errors)
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_missing_name_test(git_branch)
|
29
|
+
Git.checkout git_branch
|
30
|
+
puts 'Check whatever names are displayed:'
|
31
|
+
run_global_check(:check_missing_names)
|
32
|
+
puts
|
33
|
+
end
|
34
|
+
|
35
|
+
def run_unwanted_name_test(git_branch)
|
36
|
+
Git.checkout git_branch
|
37
|
+
puts 'Check whatever names are displayed:'
|
38
|
+
run_global_check(:check_unwanted_names)
|
22
39
|
puts
|
23
40
|
end
|
24
41
|
|
@@ -36,137 +53,181 @@ module CartoCSSHelper
|
|
36
53
|
puts
|
37
54
|
end
|
38
55
|
|
39
|
-
def compare_expected_with_real_rendering
|
56
|
+
def compare_expected_with_real_rendering(quick_and_more_prone_to_errors = false)
|
40
57
|
list_of_documented = CartoCSSHelper::Configuration.get_style_specific_data.list_of_documented_tags
|
41
58
|
info = Info.new
|
42
|
-
list_of_rendered = info.get_render_state_of_tags
|
59
|
+
list_of_rendered = info.get_render_state_of_tags(quick_and_more_prone_to_errors)
|
43
60
|
|
61
|
+
puts 'ensure_that_tags_documented_and_rendered_have_the_same_state'
|
44
62
|
ensure_that_tags_documented_and_rendered_have_the_same_state(list_of_documented, list_of_rendered)
|
63
|
+
|
64
|
+
puts 'ensure_that_all_rendered_tags_are_documented'
|
45
65
|
ensure_that_all_rendered_tags_are_documented(list_of_documented, list_of_rendered)
|
66
|
+
|
67
|
+
puts 'ensure_that_all_documented_are_really_rendered'
|
46
68
|
ensure_that_all_documented_are_really_rendered(list_of_documented, list_of_rendered)
|
47
69
|
end
|
48
70
|
|
49
71
|
def ensure_that_tags_documented_and_rendered_have_the_same_state(list_of_documented, list_of_rendered)
|
50
|
-
list_of_rendered.each
|
72
|
+
list_of_rendered.each do |tag_info|
|
51
73
|
compare_expected_with_tag_data list_of_documented, tag_info
|
52
|
-
|
74
|
+
end
|
53
75
|
end
|
54
76
|
|
55
77
|
def ensure_that_all_rendered_tags_are_documented(list_of_documented, list_of_rendered)
|
56
|
-
list_of_rendered.each
|
57
|
-
if tag_info.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
end
|
67
|
-
}
|
78
|
+
list_of_rendered.each do |tag_info|
|
79
|
+
next if is_tag_documented(list_of_documented, tag_info.key, tag_info.value)
|
80
|
+
puts 'documented'
|
81
|
+
puts "\tmissing"
|
82
|
+
puts 'real'
|
83
|
+
print "\t"
|
84
|
+
tag_info.print
|
85
|
+
puts
|
86
|
+
end
|
68
87
|
end
|
69
88
|
|
70
89
|
def ensure_that_all_documented_are_really_rendered(list_of_documented, list_of_rendered)
|
71
|
-
list_of_documented.each
|
72
|
-
if
|
73
|
-
|
74
|
-
print "\t"
|
75
|
-
documented.print
|
76
|
-
puts 'real'
|
77
|
-
puts "\tmissing"
|
78
|
-
puts
|
90
|
+
list_of_documented.each do |documented|
|
91
|
+
if Info.get_expected_state(documented.key, documented.value) == :ignored
|
92
|
+
next
|
79
93
|
end
|
80
|
-
|
94
|
+
next if is_tag_documented(list_of_rendered, documented.key, documented.value)
|
95
|
+
puts 'documented'
|
96
|
+
print "\t"
|
97
|
+
documented.print
|
98
|
+
puts 'real'
|
99
|
+
puts "\tmissing"
|
100
|
+
puts
|
101
|
+
end
|
81
102
|
end
|
82
103
|
|
83
104
|
def is_tag_documented(list, key, value)
|
84
|
-
list.each
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
}
|
105
|
+
list.each do |tag_info|
|
106
|
+
next unless key == tag_info.key
|
107
|
+
return true if value == tag_info.value
|
108
|
+
end
|
91
109
|
return false
|
92
110
|
end
|
93
111
|
|
94
112
|
def compare_expected_with_tag_data(list_of_expected, tag_info)
|
95
|
-
list_of_expected.each
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
107
|
-
return
|
108
|
-
end
|
113
|
+
list_of_expected.each do |expected|
|
114
|
+
next unless expected.key == tag_info.key
|
115
|
+
next unless expected.value == tag_info.value
|
116
|
+
if expected.equal? tag_info
|
117
|
+
puts 'expected'
|
118
|
+
print "\t"
|
119
|
+
expected.print
|
120
|
+
puts 'real'
|
121
|
+
print "\t"
|
122
|
+
tag_info.print
|
123
|
+
puts
|
109
124
|
end
|
110
|
-
|
125
|
+
return
|
126
|
+
end
|
111
127
|
end
|
112
128
|
|
113
129
|
def run_global_check(function)
|
114
|
-
Heuristic.get_tags.each
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
130
|
+
Heuristic.get_tags.each do |element|
|
131
|
+
key = element[0]
|
132
|
+
value = element[1]
|
133
|
+
state = Info.get_expected_state(key, value)
|
134
|
+
tags = { key => value }
|
135
|
+
next if state == :ignore
|
136
|
+
if state == :composite
|
137
|
+
tags.merge!(Info.get_expected_composite(key, value))
|
138
|
+
end
|
139
|
+
(Configuration.get_max_z..Configuration.get_max_z).each do |zlevel| # get_min_z should be used - but as renderer is extremely slow this hack was used TODO
|
140
|
+
send(function, tags, zlevel)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def check_problems_with_closed_line(tags, zlevel, on_water = false)
|
146
|
+
way = Scene.new(tags, zlevel, on_water, 'way', true)
|
147
|
+
closed_way = Scene.new(tags, zlevel, on_water, 'closed_way', true)
|
148
|
+
empty = Scene.new({}, zlevel, on_water, 'node', true)
|
126
149
|
if way.is_output_different(empty)
|
127
|
-
|
128
|
-
|
150
|
+
puts tags unless closed_way.is_output_different(empty)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def check_missing_names(tags, zlevel, interactive = false, on_water = false)
|
155
|
+
not_required = CartoCSSHelper::Configuration.get_style_specific_data.name_label_is_not_required
|
156
|
+
return if not_required.include?(tags)
|
157
|
+
['node', 'closed_way', 'way'].each do |type|
|
158
|
+
next if not_required.include?(tags.merge({ type: type }))
|
159
|
+
unless is_object_displaying_anything_as_this_object_type tags, zlevel, on_water, type
|
160
|
+
# puts key+"="+value+" - not displayed as node on z#{zlevel}"
|
161
|
+
next
|
162
|
+
end
|
163
|
+
tags.delete('name') if tags['name'] != nil
|
164
|
+
unless is_object_displaying_name_as_this_object_type tags, 'a', zlevel, on_water, type
|
165
|
+
puts "#{tags} - label is missing on z#{zlevel} #{type}"
|
166
|
+
next
|
129
167
|
end
|
130
168
|
end
|
131
169
|
end
|
132
170
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
171
|
+
def check_unwanted_names(tags, zlevel, interactive = false, on_water = false)
|
172
|
+
['node', 'closed_way', 'way'].each do |type|
|
173
|
+
not_required = CartoCSSHelper::Configuration.get_style_specific_data.name_label_is_not_required
|
174
|
+
next unless not_required.include?(tags) || not_required.include?(tags.merge({ type: type }))
|
175
|
+
unless is_object_displaying_anything_as_this_object_type tags, zlevel, on_water, type
|
176
|
+
# puts key+"="+value+" - not displayed as node on z#{zlevel}"
|
177
|
+
next
|
178
|
+
end
|
179
|
+
tags.delete('name') if tags['name'] != nil
|
180
|
+
if is_object_displaying_name_as_this_object_type tags, 'a', zlevel, on_water, type
|
181
|
+
puts "#{tags} - label is unxpectedly displayed on z#{zlevel} #{type}"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def check_dy(tags, zlevel, interactive = false, on_water = false)
|
187
|
+
unless is_object_displaying_anything_as_node tags, zlevel, on_water
|
188
|
+
# puts key+"="+value+" - not displayed as node on z#{zlevel}"
|
136
189
|
return
|
137
190
|
end
|
138
|
-
|
139
|
-
#puts key+"="+value+" - label is missing on z#{zlevel} nodes"
|
191
|
+
unless is_object_displaying_name_as_node tags, 'a', zlevel, on_water
|
192
|
+
# puts key+"="+value+" - label is missing on z#{zlevel} nodes"
|
140
193
|
return
|
141
194
|
end
|
142
195
|
test_name = 'ÉÉÉÉÉÉ ÉÉÉÉÉÉ ÉÉÉÉÉÉ'
|
143
|
-
|
144
|
-
puts
|
196
|
+
until is_object_displaying_name_as_node tags, test_name, zlevel, on_water
|
197
|
+
puts "#{tags} - name is missing for name '#{test_name}' on z#{zlevel}"
|
145
198
|
if interactive
|
146
199
|
puts 'press enter'
|
147
200
|
gets
|
148
201
|
else
|
149
202
|
return
|
150
203
|
end
|
151
|
-
with_name = Scene.new({key => value, 'name' => test_name}, zlevel, on_water, 'node')
|
204
|
+
with_name = Scene.new({ key => value, 'name' => test_name }, zlevel, on_water, 'node', true)
|
152
205
|
with_name.flush_cache
|
153
206
|
puts 'calculating'
|
154
207
|
end
|
155
|
-
#puts key+"="+value+" - name is OK for name '#{name}'"
|
208
|
+
# puts key+"="+value+" - name is OK for name '#{name}'"
|
156
209
|
end
|
157
210
|
|
158
|
-
def
|
159
|
-
name_tags = {
|
160
|
-
with_name = Scene.new(name_tags, zlevel, on_water,
|
161
|
-
nameless_tags =
|
162
|
-
nameless = Scene.new(nameless_tags, zlevel, on_water,
|
211
|
+
def is_object_displaying_name_as_this_object_type(tags, name, zlevel, on_water, type)
|
212
|
+
name_tags = tags.merge({ 'name' => name })
|
213
|
+
with_name = Scene.new(name_tags, zlevel, on_water, type, true)
|
214
|
+
nameless_tags = tags
|
215
|
+
nameless = Scene.new(nameless_tags, zlevel, on_water, type, true)
|
163
216
|
return with_name.is_output_different(nameless)
|
164
217
|
end
|
165
218
|
|
166
|
-
def
|
167
|
-
|
168
|
-
|
219
|
+
def is_object_displaying_name_as_node(tags, name, zlevel, on_water)
|
220
|
+
is_object_displaying_name_as_this_object_type(tags, name, zlevel, on_water, 'node')
|
221
|
+
end
|
222
|
+
|
223
|
+
def is_object_displaying_anything_as_this_object_type(tags, zlevel, on_water, type)
|
224
|
+
object = Scene.new(tags, zlevel, on_water, type, true)
|
225
|
+
empty = Scene.new({}, zlevel, on_water, type, true)
|
169
226
|
return object.is_output_different(empty)
|
170
227
|
end
|
228
|
+
|
229
|
+
def is_object_displaying_anything_as_node(tags, zlevel, on_water)
|
230
|
+
return is_object_displaying_anything_as_this_object_type(tags, zlevel, on_water, 'node')
|
231
|
+
end
|
171
232
|
end
|
172
233
|
end
|
@@ -7,9 +7,10 @@ module CartoCSSHelper
|
|
7
7
|
@file_location = file_location
|
8
8
|
@description = description
|
9
9
|
end
|
10
|
+
|
10
11
|
def identical(another_image)
|
11
|
-
#Returns true if the contents of a file A and a file B are identical.
|
12
|
-
return FileUtils.compare_file(
|
12
|
+
# Returns true if the contents of a file A and a file B are identical.
|
13
|
+
return FileUtils.compare_file(file_location, another_image.file_location)
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
@@ -22,6 +23,7 @@ module CartoCSSHelper
|
|
22
23
|
@right_file_location = right_image.file_location
|
23
24
|
@description = left_image.description
|
24
25
|
end
|
26
|
+
|
25
27
|
def merge_description_from_next_image(image)
|
26
28
|
@description << ', ' << image.description
|
27
29
|
end
|
@@ -36,7 +38,7 @@ module CartoCSSHelper
|
|
36
38
|
@image_size = image_size
|
37
39
|
@margin = 10
|
38
40
|
@standard_pointsize = 10
|
39
|
-
@header_space = @standard_pointsize*1.5
|
41
|
+
@header_space = @standard_pointsize * 1.5
|
40
42
|
@diff_note_space = @standard_pointsize
|
41
43
|
|
42
44
|
render
|
@@ -44,13 +46,13 @@ module CartoCSSHelper
|
|
44
46
|
|
45
47
|
def compress(before, after)
|
46
48
|
returned = [PairOfComparedImages.new(before[0], after[0])]
|
47
|
-
(1...before.length).each
|
48
|
-
if before[i].identical(before[i-1]) && after[i].identical(after[i-1])
|
49
|
+
(1...before.length).each do |i|
|
50
|
+
if before[i].identical(before[i - 1]) && after[i].identical(after[i - 1])
|
49
51
|
returned[-1].merge_description_from_next_image(before[i])
|
50
52
|
else
|
51
53
|
returned.push(PairOfComparedImages.new(before[i], after[i]))
|
52
54
|
end
|
53
|
-
|
55
|
+
end
|
54
56
|
return returned
|
55
57
|
end
|
56
58
|
|
@@ -58,17 +60,16 @@ module CartoCSSHelper
|
|
58
60
|
create_canvas
|
59
61
|
offset = 0
|
60
62
|
render_header
|
61
|
-
offset += @header_space + @margin*1.5
|
62
|
-
|
63
|
-
offset += @diff_note_space + @margin*0.5
|
63
|
+
offset += @header_space + @margin * 1.5
|
64
|
+
offset += @diff_note_space + @margin * 0.5
|
64
65
|
render_images_with_labels offset
|
65
|
-
offset +=
|
66
|
+
offset += @compared.length * (@margin + @image_size)
|
66
67
|
render_footer offset
|
67
68
|
end
|
68
69
|
|
69
70
|
def create_canvas
|
70
71
|
y = get_needed_y
|
71
|
-
x = @image_size*2+3
|
72
|
+
x = @image_size * 2 + 3 * @margin
|
72
73
|
|
73
74
|
@canvas = Magick::Image.new(x, y)
|
74
75
|
end
|
@@ -76,48 +77,49 @@ module CartoCSSHelper
|
|
76
77
|
def get_needed_y
|
77
78
|
y = 0
|
78
79
|
y += @header_space
|
79
|
-
y += @margin*1.5
|
80
|
+
y += @margin * 1.5
|
80
81
|
y += @diff_note_space
|
81
|
-
y += @margin*0.5
|
82
|
-
y +=
|
82
|
+
y += @margin * 0.5
|
83
|
+
y += @compared.length * (@image_size + @margin)
|
83
84
|
y += @diff_note_space
|
84
85
|
return y
|
85
86
|
end
|
86
87
|
|
87
88
|
def render_header
|
88
89
|
header_drawer = Magick::Draw.new
|
89
|
-
header_drawer.pointsize(@header_space*3/5)
|
90
|
+
header_drawer.pointsize(@header_space * 3 / 5)
|
90
91
|
header_drawer.text(@margin, @header_space, @header)
|
91
92
|
header_drawer.draw(@canvas)
|
92
93
|
end
|
93
94
|
|
94
|
-
def render_diff_note(y_offset)
|
95
|
-
drawer = Magick::Draw.new
|
96
|
-
drawer.pointsize(@diff_note_space)
|
97
|
-
#drawer.text(@margin, y_offset, 'before')
|
98
|
-
drawer.draw(@canvas)
|
99
|
-
#drawer.text(@margin*2 + @image_size, y_offset, 'after')
|
100
|
-
drawer.draw(@canvas)
|
101
|
-
end
|
102
|
-
|
103
95
|
def render_images_with_labels(y_offset)
|
104
|
-
(0...@compared.length).each
|
96
|
+
(0...@compared.length).each do |i|
|
105
97
|
render_row_of_labelled_images(@compared[i], y_offset + i * (@margin + @image_size))
|
106
|
-
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def read_image_from_disk(filename)
|
102
|
+
return Magick::Image.read(filename)[0]
|
103
|
+
rescue Magick::ImageMagickError => e
|
104
|
+
# for example on loading corrupted empty file (for example CartoCSSHelper was interuppted during writing to disk...)
|
105
|
+
puts "reading image <#{filename}> from disk failed"
|
106
|
+
puts e.class
|
107
|
+
puts e
|
108
|
+
raise e
|
107
109
|
end
|
108
110
|
|
109
111
|
def render_row_of_labelled_images(processed, y_offset)
|
110
|
-
left_image =
|
111
|
-
right_image =
|
112
|
+
left_image = read_image_from_disk(processed.left_file_location)
|
113
|
+
right_image = read_image_from_disk(processed.right_file_location)
|
112
114
|
drawer = Magick::Draw.new
|
113
|
-
drawer.pointsize(@diff_note_space*4/5)
|
115
|
+
drawer.pointsize(@diff_note_space * 4 / 5)
|
114
116
|
if left_image == right_image
|
115
|
-
drawer.text(@margin + @image_size/2, y_offset, "#{processed.description} - unchanged")
|
117
|
+
drawer.text(@margin + @image_size / 2, y_offset, "#{processed.description} - unchanged")
|
116
118
|
drawer.draw(@canvas)
|
117
119
|
else
|
118
120
|
drawer.text(@margin, y_offset, "#{processed.description} - before")
|
119
121
|
drawer.draw(@canvas)
|
120
|
-
drawer.text(@margin*2 + @image_size, y_offset, "#{processed.description} - after")
|
122
|
+
drawer.text(@margin * 2 + @image_size, y_offset, "#{processed.description} - after")
|
121
123
|
drawer.draw(@canvas)
|
122
124
|
end
|
123
125
|
render_row_of_images(y_offset, left_image, right_image)
|
@@ -133,17 +135,17 @@ module CartoCSSHelper
|
|
133
135
|
# noinspection RubyResolve
|
134
136
|
def render_row_of_images(y_offset, left_image, right_image)
|
135
137
|
if left_image == right_image
|
136
|
-
@canvas.composite!(left_image, @margin*1.5 + @image_size/2, y_offset, Magick::OverCompositeOp)
|
138
|
+
@canvas.composite!(left_image, @margin * 1.5 + @image_size / 2, y_offset, Magick::OverCompositeOp)
|
137
139
|
else
|
138
140
|
@canvas.composite!(left_image, @margin, y_offset, Magick::OverCompositeOp)
|
139
|
-
@canvas.composite!(right_image, @margin*2
|
141
|
+
@canvas.composite!(right_image, @margin * 2 + @image_size, y_offset, Magick::OverCompositeOp)
|
140
142
|
end
|
141
143
|
end
|
142
144
|
|
143
145
|
def render_footer(y_offset)
|
144
146
|
label_drawer = Magick::Draw.new
|
145
147
|
label_drawer.pointsize(@standard_pointsize)
|
146
|
-
label_drawer.text(@margin, y_offset, 'generated using https://github.com/
|
148
|
+
label_drawer.text(@margin, y_offset, 'generated using https://github.com/matkoniecz/CartoCSSHelper')
|
147
149
|
label_drawer.draw(@canvas)
|
148
150
|
end
|
149
151
|
|