gpx2exif 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +1,14 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- builder (3.0.0)
4
+ builder (3.1.3)
5
5
  diff-lcs (1.1.3)
6
6
  git (1.2.5)
7
7
  jeweler (1.6.4)
8
8
  bundler (~> 1.0)
9
9
  git (>= 1.2.5)
10
10
  rake
11
- mini_exiftool (1.5.1)
11
+ mini_exiftool (1.6.0)
12
12
  multi_json (1.3.6)
13
13
  nokogiri (1.5.5)
14
14
  rake (0.9.2.2)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.3
@@ -0,0 +1,25 @@
1
+ require 'base64'
2
+
3
+ $:.unshift(File.dirname(__FILE__))
4
+
5
+ # Sample marker useful for everybody :)
6
+ module Gpx2png
7
+ class SampleMarker
8
+
9
+ STRING = "iVBORw0KGgoAAAANSUhEUgAAACAAAAA8CAYAAAAHbrgUAAAACXBIWXMAAAsT
10
+ AAALEwEAmpwYAAAAB3RJTUUH3AoHCwYNWvFiNgAAAYxJREFUWMPtls9KAzEQ
11
+ xr9d//QkgmjxKPQBVDwJYvEPXoQWfQ7Bm48hKL6AIhT6DIp3QaGC4KEnT0q1
12
+ FxE8db2ksIRJNtlM1oPzg1A2O5v5Js23O4A/mwCuAPQB/KjRV3NNRKQOoAcg
13
+ AzBSv/kxnnsCsMidfNmS2CRklSv5gkdyXUSdQ8Ajkdz2F+Sve6HJ1w2JPgC0
14
+ AUyo0QIwMAjbCBFwqS06AvBpiR8Q8dchAl6Jig4t8W0i/i1EAHXAapb4KcMz
15
+ RlIHAToJp7+LBDwTc/uWeOreS4jAM8IBQ4PwRLlDd8JFiIAtgw2H6jBOq3Gg
16
+ 3EHZcNeWIHE8iNRc4jBXmCN1ENAhRLgkygB0OQ5q0+MboI9tLrd8lUj+zWHD
17
+ vBt8Oed8X8yV2IF57qbk1qMhuYvRku14VL8Xqy98L9iFca8QjSOH6o99Fizz
18
+ Zcs410xLCDhltqs3M5btn0VFdIjer4sKWSKqb6BiblTl0V48Razkql/DH3EP
19
+ 4CFkgclAAScMawiCIAiCIAiCIAj/nF9mGvLkWeHRewAAAABJRU5ErkJggg=="
20
+
21
+ BLOB = Base64.decode64(STRING)
22
+
23
+ URL = "http://www.iconspedia.com/icon/map-marker-icon-19842.html"
24
+ end
25
+ end
@@ -13,6 +13,7 @@ module Gpx2png
13
13
  super
14
14
  @renderer ||= DEFAULT_RENDERER
15
15
  @r = nil
16
+ @markers = Array.new
16
17
  end
17
18
 
18
19
  def save(filename)
@@ -25,6 +26,10 @@ module Gpx2png
25
26
  @r.to_png
26
27
  end
27
28
 
29
+ def add_marker(p)
30
+ @markers << p
31
+ end
32
+
28
33
  def render
29
34
  setup_renderer
30
35
  initial_calculations
@@ -242,7 +242,20 @@ module Gpx2png
242
242
  )
243
243
  end
244
244
 
245
- #calculate_for_crop
245
+ # add points
246
+ @markers.each do |point|
247
+ lat = point[:lat]
248
+ lon = point[:lon]
249
+
250
+ p = self.class.point_on_image(@zoom, [lat, lon])
251
+ bitmap_x = (p[:osm_title_coord][0] - @tile_x_range.min) * TILE_WIDTH + p[:pixel_offset][0]
252
+ bitmap_y = (p[:osm_title_coord][1] - @tile_y_range.min) * TILE_HEIGHT + p[:pixel_offset][1]
253
+
254
+ point[:x] = bitmap_x
255
+ point[:y] = bitmap_y
256
+
257
+ @r.markers << point
258
+ end
246
259
  end
247
260
 
248
261
  # Calculate some numbers for cropping operation
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'RMagick'
3
+ require 'gpx2png/assets/sample_marker'
3
4
 
4
5
  $:.unshift(File.dirname(__FILE__))
5
6
 
@@ -20,16 +21,33 @@ module Gpx2png
20
21
  @line.stroke_opacity(@opacity)
21
22
  @line.stroke_width(@width)
22
23
 
