mirror of
https://github.com/flopp/go-staticmaps.git
synced 2025-12-08 18:26:36 +00:00
Add ImageMarker. Closes #48.
This commit is contained in:
parent
1292f1734c
commit
0818a9f287
40
README.md
40
README.md
@ -81,26 +81,23 @@ See [PkgGoDev](https://pkg.go.dev/badge/github.com/flopp/go-staticmaps) for a co
|
||||
Creates a static map
|
||||
|
||||
Application Options:
|
||||
--width=PIXELS Width of the generated static map image (default: 512)
|
||||
--height=PIXELS Height of the generated static map image (default: 512)
|
||||
-o, --output=FILENAME Output file name (default: map.png)
|
||||
-t, --type=MAPTYPE Select the map type; list possible map types with '--type list'
|
||||
-c, --center=LATLNG Center coordinates (lat,lng) of the static map
|
||||
-z, --zoom=ZOOMLEVEL Zoom factor
|
||||
-b, --bbox=NW_LATLNG|SE_LATLNG
|
||||
Set the bounding box (NW_LATLNG = north-western point of the
|
||||
bounding box, SW_LATLNG = southe-western point of the bounding
|
||||
box)
|
||||
--background=COLOR Background color (default: transparent)
|
||||
-u, --useragent=USERAGENT
|
||||
Overwrite the default HTTP user agent string
|
||||
-m, --marker=MARKER Add a marker to the static map
|
||||
-p, --path=PATH Add a path to the static map
|
||||
-a, --area=AREA Add an area to the static map
|
||||
-C, --circle=CIRCLE Add a circle to the static map
|
||||
--width=PIXELS Width of the generated static map image (default: 512)
|
||||
--height=PIXELS Height of the generated static map image (default: 512)
|
||||
-o, --output=FILENAME Output file name (default: map.png)
|
||||
-t, --type=MAPTYPE Select the map type; list possible map types with '--type list'
|
||||
-c, --center=LATLNG Center coordinates (lat,lng) of the static map
|
||||
-z, --zoom=ZOOMLEVEL Zoom factor
|
||||
-b, --bbox=nwLATLNG|seLATLNG Bounding box of the static map
|
||||
--background=COLOR Background color (default: transparent)
|
||||
-u, --useragent=USERAGENT Overwrite the default HTTP user agent string
|
||||
-m, --marker=MARKER Add a marker to the static map
|
||||
-i, --imagemarker=MARKER Add an image marker to the static map
|
||||
-p, --path=PATH Add a path to the static map
|
||||
-a, --area=AREA Add an area to the static map
|
||||
-C, --circle=CIRCLE Add a circle to the static map
|
||||
|
||||
Help Options:
|
||||
-h, --help Show this help message
|
||||
-h, --help Show this help message
|
||||
|
||||
### General
|
||||
The command line interface tries to resemble [Google's Static Maps API](https://developers.google.com/maps/documentation/static-maps/intro).
|
||||
@ -122,6 +119,13 @@ The `--marker` option defines one or more map markers of the same style. Use mul
|
||||
- `label:LABEL` - where `LABEL` is an alpha numeric character, i.e. `A`-`Z`, `a`-`z`, `0`-`9`; (default: no label)
|
||||
- `labelcolor:COLOR` - where `COLOR` is either of the form `0xRRGGBB`, `0xRRGGBBAA`, or one of `black`, `blue`, `brown`, `green`, `orange`, `purple`, `red`, `yellow`, `white` (default: `black` or `white`, depending on the marker color)
|
||||
|
||||
Using the `--imagemarker` option, you can use custom images as markers:
|
||||
|
||||
--imagemarker image:IMAGEFILE|offsetx:OFFSETX|offsety:OFFSETY|LATLNG|LATLNG|...
|
||||
|
||||
`IMAGEFILE` is the file name of a PNG or JPEG file,
|
||||
|
||||
`OFFSETX` and `OFFSETY` are the pixel offsets of the reference point from the top-left corner of the image.
|
||||
|
||||
### Paths
|
||||
The `--path` option defines a path on the map. Use multiple `--path` options to add multiple paths to the map.
|
||||
|
||||
@ -103,6 +103,19 @@ func handleMarkersOption(ctx *sm.Context, parameters []string) {
|
||||
}
|
||||
}
|
||||
|
||||
func handleImageMarkersOption(ctx *sm.Context, parameters []string) {
|
||||
for _, s := range parameters {
|
||||
markers, err := sm.ParseImageMarkerString(s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
} else {
|
||||
for _, marker := range markers {
|
||||
ctx.AddObject(marker)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handlePathsOption(ctx *sm.Context, parameters []string) {
|
||||
for _, s := range parameters {
|
||||
paths, err := sm.ParsePathString(s)
|
||||
@ -153,6 +166,7 @@ func main() {
|
||||
Background string `long:"background" description:"Background color" value-name:"COLOR" default:"transparent"`
|
||||
UserAgent string `short:"u" long:"useragent" description:"Overwrite the default HTTP user agent string" value-name:"USERAGENT"`
|
||||
Markers []string `short:"m" long:"marker" description:"Add a marker to the static map" value-name:"MARKER"`
|
||||
ImageMarkers []string `short:"i" long:"imagemarker" description:"Add an image marker to the static map" value-name:"MARKER"`
|
||||
Paths []string `short:"p" long:"path" description:"Add a path to the static map" value-name:"PATH"`
|
||||
Areas []string `short:"a" long:"area" description:"Add an area to the static map" value-name:"AREA"`
|
||||
Circles []string `short:"C" long:"circle" description:"Add a circle to the static map" value-name:"CIRCLE"`
|
||||
@ -200,6 +214,7 @@ func main() {
|
||||
|
||||
handleAreasOption(ctx, opts.Areas)
|
||||
handleMarkersOption(ctx, opts.Markers)
|
||||
handleImageMarkersOption(ctx, opts.ImageMarkers)
|
||||
handleCirclesOption(ctx, opts.Circles)
|
||||
handlePathsOption(ctx, opts.Paths)
|
||||
|
||||
|
||||
127
image_marker.go
Normal file
127
image_marker.go
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright 2021 Florian Pigorsch. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/jpeg" // to be able to decode jpegs
|
||||
_ "image/png" // to be able to decode pngs
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/flopp/go-coordsparser"
|
||||
"github.com/fogleman/gg"
|
||||
"github.com/golang/geo/s2"
|
||||
)
|
||||
|
||||
// ImageMarker represents an image marker on the map
|
||||
type ImageMarker struct {
|
||||
MapObject
|
||||
Position s2.LatLng
|
||||
Img image.Image
|
||||
OffsetX float64
|
||||
OffsetY float64
|
||||
}
|
||||
|
||||
// NewImageMarker creates a new ImageMarker
|
||||
func NewImageMarker(pos s2.LatLng, img image.Image, offsetX, offsetY float64) *ImageMarker {
|
||||
m := new(ImageMarker)
|
||||
m.Position = pos
|
||||
m.Img = img
|
||||
m.OffsetX = offsetX
|
||||
m.OffsetY = offsetY
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// ParseImageMarkerString parses a string and returns an array of image markers
|
||||
func ParseImageMarkerString(s string) ([]*ImageMarker, error) {
|
||||
markers := make([]*ImageMarker, 0)
|
||||
|
||||
var img image.Image = nil
|
||||
offsetX := 0.0
|
||||
offsetY := 0.0
|
||||
|
||||
for _, ss := range strings.Split(s, "|") {
|
||||
if ok, suffix := hasPrefix(ss, "image:"); ok {
|
||||
file, err := os.Open(suffix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
img, _, err = image.Decode(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if ok, suffix := hasPrefix(ss, "offsetx:"); ok {
|
||||
var err error
|
||||
offsetX, err = strconv.ParseFloat(suffix, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if ok, suffix := hasPrefix(ss, "offsety:"); ok {
|
||||
var err error
|
||||
offsetY, err = strconv.ParseFloat(suffix, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
lat, lng, err := coordsparser.Parse(ss)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if img == nil {
|
||||
return nil, fmt.Errorf("cannot create an ImageMarker without an image: %s", s)
|
||||
}
|
||||
m := NewImageMarker(s2.LatLngFromDegrees(lat, lng), img, offsetX, offsetY)
|
||||
markers = append(markers, m)
|
||||
}
|
||||
}
|
||||
return markers, nil
|
||||
}
|
||||
|
||||
// SetImage sets the marker's image
|
||||
func (m *ImageMarker) SetImage(img image.Image) {
|
||||
m.Img = img
|
||||
}
|
||||
|
||||
// SetOffsetX sets the marker's x offset
|
||||
func (m *ImageMarker) SetOffsetX(offset float64) {
|
||||
m.OffsetX = offset
|
||||
}
|
||||
|
||||
// SetOffsetY sets the marker's y offset
|
||||
func (m *ImageMarker) SetOffsetY(offset float64) {
|
||||
m.OffsetY = offset
|
||||
}
|
||||
|
||||
// ExtraMarginPixels return the marker's left, top, right, bottom pixel extent.
|
||||
func (m *ImageMarker) ExtraMarginPixels() (float64, float64, float64, float64) {
|
||||
size := m.Img.Bounds().Size()
|
||||
return m.OffsetX, m.OffsetY, float64(size.X) - m.OffsetX, float64(size.Y) - m.OffsetY
|
||||
}
|
||||
|
||||
// Bounds returns single point rect containing the marker's geographical position.
|
||||
func (m *ImageMarker) Bounds() s2.Rect {
|
||||
r := s2.EmptyRect()
|
||||
r = r.AddPoint(m.Position)
|
||||
return r
|
||||
}
|
||||
|
||||
// Draw draws the object in the given graphical context.
|
||||
func (m *ImageMarker) Draw(gc *gg.Context, trans *Transformer) {
|
||||
if !CanDisplay(m.Position) {
|
||||
log.Printf("ImageMarker coordinates not displayable: %f/%f", m.Position.Lat.Degrees(), m.Position.Lng.Degrees())
|
||||
return
|
||||
}
|
||||
|
||||
x, y := trans.LatLngToXY(m.Position)
|
||||
gc.DrawImage(m.Img, int(x-m.OffsetX), int(y-m.OffsetY))
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user