gpx2exif 0.1.1 → 0.1.3

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.
@@ -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