24
+ @marker_label = Magick::Draw.new
25
+ @marker_label.text_antialias(@aa)
26
+ @marker_label.font_family('helvetica')
27
+ @marker_label.font_style(Magick::NormalStyle)
28
+ @marker_label.text_align(Magick::LeftAlign)
29
+ @marker_label.pointsize(12)
30
+
31
+ @marker_frame = Magick::Draw.new
32
+ @marker_frame.stroke_antialias(@aa)
33
+ @marker_frame.stroke('black')
34
+ @marker_frame.stroke_opacity(0.3)
35
+ @marker_frame.fill('white')
36
+ @marker_frame.fill_opacity(0.3)
37
+
23
38
  @licence_text = Magick::Draw.new
24
39
  @licence_text.text_antialias(@aa)
25
40
  @licence_text.font_family('helvetica')
26
41
  @licence_text.font_style(Magick::NormalStyle)
27
42
  @licence_text.text_align(Magick::RightAlign)
28
43
  @licence_text.pointsize(12)
44
+
45
+ @markers = Array.new
29
46
  end
30
47
 
31
48
  attr_accessor :x, :y
32
49
  attr_accessor :licence_string
50
+ attr_accessor :markers
33
51
 
34
52
  # Create new (full) image
35
53
  def new_image
@@ -97,13 +115,71 @@ module Gpx2png
97
115
  @y = @new_y
98
116
  end
99
117
 
118
+ # Render only marker images, and perform some calculations
119
+ def render_markers
120
+ @markers.each do |p|
121
+ # using custom marker
122
+ _blob = p[:blob]
123
+ # or default
124
+ _blob = SampleMarker::BLOB if _blob.nil?
125
+
126
+ img_tile = Magick::Image.from_blob(_blob)[0]
127
+ p[:x_after_crop] = p[:x] - @crop_l.to_i
128
+ p[:y_after_crop] = p[:y] - @crop_t.to_i
129
+ p[:x_center] = p[:x_after_crop] - img_tile.columns / 2
130
+ p[:y_center] = p[:y_after_crop] - img_tile.rows / 2
131
+ p[:x_next_to_image] = p[:x_after_crop] + img_tile.columns
132
+
133
+ @image = @image.composite(
134
+ img_tile,
135
+ p[:x_center],
136
+ p[:y_center],
137
+ Magick::OverCompositeOp
138
+ )
139
+ end
140
+ end
141
+
142
+ # Render nice looking labels
143
+ def render_marker_labels
144
+ #http://www.simplesystems.org/RMagick/doc/draw.html#get_type_metrics
145
+ #http://rmagick.rubyforge.org/web2/web2-3.html
146
+
147
+ @markers.each do |p|
148
+ p[:x_label] = p[:x_after_crop] + 10
149
+ p[:y_label] = p[:y_after_crop] - 15
150
+
151
+ tm = @marker_label.get_type_metrics(@image, p[:label])
152
+ p[:text_width] = tm.width
153
+ p[:text_height] = tm.height
154
+ p[:text_padding] = 3
155
+
156
+ @marker_frame.rectangle(
157
+ p[:x_label],
158
+ p[:y_label],
159
+ p[:x_label] + p[:text_width] + p[:text_padding] * 2,
160
+ p[:y_label] + p[:text_height] + p[:text_padding] * 2
161
+ )
162
+ # text
163
+ @marker_label.text(p[:x_label] + p[:text_padding], p[:y_label] + p[:text_padding] + 12, p[:label].to_s + " ")
164
+ end
165
+
166
+ @marker_frame.draw(@image)
167
+ @marker_label.draw(@image)
168
+ end
169
+
100
170
  def render
101
171
  @line.draw(@image)
172
+
102
173
  # crop after drawing lines, before drawing "legend"
103
174
  crop!
175
+
104
176
  # "static" elements
105
177
  @licence_text.text(@x - 10, @y - 10, @licence_string)
106
178
  @licence_text.draw(@image)
179
+
180
+ # draw point images
181
+ render_markers
182
+ render_marker_labels
107
183
  end
108
184
 
109
185
  def save(filename)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gpx2exif
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-06 00:00:00.000000000Z
12
+ date: 2012-10-07 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
16
- requirement: &19750200 !ruby/object:Gem::Requirement
16
+ requirement: &16633900 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *19750200
24
+ version_requirements: *16633900
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: mini_exiftool
27
- requirement: &19749640 !ruby/object:Gem::Requirement
27
+ requirement: &16633240 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *19749640
35
+ version_requirements: *16633240
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: builder
38
- requirement: &19749100 !ruby/object:Gem::Requirement
38
+ requirement: &16632640 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *19749100
46
+ version_requirements: *16632640
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &19748580 !ruby/object:Gem::Requirement
49
+ requirement: &16626120 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.3.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *19748580
57
+ version_requirements: *16626120
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: bundler
60
- requirement: &19748100 !ruby/object:Gem::Requirement
60
+ requirement: &16625620 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.0.0
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *19748100
68
+ version_requirements: *16625620
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: jeweler
71
- requirement: &19747620 !ruby/object:Gem::Requirement
71
+ requirement: &16625080 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 1.6.4
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *19747620
79
+ version_requirements: *16625080
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: simplecov
82
- requirement: &19747100 !ruby/object:Gem::Requirement
82
+ requirement: &16624580 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,7 +87,7 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *19747100
90
+ version_requirements: *16624580
91
91
  description: Mass geotagger using GPX files.
92
92
  email: bobikx@poczta.fm
93
93
  executables:
@@ -115,8 +115,8 @@ files:
115
115
  - lib/geotagger/geotagger.rb
116
116
  - lib/geotagger/track_importer.rb
117
117
  - lib/gpx2exif.rb
118
+ - lib/gpx2png/assets/sample_marker.rb
118
119
  - lib/gpx2png/base.rb
119
- - lib/gpx2png/gpx2png.rb
120
120
  - lib/gpx2png/osm.rb
121
121
  - lib/gpx2png/osm_base.rb
122
122
  - lib/gpx2png/renderers/chunky_png_renderer.rb
@@ -142,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
142
  version: '0'
143
143
  segments:
144
144
  - 0
145
- hash: -3598611687449756095
145
+ hash: -1136394423762975328
146
146
  required_rubygems_version: !ruby/object:Gem::Requirement
147
147
  none: false
148
148
  requirements:
@@ -1,210 +0,0 @@
1
- require 'rubygems'
2
- require 'chunky_png'
3
- require 'net/http'
4
- require "uri"
5
-
6
-
7
- $:.unshift(File.dirname(__FILE__))
8
-
9
- module Gpx2png
10
- class Gpx2png
11
-
12
- TILE_WIDTH = 256
13
- TILE_HEIGHT = 256
14
-
15
- def initialize
16
- @coords = Array.new
17
- @zoom = 9
18
- @color = ChunkyPNG::Color.from_hex('#FF0000')
19
- end
20
-
21
- def add(lat, lon)
22
- @coords << { lat: lat, lon: lon }
23
- end
24
-
25
- attr_accessor :zoom, :color, :coords
26
-
27
- def dev
28
- zoom = 15
29
- @coords.collect { |c|
30
- {
31
- url: self.class.url(zoom, [c[:lat], c[:lon]]),
32
- tile: self.class.convert(zoom, [c[:lat], c[:lon]]),
33
- return: self.class.reverse_convert(zoom,
34
- self.class.convert(zoom, [c[:lat], c[:lon]])
35
- ),
36
- point: self.class.point_on_image(zoom, [c[:lat], c[:lon]])
37
- }
38
- }
39
- end
40
-
41
- def to_png(filename)
42
- download_and_join_tiles
43
- @full_image.save(filename)
44
- filename
45
- end
46
-
47
- # http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y
48
- def self.convert(zoom, coord)
49
- lat_deg, lon_deg = coord
50
- lat_rad = deg2rad(lat_deg)
51
- x = (((lon_deg + 180) / 360) * (2 ** zoom)).floor
52
- y = ((1 - Math.log(Math.tan(lat_rad) + 1 / Math.cos(lat_rad)) / Math::PI) /2 * (2 ** zoom)).floor
53
-
54
- return [x, y]
55
- end
56
-
57
- def self.url_convert(zoom, coord, server = 'b.')
58
- x, y = convert(zoom, coord)
59
- url(zoom, [x, y], server)
60
- end
61
-
62
- def self.url(zoom, coord, server = 'b.')
63
- x, y = coord
64
- url = "http://#{server}tile.openstreetmap.org\/#{zoom}\/#{x}\/#{y}.png"
65
- return url
66
- end
67
-
68
- # top-left corner
69
- def self.reverse_convert(zoom, coord)
70
- x, y = coord
71
- n = 2 ** zoom
72
- lon_deg = x.to_f / n.to_f * 360.0 - 180.0
73
- lat_deg = rad2deg(Math.atan(Math.sinh(Math::PI * (1.to_f - 2.to_f * y.to_f / n.to_f))))
74
- return [lat_deg, lon_deg]
75
- end
76
-
77
- # return where you should put point on tile
78
- def self.point_on_image(zoom, geo_coord)
79
- osm_tile_coord = convert(zoom, geo_coord)
80
- top_left_corner = reverse_convert(zoom, osm_tile_coord)
81
- bottom_right_corner = reverse_convert(zoom, [
82
- osm_tile_coord[0] + 1, osm_tile_coord[1] + 1
83
- ])
84
-
85
- # some line y = ax + b math
86
-
87
- x_geo = geo_coord[1]
88
- # offset
89
- x_offset = x_geo - top_left_corner[1]
90
- # scale
91
- x_distance = (bottom_right_corner[1] - top_left_corner[1])
92
- x = (TILE_WIDTH.to_f * (x_offset / x_distance)).round
93
-
94
- y_geo = geo_coord[0]
95
- # offset
96
- y_offset = y_geo - top_left_corner[0]
97
- # scale
98
- y_distance = (bottom_right_corner[0] - top_left_corner[0])
99
- y = (TILE_HEIGHT.to_f * (y_offset / y_distance)).round
100
-
101
- return { osm_title_coord: osm_tile_coord, pixel_offset: [x, y] }
102
- end
103
-
104
-
105
- attr_reader :lat_min, :lat_max, :lon_min, :lon_max
106
- attr_reader :tile_x_distance, :tile_y_distance
107
-
108
- def download_and_join_tiles
109
- @lat_min = @coords.collect { |c| c[:lat] }.min
110
- @lat_max = @coords.collect { |c| c[:lat] }.max
111
- @lon_min = @coords.collect { |c| c[:lon] }.min
112
- @lon_max = @coords.collect { |c| c[:lon] }.max
113
-
114
- @border_tiles = [
115
- self.class.convert(@zoom, [@lat_min, @lon_min]),
116
- self.class.convert(@zoom, [@lat_max, @lon_max])
117
- ]
118
-
119
- @tile_x_range = (@border_tiles[0][0])..(@border_tiles[1][0])
120
- @tile_y_range = (@border_tiles[1][1])..(@border_tiles[0][1])
121
-
122
- # new image
123
- @full_image_x = (1 + @tile_x_range.max - @tile_x_range.min) * TILE_WIDTH
124
- @full_image_y = (1 + @tile_y_range.max - @tile_y_range.min) * TILE_HEIGHT
125
- puts "Output image dimension #{@full_image_x}x#{@full_image_y}"
126
- @full_image = ChunkyPNG::Image.new(
127
- @full_image_x,
128
- @full_image_y,
129
- ChunkyPNG::Color::WHITE
130
- )
131
-
132
- # {:x, :y, :blob}
133
- @images = Array.new
134
-
135
- @tile_x_range.each do |x|
136
- @tile_y_range.each do |y|
137
- url = self.class.url(@zoom, [x,y])
138
-
139
- # blob time
140
- uri = URI.parse(url)
141
- response = Net::HTTP.get_response(uri)
142
- blob = response.body
143
- image = ChunkyPNG::Image.from_blob(blob)
144
-
145
- @images << {
146
- url: url,
147
- image: image,
148
- x: x,
149
- y: y
150
- }
151
-
152
- # compose image
153
- x_offset = (x - @tile_x_range.min) * TILE_WIDTH
154
- y_offset = (y - @tile_y_range.min) * TILE_HEIGHT
155
- @full_image.compose!(
156
- image,
157
- x_offset,
158
- y_offset
159
- )
160
-
161
- puts "processed #{x - @tile_x_range.min}x#{y - @tile_y_range.min} (max #{@tile_x_range.max - @tile_x_range.min}x#{@tile_y_range.max - @tile_y_range.min})"
162
- end
163
- end
164
-
165
- # sweet, image is joined
166
-
167
- # add some coords to the map
168
- (1...@coords.size).each do |i|
169
- lat_from = @coords[i-1][:lat]
170
- lon_from = @coords[i-1][:lon]
171
-
172
- lat_to = @coords[i][:lat]
173
- lon_to = @coords[i][:lon]
174
-
175
- point_from = self.class.point_on_image(@zoom, [lat_from, lon_from])
176
- point_to = self.class.point_on_image(@zoom, [lat_to, lon_to])
177
- # { osm_title_coord: osm_tile_coord, pixel_offset: [x, y] }
178
-
179
- # first point
180
- bitmap_xa = (point_from[:osm_title_coord][0] - @tile_x_range.min) * TILE_WIDTH + point_from[:pixel_offset][0]
181
- bitmap_ya = (point_from[:osm_title_coord][1] - @tile_y_range.min) * TILE_HEIGHT + point_from[:pixel_offset][1]
182
- bitmap_xb = (point_to[:osm_title_coord][0] - @tile_x_range.min) * TILE_WIDTH + point_to[:pixel_offset][0]
183
- bitmap_yb = (point_to[:osm_title_coord][1] - @tile_y_range.min) * TILE_HEIGHT + point_to[:pixel_offset][1]
184
-
185
- @full_image.line(
186
- bitmap_xa, bitmap_ya,
187
- bitmap_xb, bitmap_yb,
188
- @color
189
- )
190
-
191
- end
192
- end
193
-
194
- def expand_map
195
- # TODO expand min and max ranges
196
- end
197
-
198
-
199
- # Some math stuff
200
- def self.rad2deg(rad)
201
- return rad * 180.0 / Math::PI
202
- end
203
-
204
- def self.deg2rad(deg)
205
- return deg * Math::PI / 180.0
206
- end
207
-
208
-
209
- end
210
- end