├── vendor ├── github.com │ ├── jbeda │ │ ├── geom │ │ │ ├── README │ │ │ ├── .gitignore │ │ │ ├── debug.go │ │ │ ├── geom.go │ │ │ ├── util.go │ │ │ ├── line.go │ │ │ ├── segment.go │ │ │ ├── LICENSE │ │ │ ├── tri.go │ │ │ ├── path.go │ │ │ ├── coord.go │ │ │ ├── rect.go │ │ │ └── poly.go │ │ └── svgdata-go │ │ │ ├── README.md │ │ │ ├── unknown.go │ │ │ ├── factory.go │ │ │ ├── root.go │ │ │ ├── polyshape.go │ │ │ ├── units.go │ │ │ ├── attrmap.go │ │ │ ├── circle.go │ │ │ ├── rect.go │ │ │ ├── node.go │ │ │ ├── serialize.go │ │ │ ├── path.go │ │ │ └── LICENSE │ ├── pkg │ │ └── errors │ │ │ ├── .travis.yml │ │ │ ├── .gitignore │ │ │ ├── appveyor.yml │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── stack.go │ │ │ └── errors.go │ └── disintegration │ │ └── imaging │ │ ├── .travis.yml │ │ ├── doc.go │ │ ├── LICENSE │ │ ├── histogram.go │ │ ├── utils.go │ │ ├── convolution.go │ │ ├── effects.go │ │ ├── scanner.go │ │ ├── tools.go │ │ ├── adjust.go │ │ ├── helpers.go │ │ ├── README.md │ │ └── transform.go └── golang.org │ └── x │ └── image │ ├── AUTHORS │ ├── CONTRIBUTORS │ ├── PATENTS │ ├── tiff │ ├── compress.go │ ├── buffer.go │ ├── consts.go │ ├── lzw │ │ └── reader.go │ └── writer.go │ ├── LICENSE │ └── bmp │ ├── writer.go │ └── reader.go ├── images ├── ada-lovelace.jpg ├── alan-turing.jpg └── alan-turing-licence.txt ├── README-assets ├── ada-lovelace.jpg ├── ada-lovelace-cut.jpg └── ada-lovelace-svg.png ├── interface.go ├── circgrad.go ├── main.go ├── util.go ├── consts.go ├── imagecontent.go ├── Gopkg.toml ├── Gopkg.lock ├── README.md ├── svggrid.go └── LICENSE /vendor/github.com/jbeda/geom/README: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | _obj 3 | *.6 4 | -------------------------------------------------------------------------------- /images/ada-lovelace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbeda/circle-art/HEAD/images/ada-lovelace.jpg -------------------------------------------------------------------------------- /images/alan-turing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbeda/circle-art/HEAD/images/alan-turing.jpg -------------------------------------------------------------------------------- /README-assets/ada-lovelace.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbeda/circle-art/HEAD/README-assets/ada-lovelace.jpg -------------------------------------------------------------------------------- /README-assets/ada-lovelace-cut.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbeda/circle-art/HEAD/README-assets/ada-lovelace-cut.jpg -------------------------------------------------------------------------------- /README-assets/ada-lovelace-svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbeda/circle-art/HEAD/README-assets/ada-lovelace-svg.png -------------------------------------------------------------------------------- /interface.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type GridContent interface { 4 | SetSize(w, h int) 5 | 6 | // The GridContent should return a value between 0 and 1 for this "pixel" 7 | GetValue(x, y int) float64 8 | } 9 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/AUTHORS: -------------------------------------------------------------------------------- 1 | # This source code refers to The Go Authors for copyright purposes. 2 | # The master list of authors is in the main Go distribution, 3 | # visible at http://tip.golang.org/AUTHORS. 4 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # This source code was written by the Go contributors. 2 | # The master list of contributors is in the main Go distribution, 3 | # visible at http://tip.golang.org/CONTRIBUTORS. 4 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go_import_path: github.com/pkg/errors 3 | go: 4 | - 1.4.3 5 | - 1.5.4 6 | - 1.6.2 7 | - 1.7.1 8 | - tip 9 | 10 | script: 11 | - go test -v ./... 12 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - "1.7.x" 4 | - "1.8.x" 5 | - "1.9.x" 6 | - "1.10.x" 7 | 8 | before_install: 9 | - go get github.com/mattn/goveralls 10 | 11 | script: 12 | - go test -v -race -cover 13 | - $GOPATH/bin/goveralls -service=travis-ci 14 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/debug.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | import "fmt" 8 | 9 | var Debug = false 10 | 11 | func dbg(format string, args ...interface{}) { 12 | if Debug { 13 | fmt.Printf(format+"\n", args...) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/geom.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | type Bounded interface { 8 | Bounds() (bounds Rect) 9 | } 10 | 11 | type Transformable interface { 12 | Translate(offset Coord) 13 | Rotate(rad float64) 14 | Scale(xfactor, yfactor float64) 15 | } 16 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.). 3 | 4 | All the image processing functions provided by the package accept any image type that implements image.Image interface 5 | as an input, and return a new image of *image.NRGBA type (32bit RGBA colors, not premultiplied by alpha). 6 | */ 7 | package imaging 8 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | func minf(x, y float64) (r float64) { 8 | r = x 9 | if r > y { 10 | r = y 11 | } 12 | return 13 | } 14 | 15 | func maxf(x, y float64) (r float64) { 16 | r = x 17 | if r < y { 18 | r = y 19 | } 20 | return 21 | } 22 | -------------------------------------------------------------------------------- /circgrad.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/jbeda/geom" 4 | 5 | type CircularGradient struct { 6 | w, h int 7 | center geom.Coord 8 | maxDist float64 9 | } 10 | 11 | func (c *CircularGradient) SetSize(w, h int) { 12 | c.w, c.h = w, h 13 | c.center = geom.Coord{float64(c.w) / 2.0, float64(c.h) / 2.0} 14 | c.maxDist = geom.Coord{0, 0}.DistanceFrom(c.center) 15 | } 16 | 17 | func (c *CircularGradient) GetValue(x, y int) float64 { 18 | p := geom.Coord{float64(x), float64(y)} 19 | dist := p.DistanceFrom(c.center) 20 | return dist / c.maxDist 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/README.md: -------------------------------------------------------------------------------- 1 | # svgdata-go 2 | 3 | **WARNING:** This is very early library that I wrote for myself and anything may change at any time. 4 | 5 | A go library for representing SVG data and then writing it out. 6 | This isn't the best API but it is useful. 7 | 8 | The one thing this does well is collect a set of path segment and then construct a Path from those by looking for the segments that match up. 9 | This is useful for CAD applications where often times you'll get a collection of path segments and need to assemble continuous paths from those segments. -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | if len(os.Args) != 2 { 12 | fmt.Fprintln(os.Stderr, "USAGE: circle-art ") 13 | os.Exit(1) 14 | } 15 | 16 | input := os.Args[1] 17 | 18 | sg := NewSVGGrid() 19 | //sg.RenderGrid(&CircularGradient{}) 20 | ic, err := NewImageContent(input) 21 | if err != nil { 22 | panic(err) 23 | } 24 | outputPrefix := filepath.Base(input) 25 | outputPrefix = strings.TrimSuffix(outputPrefix, filepath.Ext(outputPrefix)) 26 | sg.RenderGrid(ic, outputPrefix) 27 | } 28 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/line.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | /* 8 | A line that goes through Intersection and has a normal Normal. 9 | */ 10 | type Line struct { 11 | Intersection Coord 12 | Normal Coord 13 | } 14 | 15 | func LineIntersection(l1, l2 Line) (p Coord) { 16 | b1 := l1.Normal.Unit() 17 | b1.RotateRight() 18 | unum := (l2.Normal.X*l2.Intersection.X + l2.Normal.Y*l2.Intersection.Y) 19 | uden := (l2.Normal.X*b1.X + l2.Normal.Y*b1.Y) 20 | u := unum / uden 21 | p = l1.Intersection.Plus(b1.Times(u)) 22 | return 23 | } 24 | -------------------------------------------------------------------------------- /util.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/jbeda/geom" 7 | ) 8 | 9 | func initColors(n int) []string { 10 | r := []string{} 11 | 12 | for i := 0; i < n; i++ { 13 | r = append(r, fmt.Sprintf("#00%02x00", int(scaleToRange(float64(i), float64(n), 32, 255)))) 14 | } 15 | return r 16 | } 17 | 18 | // Scales a number between 0 and inMax proportionally to outMin and outMax 19 | func scaleToRange(in, inMax, outMin, outMax float64) float64 { 20 | return outMin + (outMax-outMin)*(in/inMax) 21 | } 22 | 23 | func scaleValue(f float64) float64 { 24 | return f * unitsPerInch 25 | } 26 | 27 | func scaleCoord(c geom.Coord) geom.Coord { 28 | return geom.Coord{scaleValue(c.X), scaleValue(c.Y)} 29 | } 30 | -------------------------------------------------------------------------------- /images/alan-turing-licence.txt: -------------------------------------------------------------------------------- 1 | Please find, attached, a copy of the image, which I am happy to supply to you with permission to use solely according to your licence, detailed at http://creativecommons.org/licenses/by-nc-nd/3.0/ 2 | 3 | It is essential that you ensure images are captioned and credited as they are on the Gallery's own website (search/find each item by NPG number at http://www.npg.org.uk/collections/search/advanced-search.php). 4 | 5 | This has been supplied to you free of charge. I would be grateful if you would please consider making a donation at http://www.npg.org.uk/support/donation/general-donation.php in support of our work and the service we provide. 6 | 7 | Regards 8 | 9 | Rights and Images Department 10 | National Portrait Gallery St Martin's Place London WC2H OHE -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: build-{build}.{branch} 2 | 3 | clone_folder: C:\gopath\src\github.com\pkg\errors 4 | shallow_clone: true # for startup speed 5 | 6 | environment: 7 | GOPATH: C:\gopath 8 | 9 | platform: 10 | - x64 11 | 12 | # http://www.appveyor.com/docs/installed-software 13 | install: 14 | # some helpful output for debugging builds 15 | - go version 16 | - go env 17 | # pre-installed MinGW at C:\MinGW is 32bit only 18 | # but MSYS2 at C:\msys64 has mingw64 19 | - set PATH=C:\msys64\mingw64\bin;%PATH% 20 | - gcc --version 21 | - g++ --version 22 | 23 | build_script: 24 | - go install -v ./... 25 | 26 | test_script: 27 | - set PATH=C:\gopath\bin;%PATH% 28 | - go test -v ./... 29 | 30 | #artifacts: 31 | # - path: '%GOPATH%\bin\*.exe' 32 | deploy: off 33 | -------------------------------------------------------------------------------- /consts.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | const ( 4 | // The total width/height of each "cell" 5 | cSpace = 0.12 6 | // The min between circles 7 | cMargin = 0.025 8 | // The radius for "white" circles 9 | cMinRadius = 0.01 10 | // The radius of "black" circles 11 | cMaxRadius = (cSpace - cMargin) / 2.0 12 | 13 | // The margin between edge of art and first circle 14 | canvasMargin = 0.2 15 | 16 | canvasAspectRatio = 3.0 / 2.0 17 | 18 | // canvasHeight = 10.5 19 | canvasHeight = 5 20 | canvasInsideHeight = canvasHeight - canvasMargin*2.0 21 | canvasWidth = canvasHeight * canvasAspectRatio 22 | canvasInsideWidth = canvasWidth - canvasMargin*2.0 23 | 24 | // The total size of the board 25 | boardWidth = 19.0 26 | boardHeight = 11.0 27 | 28 | // The units to use when rendering SVG. It shouldn't matter but the GlowForge seems to care. 29 | unitsPerInch = 96 30 | strokeWidth = 0.01 31 | ) 32 | -------------------------------------------------------------------------------- /imagecontent.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "image" 5 | 6 | "image/color" 7 | 8 | "github.com/disintegration/imaging" 9 | ) 10 | 11 | type ImageContent struct { 12 | w, h int 13 | src, small image.Image 14 | } 15 | 16 | func NewImageContent(fn string) (*ImageContent, error) { 17 | src, err := imaging.Open(fn) 18 | if err != nil { 19 | return nil, err 20 | } 21 | 22 | src = imaging.Grayscale(src) 23 | 24 | if src.Bounds().Dx() < src.Bounds().Dy() { 25 | src = imaging.Rotate90(src) 26 | } 27 | 28 | return &ImageContent{src: src}, nil 29 | } 30 | 31 | func (ic *ImageContent) SetSize(w, h int) { 32 | ic.w, ic.h = w, h 33 | ic.small = imaging.Invert(imaging.Fill(ic.src, ic.w, ic.h, imaging.Center, imaging.Lanczos)) 34 | } 35 | 36 | func (ic *ImageContent) GetValue(x, y int) float64 { 37 | c := color.GrayModel.Convert(ic.small.At(x, y)).(color.Gray) 38 | return float64(c.Y) / 255.0 39 | } 40 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [[constraint]] 29 | name = "github.com/disintegration/imaging" 30 | version = "1.4.1" 31 | 32 | [[constraint]] 33 | branch = "master" 34 | name = "github.com/jbeda/geom" 35 | 36 | [[constraint]] 37 | branch = "master" 38 | name = "github.com/jbeda/svgdata-go" 39 | 40 | [prune] 41 | go-tests = true 42 | unused-packages = true 43 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/segment.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | type Segment struct { 8 | A, B Coord 9 | } 10 | 11 | func (s *Segment) IntersectParameters(t *Segment) (ps, pt float64) { 12 | x1, y1 := s.A.X, s.A.Y 13 | x2, y2 := s.B.X, s.B.Y 14 | x3, y3 := t.A.X, t.A.Y 15 | x4, y4 := t.B.X, t.B.Y 16 | 17 | x4x3 := x4 - x3 18 | y1y3 := y1 - y3 19 | y4y3 := y4 - y3 20 | x1x3 := x1 - x3 21 | x2x1 := x2 - x1 22 | y2y1 := y2 - y1 23 | 24 | ps = (x4x3*y1y3 - y4y3*x1x3) / (y4y3*x2x1 - x4x3*y2y1) 25 | pt = (x2x1*y1y3 - y2y1*x1x3) / (y4y3*x2x1 - x4x3*y2y1) 26 | 27 | return 28 | } 29 | 30 | func (s *Segment) Intersection(t *Segment) (p Coord, ok bool) { 31 | ps, pt := s.IntersectParameters(t) 32 | 33 | p.X = s.A.X + ps*(s.B.X-s.A.X) 34 | p.Y = s.A.Y + ps*(s.B.Y-s.A.Y) 35 | 36 | ok = ps >= 0 && ps <= 1 && pt >= 0 && pt <= 1 37 | 38 | return 39 | } 40 | 41 | func (s *Segment) Extrapolate(t float64) (p Coord) { 42 | p.X = s.A.X + t*(s.B.X-s.A.X) 43 | p.Y = s.A.Y + t*(s.B.Y-s.A.Y) 44 | return 45 | } 46 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2018 Grigory Dryapak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/unknown.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | // Unknown is an SVG element that has no specialized code or representation. 18 | type Unknown struct { 19 | nodeImpl 20 | } 21 | 22 | func init() { 23 | unknownCreator = func() Node { return createUnknown() } 24 | } 25 | 26 | func createUnknown() *Unknown { 27 | return &Unknown{} 28 | } 29 | 30 | func NewGroup() Node { 31 | u := createUnknown() 32 | u.name = "g" 33 | return u 34 | } 35 | 36 | func NewStyle() Node { 37 | u := createUnknown() 38 | u.name = "style" 39 | return u 40 | } 41 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/factory.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import "encoding/xml" 18 | 19 | type nodeCreator func() Node 20 | 21 | var factoryMap map[string]nodeCreator = map[string]nodeCreator{} 22 | var unknownCreator nodeCreator 23 | 24 | func CreateNodeFromName(n xml.Name) Node { 25 | if n.Space != SvgNs { 26 | return nil 27 | } 28 | 29 | creator, ok := factoryMap[n.Local] 30 | if !ok { 31 | creator = unknownCreator 32 | } 33 | 34 | return creator() 35 | } 36 | 37 | func RegisterNodeCreator(n string, c nodeCreator) { 38 | factoryMap[n] = c 39 | } 40 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | name = "github.com/disintegration/imaging" 6 | packages = ["."] 7 | revision = "fd34ef7671b12cdf1b024d98c6b327b2770d32c4" 8 | version = "v1.4.1" 9 | 10 | [[projects]] 11 | branch = "master" 12 | name = "github.com/jbeda/geom" 13 | packages = ["."] 14 | revision = "4107299174a83a444c887753bce11e538121c6c4" 15 | 16 | [[projects]] 17 | branch = "master" 18 | name = "github.com/jbeda/svgdata-go" 19 | packages = ["."] 20 | revision = "010a637888c7e0eb5b24333922498c300f3157d5" 21 | 22 | [[projects]] 23 | name = "github.com/pkg/errors" 24 | packages = ["."] 25 | revision = "645ef00459ed84a119197bfb8d8205042c6df63d" 26 | version = "v0.8.0" 27 | 28 | [[projects]] 29 | branch = "master" 30 | name = "golang.org/x/image" 31 | packages = [ 32 | "bmp", 33 | "tiff", 34 | "tiff/lzw" 35 | ] 36 | revision = "f3a9b89b59def9194717c1d0bd4c0d08fa1afa7b" 37 | 38 | [solve-meta] 39 | analyzer-name = "dep" 40 | analyzer-version = 1 41 | inputs-digest = "2c915bbe1226c52a8a13aae49ff7883c212f7c923b1e0ce492a868c7c29a5033" 42 | solver-name = "gps-cdcl" 43 | solver-version = 1 44 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/root.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | // Root represents the root element. 18 | type Root struct { 19 | nodeImpl 20 | } 21 | 22 | var _ Node = (*Root)(nil) 23 | 24 | func CreateRoot() *Root { 25 | r := &Root{} 26 | r.nodeImpl.name = "svg" 27 | r.nodeImpl.onMarshalAttrs = r.marshalAttrs 28 | r.nodeImpl.onUnmarshalAttrs = r.unmarshalAttrs 29 | return r 30 | } 31 | 32 | func init() { 33 | RegisterNodeCreator("svg", func() Node { return CreateRoot() }) 34 | } 35 | 36 | func (r *Root) marshalAttrs(am AttrMap) { 37 | 38 | } 39 | 40 | func (r *Root) unmarshalAttrs(am AttrMap) error { 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/histogram.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "image" 5 | "sync" 6 | ) 7 | 8 | // Histogram returns a normalized histogram of an image. 9 | // 10 | // Resulting histogram is represented as an array of 256 floats, where 11 | // histogram[i] is a probability of a pixel being of a particular luminance i. 12 | func Histogram(img image.Image) [256]float64 { 13 | var mu sync.Mutex 14 | var histogram [256]float64 15 | var total float64 16 | 17 | src := newScanner(img) 18 | if src.w == 0 || src.h == 0 { 19 | return histogram 20 | } 21 | 22 | parallel(0, src.h, func(ys <-chan int) { 23 | var tmpHistogram [256]float64 24 | var tmpTotal float64 25 | scanLine := make([]uint8, src.w*4) 26 | for y := range ys { 27 | src.scan(0, y, src.w, y+1, scanLine) 28 | i := 0 29 | for x := 0; x < src.w; x++ { 30 | r := scanLine[i+0] 31 | g := scanLine[i+1] 32 | b := scanLine[i+2] 33 | y := 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b) 34 | tmpHistogram[int(y+0.5)]++ 35 | tmpTotal++ 36 | i += 4 37 | } 38 | } 39 | mu.Lock() 40 | for i := 0; i < 256; i++ { 41 | histogram[i] += tmpHistogram[i] 42 | } 43 | total += tmpTotal 44 | mu.Unlock() 45 | }) 46 | 47 | for i := 0; i < 256; i++ { 48 | histogram[i] = histogram[i] / total 49 | } 50 | return histogram 51 | } 52 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/tiff/compress.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | import ( 8 | "bufio" 9 | "io" 10 | ) 11 | 12 | type byteReader interface { 13 | io.Reader 14 | io.ByteReader 15 | } 16 | 17 | // unpackBits decodes the PackBits-compressed data in src and returns the 18 | // uncompressed data. 19 | // 20 | // The PackBits compression format is described in section 9 (p. 42) 21 | // of the TIFF spec. 22 | func unpackBits(r io.Reader) ([]byte, error) { 23 | buf := make([]byte, 128) 24 | dst := make([]byte, 0, 1024) 25 | br, ok := r.(byteReader) 26 | if !ok { 27 | br = bufio.NewReader(r) 28 | } 29 | 30 | for { 31 | b, err := br.ReadByte() 32 | if err != nil { 33 | if err == io.EOF { 34 | return dst, nil 35 | } 36 | return nil, err 37 | } 38 | code := int(int8(b)) 39 | switch { 40 | case code >= 0: 41 | n, err := io.ReadFull(br, buf[:code+1]) 42 | if err != nil { 43 | return nil, err 44 | } 45 | dst = append(dst, buf[:n]...) 46 | case code == -128: 47 | // No-op. 48 | default: 49 | if b, err = br.ReadByte(); err != nil { 50 | return nil, err 51 | } 52 | for j := 0; j < 1-code; j++ { 53 | buf[j] = b 54 | } 55 | dst = append(dst, buf[:1-code]...) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Dave Cheney 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012 John Asmuth. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY JOHN ASMUTH ``AS IS'' AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 15 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 16 | SHALL JOHN ASMUTH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 18 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 19 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 20 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 21 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of John Asmuth. 27 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google Inc. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/polyshape.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import "github.com/jbeda/geom" 18 | 19 | // Polyshape is an SVG element is a shape specified with a list of straight 20 | // lines. 21 | type Polyshape struct { 22 | nodeImpl 23 | 24 | // TODO: Handle Points 25 | Points []geom.Coord 26 | } 27 | 28 | func init() { 29 | RegisterNodeCreator("polygon", CreatePolygon) 30 | RegisterNodeCreator("polyline", CreatePolyline) 31 | } 32 | 33 | func CreatePolygon() Node { 34 | p := &Polyshape{} 35 | p.nodeImpl.name = "polygon" 36 | p.nodeImpl.onMarshalAttrs = p.marshalAttrs 37 | p.nodeImpl.onUnmarshalAttrs = p.unmarshalAttrs 38 | 39 | return p 40 | } 41 | 42 | func CreatePolyline() Node { 43 | p := &Polyshape{} 44 | p.nodeImpl.name = "polygon" 45 | p.nodeImpl.onMarshalAttrs = p.marshalAttrs 46 | p.nodeImpl.onUnmarshalAttrs = p.unmarshalAttrs 47 | 48 | return p 49 | } 50 | 51 | func (p *Polyshape) marshalAttrs(am AttrMap) { 52 | } 53 | 54 | func (p *Polyshape) unmarshalAttrs(am AttrMap) error { 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # circle-art 2 | 3 | This is a small program that takes a bitmap image and converts it to a grid of SVG circles. The size of the circles depends on the intensity of the image at that point. 4 | 5 | I created this for laser cutting on a [Glowforge](https://glowforge.com) laser cutter. It can probably be adapted to other cutters and things like plotters. 6 | 7 | ## Example 8 | 9 | | Input | SVG | Cut | 10 | |-------|-----|-----| 11 | |![](README-assets/ada-lovelace.jpg)|![](README-assets/ada-lovelace-svg.png)|![](README-assets/ada-lovelace-cut.jpg)| 12 | 13 | ## WARNING! 14 | 15 | This is alpha software and you could literally light your house on fire if you aren't careful. Lasers can lay down a lot of heat and these designs concentrate a lot of it in a small area. Please stay by your laser as it is cutting and watch for flare ups. 16 | 17 | The output is set up with multiple colors with the idea that you cut one color at a time. This offsets the circles being cut in order to let things cool down before you cut again right next to a previous cut. This is based on experience. 18 | 19 | ## Install and Usage 20 | 21 | Right now the only way to get this running is to have Go installed on your machine and work from the command line. I may package this up at some point for download via other mechanisms or host it on a web site but for now it is a little fiddly. 22 | 23 | You can probably do a `go get github.com/jbeda/circle-art` and have it show up in your `$GOPATH/bin` directory. Or you can clone this repo and run `go run *.go `. 24 | 25 | There are a bunch of constants in `constants.go` that you can play with. I'll probably turn those into command line flags at some point. -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/utils.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "image" 5 | "runtime" 6 | "sync" 7 | ) 8 | 9 | // parallel processes the data in separate goroutines. 10 | func parallel(start, stop int, fn func(<-chan int)) { 11 | count := stop - start 12 | if count < 1 { 13 | return 14 | } 15 | 16 | procs := runtime.GOMAXPROCS(0) 17 | if procs > count { 18 | procs = count 19 | } 20 | 21 | c := make(chan int, count) 22 | for i := start; i < stop; i++ { 23 | c <- i 24 | } 25 | close(c) 26 | 27 | var wg sync.WaitGroup 28 | for i := 0; i < procs; i++ { 29 | wg.Add(1) 30 | go func() { 31 | defer wg.Done() 32 | fn(c) 33 | }() 34 | } 35 | wg.Wait() 36 | } 37 | 38 | // absint returns the absolute value of i. 39 | func absint(i int) int { 40 | if i < 0 { 41 | return -i 42 | } 43 | return i 44 | } 45 | 46 | // clamp rounds and clamps float64 value to fit into uint8. 47 | func clamp(x float64) uint8 { 48 | v := int64(x + 0.5) 49 | if v > 255 { 50 | return 255 51 | } 52 | if v > 0 { 53 | return uint8(v) 54 | } 55 | return 0 56 | } 57 | 58 | func reverse(pix []uint8) { 59 | if len(pix) <= 4 { 60 | return 61 | } 62 | i := 0 63 | j := len(pix) - 4 64 | for i < j { 65 | pix[i+0], pix[j+0] = pix[j+0], pix[i+0] 66 | pix[i+1], pix[j+1] = pix[j+1], pix[i+1] 67 | pix[i+2], pix[j+2] = pix[j+2], pix[i+2] 68 | pix[i+3], pix[j+3] = pix[j+3], pix[i+3] 69 | i += 4 70 | j -= 4 71 | } 72 | } 73 | 74 | func toNRGBA(img image.Image) *image.NRGBA { 75 | if img, ok := img.(*image.NRGBA); ok { 76 | return &image.NRGBA{ 77 | Pix: img.Pix, 78 | Stride: img.Stride, 79 | Rect: img.Rect.Sub(img.Rect.Min), 80 | } 81 | } 82 | return Clone(img) 83 | } 84 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/tiff/buffer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | import "io" 8 | 9 | // buffer buffers an io.Reader to satisfy io.ReaderAt. 10 | type buffer struct { 11 | r io.Reader 12 | buf []byte 13 | } 14 | 15 | // fill reads data from b.r until the buffer contains at least end bytes. 16 | func (b *buffer) fill(end int) error { 17 | m := len(b.buf) 18 | if end > m { 19 | if end > cap(b.buf) { 20 | newcap := 1024 21 | for newcap < end { 22 | newcap *= 2 23 | } 24 | newbuf := make([]byte, end, newcap) 25 | copy(newbuf, b.buf) 26 | b.buf = newbuf 27 | } else { 28 | b.buf = b.buf[:end] 29 | } 30 | if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil { 31 | end = m + n 32 | b.buf = b.buf[:end] 33 | return err 34 | } 35 | } 36 | return nil 37 | } 38 | 39 | func (b *buffer) ReadAt(p []byte, off int64) (int, error) { 40 | o := int(off) 41 | end := o + len(p) 42 | if int64(end) != off+int64(len(p)) { 43 | return 0, io.ErrUnexpectedEOF 44 | } 45 | 46 | err := b.fill(end) 47 | return copy(p, b.buf[o:end]), err 48 | } 49 | 50 | // Slice returns a slice of the underlying buffer. The slice contains 51 | // n bytes starting at offset off. 52 | func (b *buffer) Slice(off, n int) ([]byte, error) { 53 | end := off + n 54 | if err := b.fill(end); err != nil { 55 | return nil, err 56 | } 57 | return b.buf[off:end], nil 58 | } 59 | 60 | // newReaderAt converts an io.Reader into an io.ReaderAt. 61 | func newReaderAt(r io.Reader) io.ReaderAt { 62 | if ra, ok := r.(io.ReaderAt); ok { 63 | return ra 64 | } 65 | return &buffer{ 66 | r: r, 67 | buf: make([]byte, 0, 1024), 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/units.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import ( 18 | "fmt" 19 | "regexp" 20 | "strconv" 21 | 22 | "github.com/pkg/errors" 23 | ) 24 | 25 | const ( 26 | dpi = float64(96) // CSS standard. Good enough. 27 | mmPerInch = float64(25.4) 28 | mmPerCm = float64(10) 29 | ptPerInch = float64(72) 30 | ptPerPc = float64(12) 31 | ) 32 | 33 | var valueRE *regexp.Regexp = regexp.MustCompile(`^([-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?)(.*)$`) 34 | 35 | // parseValue parses a string value and returns the equivalent in pixels. 36 | func parseValue(s string) (float64, error) { 37 | caps := valueRE.FindStringSubmatch(s) 38 | if len(caps) == 0 { 39 | return 0, fmt.Errorf("Unparsable value: %s", s) 40 | } 41 | v, err := strconv.ParseFloat(caps[1], 64) 42 | if err != nil { 43 | return 0.0, errors.Wrapf(err, "Error parsing value: %s", s) 44 | } 45 | 46 | switch u := caps[2]; u { 47 | case "": 48 | fallthrough 49 | case "px": 50 | return v, nil 51 | case "in": 52 | return v * dpi, nil 53 | case "mm": 54 | return v * (dpi / mmPerInch), nil 55 | case "cm": 56 | return v * (mmPerCm * dpi / mmPerInch), nil 57 | case "pt": 58 | return v * (dpi / ptPerInch), nil 59 | case "pc": 60 | return v * (ptPerPc * dpi / ptPerInch), nil 61 | default: 62 | return 0, fmt.Errorf("Unknown unit: %s", u) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/attrmap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import ( 18 | "fmt" 19 | 20 | "github.com/pkg/errors" 21 | ) 22 | 23 | type AttrMap map[string]string 24 | 25 | // ExtractValue will pull a value out of the AttrMap. It will convert it to a float and delete it from the map. If it 26 | // is not in the map 0.0 will be returned. An error will be returned if this is not a parsable value. 27 | func (am AttrMap) ExtractValue(k string) (float64, error) { 28 | var v float64 29 | var err error 30 | str, ok := am[k] 31 | if ok { 32 | v, err = parseValue(str) 33 | if err != nil { 34 | return 0, errors.WithStack(err) 35 | } 36 | delete(am, k) 37 | return v, nil 38 | } 39 | return v, nil 40 | } 41 | 42 | // ExtractValue will pull a value out of the AttrMap. It will convert it to a float and delete it from the map. If it 43 | // is not in the map an error will be returned. An error will be returned if this is not a parsable value. 44 | func (am AttrMap) ExtractValueNoDefault(k string) (float64, error) { 45 | var v float64 46 | var err error 47 | str, ok := am[k] 48 | if !ok { 49 | return 0, errors.New(fmt.Sprintf("no value for %s specified", k)) 50 | } 51 | if ok { 52 | v, err = parseValue(str) 53 | if err != nil { 54 | return 0, errors.WithStack(err) 55 | } 56 | delete(am, k) 57 | return v, nil 58 | } 59 | return 0, nil 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/circle.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import "github.com/jbeda/geom" 18 | 19 | // Circle is an SVG element that has no specialized code or representation. 20 | type Circle struct { 21 | nodeImpl 22 | Center geom.Coord 23 | Radius float64 24 | } 25 | 26 | func init() { 27 | RegisterNodeCreator("circle", func() Node { return createCircle() }) 28 | } 29 | 30 | func createCircle() *Circle { 31 | c := &Circle{} 32 | c.nodeImpl.name = "circle" 33 | c.nodeImpl.onMarshalAttrs = c.marshalAttrs 34 | c.nodeImpl.onUnmarshalAttrs = c.unmarshalAttrs 35 | return c 36 | } 37 | 38 | func NewCircle(c geom.Coord, r float64) *Circle { 39 | n := createCircle() 40 | n.Center = c 41 | n.Radius = r 42 | return n 43 | } 44 | 45 | func (c *Circle) marshalAttrs(am AttrMap) { 46 | am["cx"] = floatToString(c.Center.X) 47 | am["cy"] = floatToString(c.Center.Y) 48 | am["r"] = floatToString(c.Radius) 49 | } 50 | 51 | func (c *Circle) unmarshalAttrs(am AttrMap) error { 52 | cx, err := parseValue(am["cx"]) 53 | if err != nil { 54 | return err 55 | } 56 | delete(am, "cx") 57 | 58 | cy, err := parseValue(am["cy"]) 59 | if err != nil { 60 | return err 61 | } 62 | delete(am, "cy") 63 | 64 | r, err := parseValue(am["r"]) 65 | if err != nil { 66 | return err 67 | } 68 | delete(am, "r") 69 | 70 | c.Center = geom.Coord{X: cx, Y: cy} 71 | c.Radius = r 72 | 73 | return nil 74 | } 75 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/tri.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | type Triangle struct { 8 | A, B, C Coord 9 | } 10 | 11 | func (me *Triangle) Bounds() (bounds Rect) { 12 | bounds = Rect{me.A, me.A} 13 | bounds.ExpandToContainCoord(me.B) 14 | bounds.ExpandToContainCoord(me.C) 15 | return 16 | } 17 | 18 | func (me *Triangle) Equals(oi interface{}) bool { 19 | ot, ok := oi.(*Triangle) 20 | if !ok { 21 | return false 22 | } 23 | if me.A.EqualsCoord(ot.A) { 24 | if me.B.EqualsCoord(ot.B) { 25 | return me.C.EqualsCoord(ot.C) 26 | } 27 | if me.B.EqualsCoord(ot.C) { 28 | return me.C.EqualsCoord(ot.B) 29 | } 30 | } 31 | if me.A.EqualsCoord(ot.B) { 32 | if me.B.EqualsCoord(ot.A) { 33 | return me.C.EqualsCoord(ot.C) 34 | } 35 | if me.B.EqualsCoord(ot.C) { 36 | return me.C.EqualsCoord(ot.A) 37 | } 38 | } 39 | if me.A.EqualsCoord(ot.C) { 40 | if me.B.EqualsCoord(ot.B) { 41 | return me.C.EqualsCoord(ot.A) 42 | } 43 | if me.B.EqualsCoord(ot.A) { 44 | return me.C.EqualsCoord(ot.B) 45 | } 46 | } 47 | return false 48 | } 49 | 50 | func (me *Triangle) Translate(offset Coord) { 51 | me.A.Translate(offset) 52 | me.B.Translate(offset) 53 | me.C.Translate(offset) 54 | } 55 | 56 | func (me *Triangle) Scale(xf, yf float64) { 57 | me.A.Scale(xf, yf) 58 | me.B.Scale(xf, yf) 59 | me.C.Scale(xf, yf) 60 | } 61 | 62 | func (me *Triangle) Rotate(rad float64) { 63 | me.A.Rotate(rad) 64 | me.B.Rotate(rad) 65 | me.C.Rotate(rad) 66 | } 67 | 68 | func (me *Triangle) Vertices() (vertices []Coord) { 69 | vertices = []Coord{me.A, me.B, me.C} 70 | return 71 | } 72 | 73 | func (me *Triangle) ContainsCoord(p Coord) bool { 74 | leftA := CrossProduct(me.B.Minus(me.A), p.Minus(me.A)) < 0 75 | leftB := CrossProduct(me.C.Minus(me.B), p.Minus(me.B)) < 0 76 | leftC := CrossProduct(me.A.Minus(me.C), p.Minus(me.C)) < 0 77 | return leftA == leftB && leftA == leftC 78 | } 79 | 80 | func (me *Triangle) HasVertex(v Coord) bool { 81 | return v.EqualsCoord(me.A) || v.EqualsCoord(me.B) || v.EqualsCoord(me.C) 82 | } 83 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/rect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import "github.com/jbeda/geom" 18 | 19 | // Circle is an SVG element that has no specialized code or representation. 20 | type Rect struct { 21 | nodeImpl 22 | R geom.Rect 23 | } 24 | 25 | func init() { 26 | RegisterNodeCreator("rect", func() Node { return createRect() }) 27 | } 28 | 29 | func createRect() *Rect { 30 | r := &Rect{} 31 | r.nodeImpl.name = "rect" 32 | r.nodeImpl.onMarshalAttrs = r.marshalAttrs 33 | r.nodeImpl.onUnmarshalAttrs = r.unmarshalAttrs 34 | return r 35 | } 36 | 37 | func NewRect(r geom.Rect) *Rect { 38 | n := createRect() 39 | n.R = r 40 | return n 41 | } 42 | 43 | func NewRectXYWH(x, y, w, h float64) *Rect { 44 | return NewRect(geom.Rect{ 45 | geom.Coord{x, y}, 46 | geom.Coord{x + w, y + h}, 47 | }) 48 | } 49 | 50 | func (r *Rect) marshalAttrs(am AttrMap) { 51 | am["x"] = floatToString(r.R.Min.X) 52 | am["y"] = floatToString(r.R.Min.Y) 53 | am["width"] = floatToString(r.R.Width()) 54 | am["height"] = floatToString(r.R.Height()) 55 | } 56 | 57 | func (r *Rect) unmarshalAttrs(am AttrMap) error { 58 | x, err := am.ExtractValue("x") 59 | if err != nil { 60 | return err 61 | } 62 | 63 | y, err := am.ExtractValue("y") 64 | if err != nil { 65 | return err 66 | } 67 | 68 | width, err := am.ExtractValueNoDefault("width") 69 | if err != nil { 70 | return err 71 | } 72 | 73 | height, err := am.ExtractValueNoDefault("height") 74 | if err != nil { 75 | return nil 76 | } 77 | 78 | r.R.Min = geom.Coord{x, y} 79 | r.R.Max = geom.Coord{x + width, y + height} 80 | 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/README.md: -------------------------------------------------------------------------------- 1 | # errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) 2 | 3 | Package errors provides simple error handling primitives. 4 | 5 | `go get github.com/pkg/errors` 6 | 7 | The traditional error handling idiom in Go is roughly akin to 8 | ```go 9 | if err != nil { 10 | return err 11 | } 12 | ``` 13 | which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. 14 | 15 | ## Adding context to an error 16 | 17 | The errors.Wrap function returns a new error that adds context to the original error. For example 18 | ```go 19 | _, err := ioutil.ReadAll(r) 20 | if err != nil { 21 | return errors.Wrap(err, "read failed") 22 | } 23 | ``` 24 | ## Retrieving the cause of an error 25 | 26 | Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. 27 | ```go 28 | type causer interface { 29 | Cause() error 30 | } 31 | ``` 32 | `errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: 33 | ```go 34 | switch err := errors.Cause(err).(type) { 35 | case *MyError: 36 | // handle specifically 37 | default: 38 | // unknown error 39 | } 40 | ``` 41 | 42 | [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). 43 | 44 | ## Contributing 45 | 46 | We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. 47 | 48 | Before proposing a change, please discuss your change by raising an issue. 49 | 50 | ## Licence 51 | 52 | BSD-2-Clause 53 | -------------------------------------------------------------------------------- /svggrid.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "math" 7 | 8 | "bytes" 9 | 10 | "github.com/jbeda/geom" 11 | svgdata "github.com/jbeda/svgdata-go" 12 | ) 13 | 14 | type SVGGrid struct { 15 | xNum, yNum int 16 | xSpace, ySpace float64 17 | } 18 | 19 | func NewSVGGrid() *SVGGrid { 20 | sg := &SVGGrid{} 21 | 22 | sg.xNum = int(math.Floor(canvasInsideWidth / cSpace)) 23 | sg.xSpace = canvasInsideWidth / float64(sg.xNum) 24 | sg.yNum = int(math.Floor(canvasInsideHeight / cSpace)) 25 | sg.ySpace = canvasInsideHeight / float64(sg.yNum) 26 | 27 | return sg 28 | } 29 | 30 | func (sg *SVGGrid) createStyleElement() svgdata.Node { 31 | style := svgdata.NewStyle() 32 | style.Attrs()["type"] = "text/css" 33 | 34 | colors := initColors(4) 35 | 36 | b := bytes.Buffer{} 37 | b.WriteString(fmt.Sprintf(".border{fill:none;stroke:red;stroke-width:%g;}\n", scaleValue(strokeWidth))) 38 | for i := 0; i < 4; i++ { 39 | b.WriteString(fmt.Sprintf(".c%d{fill:none;stroke:%s;stroke-width:%g;}\n", i, colors[i], scaleValue(strokeWidth))) 40 | } 41 | 42 | style.SetText(b.String()) 43 | return style 44 | } 45 | 46 | func (sg *SVGGrid) CreateRoot() *svgdata.Root { 47 | r := svgdata.CreateRoot() 48 | r.Attrs()["viewBox"] = fmt.Sprintf("0 0 %g %g", scaleValue(boardWidth), scaleValue(boardHeight)) 49 | r.Attrs()["version"] = "1.1" 50 | //r.Attrs()["width"] = fmt.Sprintf("%gin", boardWidth) 51 | //r.Attrs()["height"] = fmt.Sprintf("%gin", boardHeight) 52 | r.Attrs()["x"] = "0px" 53 | r.Attrs()["y"] = "0px" 54 | r.Attrs()["style"] = fmt.Sprintf("enable-background:new %s;", r.Attrs()["viewBox"]) 55 | 56 | r.AddChild(sg.createStyleElement()) 57 | 58 | return r 59 | } 60 | 61 | func (sg *SVGGrid) RenderGrid(gc GridContent, outputPrefix string) { 62 | gc.SetSize(sg.xNum, sg.yNum) 63 | 64 | xOffset := (boardWidth - canvasWidth) / 2.0 65 | yOffset := (boardHeight - canvasHeight) / 2.0 66 | 67 | r := sg.CreateRoot() 68 | 69 | for xSkip := 0; xSkip < 2; xSkip++ { 70 | for ySkip := 0; ySkip < 2; ySkip++ { 71 | 72 | if xSkip == 1 && ySkip == 1 { 73 | outline := svgdata.NewRectXYWH(scaleValue(xOffset), scaleValue(yOffset), scaleValue(canvasWidth), scaleValue(canvasHeight)) 74 | r.AddChild(outline) 75 | outline.Attrs()["class"] = "border" 76 | } 77 | 78 | g := svgdata.NewGroup() 79 | r.AddChild(g) 80 | 81 | for x := 0 + xSkip; x < sg.xNum; x += 2 { 82 | for y := 0 + ySkip; y < sg.yNum; y += 2 { 83 | c := scaleCoord(geom.Coord{ 84 | xOffset + canvasMargin + cSpace/2 + float64(x)*sg.xSpace, 85 | yOffset + canvasMargin + cSpace/2 + float64(y)*sg.ySpace, 86 | }) 87 | rRaw := gc.GetValue(x, y) 88 | rad := scaleValue(scaleToRange(rRaw, 1.0, cMinRadius, cMaxRadius)) 89 | circle := svgdata.NewCircle(c, rad) 90 | circle.Attrs()["class"] = fmt.Sprintf("c%d", 2*xSkip+ySkip) 91 | g.AddChild(circle) 92 | } 93 | } 94 | } 95 | } 96 | 97 | // Write out the SVG file 98 | d, _ := svgdata.Marshal(r, true) 99 | ioutil.WriteFile(fmt.Sprintf("%s.svg", outputPrefix), d, 0644) 100 | } 101 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/path.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | import ( 8 | "math" 9 | ) 10 | 11 | type Path struct { 12 | vertices []Coord 13 | bounds Rect 14 | } 15 | 16 | func (p *Path) Translate(offset Coord) { 17 | p.bounds.Translate(offset) 18 | for i := range p.vertices { 19 | p.vertices[i].Translate(offset) 20 | } 21 | } 22 | 23 | func (p *Path) Rotate(rad float64) { 24 | for i := range p.vertices { 25 | p.vertices[i].Rotate(rad) 26 | } 27 | p.bounds = Rect{p.vertices[0], p.vertices[0]} 28 | p.bounds.ExpandToContain(CoordChan(p.vertices[1:])) 29 | } 30 | 31 | func (p *Path) Scale(xf, yf float64) { 32 | 33 | for i := range p.vertices { 34 | p.vertices[i].Scale(xf, yf) 35 | } 36 | p.bounds.Scale(xf, yf) 37 | } 38 | 39 | func (p *Path) Clone() (op *Path) { 40 | op = &Path{} 41 | op.bounds = p.bounds 42 | op.vertices = append([]Coord{}, p.vertices...) 43 | return 44 | } 45 | 46 | //uncomment to check interface fulfillment 47 | //var _ Bounded = &Path{} 48 | 49 | func (p *Path) Equals(oi interface{}) bool { 50 | o, ok := oi.(*Path) 51 | if !ok { 52 | return false 53 | } 54 | 55 | if len(p.vertices) != len(o.vertices) { 56 | return false 57 | } 58 | 59 | for i := range p.vertices { 60 | if !p.vertices[i].EqualsCoord(o.vertices[i]) { 61 | return false 62 | } 63 | } 64 | 65 | return true 66 | } 67 | 68 | func (p *Path) Register(op *Path) (offset Coord, match bool) { 69 | offset = p.bounds.Min.Minus(op.bounds.Min) 70 | if len(p.vertices) != len(op.vertices) { 71 | dbg("registure failure: wrong counts") 72 | return // with match = false 73 | } 74 | for i := range p.vertices { 75 | if !p.vertices[i].EqualsCoord(op.vertices[i].Plus(offset)) { 76 | dbg("register failure: v1=%v v2=%v offset=%v", p.vertices[i], op.vertices[i], offset) 77 | return // with match = false 78 | } 79 | } 80 | match = true 81 | return 82 | } 83 | 84 | func (p *Path) Length() int { 85 | return len(p.vertices) 86 | } 87 | 88 | func (p *Path) AddVertex(v Coord) { 89 | if len(p.vertices) == 0 { 90 | p.bounds = Rect{ 91 | Min: v, 92 | Max: v, 93 | } 94 | } else { 95 | p.bounds.ExpandToContainCoord(v) 96 | } 97 | p.vertices = append(p.vertices, v) 98 | } 99 | 100 | func (p *Path) InsertVertexAfter(v Coord, index int) { 101 | p.vertices = append(p.vertices, v) 102 | copy(p.vertices[index+1:], p.vertices[index:len(p.vertices)-1]) 103 | p.vertices[index] = v 104 | } 105 | 106 | func (p *Path) Bounds() (bounds *Rect) { 107 | return &p.bounds 108 | } 109 | 110 | func (p *Path) Vertices() (v []Coord) { 111 | v = p.vertices 112 | return 113 | } 114 | 115 | func (me *Path) Error(other *Path) (offset Coord, error float64) { 116 | 117 | meCenter := me.bounds.Center() 118 | oCenter := other.bounds.Center() 119 | 120 | offset = meCenter.Minus(oCenter) 121 | if len(me.vertices) != len(other.vertices) { 122 | error = math.Inf(1) 123 | return 124 | } 125 | 126 | for i, mv := range me.vertices { 127 | ov := other.vertices[i] 128 | offsetMe := mv.Minus(meCenter) 129 | offsetOther := ov.Minus(oCenter) 130 | error += offsetMe.DistanceFrom(offsetOther) 131 | } 132 | 133 | return 134 | } 135 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/coord.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | import ( 8 | "math" 9 | ) 10 | 11 | type Coord struct { 12 | X, Y float64 13 | } 14 | 15 | func (p *Coord) Hashcode() (hash uint64) { 16 | x, y := uint64(p.X), uint64(p.Y) 17 | hash = x + y 18 | return 19 | } 20 | 21 | func (p *Coord) Equals(oi interface{}) (equals bool) { 22 | o, equals := oi.(*Coord) 23 | if !equals { 24 | var op Coord 25 | op, equals = oi.(Coord) 26 | equals = equals && p.EqualsCoord(op) 27 | return 28 | } 29 | equals = p.EqualsCoord(*o) 30 | return 31 | } 32 | 33 | func (p *Coord) Translate(offset Coord) { 34 | *p = p.Plus(offset) 35 | } 36 | 37 | func (p *Coord) Rotate(rad float64) { 38 | p.X = p.X*math.Cos(rad) - p.Y*math.Sin(rad) 39 | p.Y = p.X*math.Sin(rad) + p.Y*math.Cos(rad) 40 | } 41 | 42 | func (p *Coord) RotateLeft() { 43 | p.X, p.Y = -p.Y, p.X 44 | } 45 | 46 | func (p *Coord) RotateRight() { 47 | p.X, p.Y = p.Y, -p.X 48 | } 49 | 50 | func (p Coord) Unit() (u Coord) { 51 | m := p.Magnitude() 52 | u.X = p.X / m 53 | u.Y = p.Y / m 54 | return 55 | } 56 | 57 | func (p *Coord) Scale(xfactor, yfactor float64) { 58 | p.X *= xfactor 59 | p.Y *= yfactor 60 | } 61 | 62 | func (p Coord) EqualsCoord(q Coord) bool { 63 | return p.X == q.X && p.Y == q.Y 64 | } 65 | 66 | func (p Coord) DistanceFrom(q Coord) (d float64) { 67 | return p.Minus(q).Magnitude() 68 | } 69 | 70 | func (p Coord) DistanceFromSquared(q Coord) (ds float64) { 71 | return p.Minus(q).MagnitudeSquared() 72 | } 73 | 74 | func (p Coord) Magnitude() (m float64) { 75 | m = math.Sqrt(p.MagnitudeSquared()) 76 | return 77 | } 78 | 79 | func (p Coord) MagnitudeSquared() (ms float64) { 80 | ms = p.X*p.X + p.Y*p.Y 81 | return 82 | } 83 | 84 | func (p Coord) Minus(q Coord) (r Coord) { 85 | r.X = p.X - q.X 86 | r.Y = p.Y - q.Y 87 | return 88 | } 89 | 90 | func (p Coord) Plus(q Coord) (r Coord) { 91 | r.X = p.X + q.X 92 | r.Y = p.Y + q.Y 93 | return 94 | } 95 | 96 | func (p Coord) Times(s float64) (r Coord) { 97 | r.X = p.X * s 98 | r.Y = p.Y * s 99 | return 100 | } 101 | 102 | func (p Coord) QuadPP(q Coord) bool { 103 | return q.X >= p.X && q.Y >= p.Y 104 | } 105 | 106 | func (p Coord) QuadPM(q Coord) bool { 107 | return q.X >= p.X && q.Y <= p.Y 108 | } 109 | 110 | func (p Coord) QuadMP(q Coord) bool { 111 | return q.X <= p.X && q.Y >= p.Y 112 | } 113 | 114 | func (p Coord) QuadMM(q Coord) bool { 115 | return q.X <= p.X && q.Y <= p.Y 116 | } 117 | 118 | func DotProduct(p, q Coord) (r float64) { 119 | r = p.X*q.X + p.Y*q.Y 120 | return 121 | } 122 | 123 | func CrossProduct(p, q Coord) (z float64) { 124 | z = p.X*q.Y - p.Y*q.X 125 | return 126 | } 127 | 128 | func VectorAngle(X, Y Coord) (r float64) { 129 | XdotY := DotProduct(X, Y) 130 | mXmY := X.Magnitude() * Y.Magnitude() 131 | r = math.Acos(XdotY / mXmY) 132 | z := CrossProduct(X, Y) 133 | if z < 0 { 134 | r *= -1 135 | } 136 | return 137 | } 138 | 139 | func VertexAngle(A, B, C Coord) (r float64) { 140 | X := A.Minus(B) 141 | Y := C.Minus(B) 142 | r = VectorAngle(X, Y) 143 | return 144 | } 145 | 146 | func CoordChan(points []Coord) (ch <-chan Coord) { 147 | tch := make(chan Coord, len(points)) 148 | go func(points []Coord, ch chan<- Coord) { 149 | for _, p := range points { 150 | ch <- p 151 | } 152 | close(ch) 153 | }(points, tch) 154 | ch = tch 155 | return 156 | } 157 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/convolution.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "image" 5 | ) 6 | 7 | // ConvolveOptions are convolution parameters. 8 | type ConvolveOptions struct { 9 | // If Normalize is true the kernel is normalized before convolution. 10 | Normalize bool 11 | 12 | // If Abs is true the absolute value of each color channel is taken after convolution. 13 | Abs bool 14 | 15 | // Bias is added to each color channel value after convolution. 16 | Bias int 17 | } 18 | 19 | // Convolve3x3 convolves the image with the specified 3x3 convolution kernel. 20 | // Default parameters are used if a nil *ConvolveOptions is passed. 21 | func Convolve3x3(img image.Image, kernel [9]float64, options *ConvolveOptions) *image.NRGBA { 22 | return convolve(img, kernel[:], options) 23 | } 24 | 25 | // Convolve5x5 convolves the image with the specified 5x5 convolution kernel. 26 | // Default parameters are used if a nil *ConvolveOptions is passed. 27 | func Convolve5x5(img image.Image, kernel [25]float64, options *ConvolveOptions) *image.NRGBA { 28 | return convolve(img, kernel[:], options) 29 | } 30 | 31 | func convolve(img image.Image, kernel []float64, options *ConvolveOptions) *image.NRGBA { 32 | src := toNRGBA(img) 33 | w := src.Bounds().Max.X 34 | h := src.Bounds().Max.Y 35 | dst := image.NewNRGBA(image.Rect(0, 0, w, h)) 36 | 37 | if w < 1 || h < 1 { 38 | return dst 39 | } 40 | 41 | if options == nil { 42 | options = &ConvolveOptions{} 43 | } 44 | 45 | if options.Normalize { 46 | normalizeKernel(kernel) 47 | } 48 | 49 | type coef struct { 50 | x, y int 51 | k float64 52 | } 53 | var coefs []coef 54 | var m int 55 | 56 | switch len(kernel) { 57 | case 9: 58 | m = 1 59 | case 25: 60 | m = 2 61 | } 62 | 63 | i := 0 64 | for y := -m; y <= m; y++ { 65 | for x := -m; x <= m; x++ { 66 | if kernel[i] != 0 { 67 | coefs = append(coefs, coef{x: x, y: y, k: kernel[i]}) 68 | } 69 | i++ 70 | } 71 | } 72 | 73 | parallel(0, h, func(ys <-chan int) { 74 | for y := range ys { 75 | for x := 0; x < w; x++ { 76 | var r, g, b float64 77 | for _, c := range coefs { 78 | ix := x + c.x 79 | if ix < 0 { 80 | ix = 0 81 | } else if ix >= w { 82 | ix = w - 1 83 | } 84 | 85 | iy := y + c.y 86 | if iy < 0 { 87 | iy = 0 88 | } else if iy >= h { 89 | iy = h - 1 90 | } 91 | 92 | off := iy*src.Stride + ix*4 93 | r += float64(src.Pix[off+0]) * c.k 94 | g += float64(src.Pix[off+1]) * c.k 95 | b += float64(src.Pix[off+2]) * c.k 96 | } 97 | 98 | if options.Abs { 99 | if r < 0 { 100 | r = -r 101 | } 102 | if g < 0 { 103 | g = -g 104 | } 105 | if b < 0 { 106 | b = -b 107 | } 108 | } 109 | 110 | if options.Bias != 0 { 111 | r += float64(options.Bias) 112 | g += float64(options.Bias) 113 | b += float64(options.Bias) 114 | } 115 | 116 | srcOff := y*src.Stride + x*4 117 | dstOff := y*dst.Stride + x*4 118 | dst.Pix[dstOff+0] = clamp(r) 119 | dst.Pix[dstOff+1] = clamp(g) 120 | dst.Pix[dstOff+2] = clamp(b) 121 | dst.Pix[dstOff+3] = src.Pix[srcOff+3] 122 | } 123 | } 124 | }) 125 | 126 | return dst 127 | } 128 | 129 | func normalizeKernel(kernel []float64) { 130 | var sum, sumpos float64 131 | for i := range kernel { 132 | sum += kernel[i] 133 | if kernel[i] > 0 { 134 | sumpos += kernel[i] 135 | } 136 | } 137 | if sum != 0 { 138 | for i := range kernel { 139 | kernel[i] /= sum 140 | } 141 | } else if sumpos != 0 { 142 | for i := range kernel { 143 | kernel[i] /= sumpos 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/node.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import ( 18 | "encoding/xml" 19 | "fmt" 20 | ) 21 | 22 | const ( 23 | SvgNs = "http://www.w3.org/2000/svg" 24 | ) 25 | 26 | type onMarshalAttrsFunc func(attr AttrMap) 27 | type onUnmarshalAttrsFunc func(attr AttrMap) error 28 | 29 | type Node interface { 30 | xml.Unmarshaler 31 | xml.Marshaler 32 | 33 | Name() string 34 | 35 | Attrs() AttrMap 36 | 37 | Children() *[]Node 38 | AddChild(n Node) 39 | 40 | GetText() string 41 | SetText(t string) 42 | } 43 | 44 | type nodeImpl struct { 45 | name string 46 | attrs AttrMap 47 | children []Node 48 | text string 49 | 50 | // onMarshalAddrs is called during marshalling with a copy of the Attrs that the can be modified before marshalling. 51 | onMarshalAttrs onMarshalAttrsFunc 52 | // onUmarshalAttrs is called during unmarshalling. The calling function can modify the Attrs as necessary and 53 | // changes will be stored with the node. 54 | onUnmarshalAttrs onUnmarshalAttrsFunc 55 | } 56 | 57 | var _ Node = (*nodeImpl)(nil) 58 | 59 | func (n *nodeImpl) Name() string { 60 | return n.name 61 | } 62 | 63 | func (n *nodeImpl) Attrs() AttrMap { 64 | if n.attrs == nil { 65 | n.attrs = AttrMap{} 66 | } 67 | return n.attrs 68 | } 69 | 70 | func (n *nodeImpl) Children() *[]Node { 71 | return &n.children 72 | } 73 | 74 | func (n *nodeImpl) AddChild(c Node) { 75 | n.children = append(n.children, c) 76 | } 77 | 78 | func (n *nodeImpl) GetText() string { 79 | return n.text 80 | } 81 | 82 | func (n *nodeImpl) SetText(t string) { 83 | n.text = t 84 | } 85 | 86 | func (n *nodeImpl) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 87 | var err error 88 | 89 | if start.Name.Space != SvgNs { 90 | return fmt.Errorf("parsing non-SVG element: %v", start.Name) 91 | } 92 | n.name = start.Name.Local 93 | n.attrs = makeAttrMap(start.Attr) 94 | 95 | if n.onUnmarshalAttrs != nil { 96 | err = n.onUnmarshalAttrs(n.attrs) 97 | if err != nil { 98 | return err 99 | } 100 | } 101 | 102 | n.children, n.text, err = readChildren(d, &start) 103 | return err 104 | } 105 | 106 | func (n *nodeImpl) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 107 | am := copyAttrMap(n.attrs) 108 | 109 | if n.onMarshalAttrs != nil { 110 | n.onMarshalAttrs(am) 111 | } 112 | 113 | se := MakeStartElement(n.name, am) 114 | 115 | // Do the namespace thing for the root. This is a total hack. 116 | if n.name == "svg" { 117 | se.Name.Space = SvgNs 118 | } 119 | 120 | err := e.EncodeToken(se) 121 | if err != nil { 122 | return err 123 | } 124 | 125 | if len(n.children) != 0 { 126 | for _, c := range n.children { 127 | err = e.Encode(c) 128 | if err != nil { 129 | return err 130 | } 131 | } 132 | } else if n.text != "" { 133 | tt := xml.CharData(n.text) 134 | err = e.EncodeToken(tt) 135 | if err != nil { 136 | return err 137 | } 138 | } 139 | 140 | err = e.EncodeToken(se.End()) 141 | if err != nil { 142 | return err 143 | } 144 | 145 | return nil 146 | } 147 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/tiff/consts.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | // A tiff image file contains one or more images. The metadata 8 | // of each image is contained in an Image File Directory (IFD), 9 | // which contains entries of 12 bytes each and is described 10 | // on page 14-16 of the specification. An IFD entry consists of 11 | // 12 | // - a tag, which describes the signification of the entry, 13 | // - the data type and length of the entry, 14 | // - the data itself or a pointer to it if it is more than 4 bytes. 15 | // 16 | // The presence of a length means that each IFD is effectively an array. 17 | 18 | const ( 19 | leHeader = "II\x2A\x00" // Header for little-endian files. 20 | beHeader = "MM\x00\x2A" // Header for big-endian files. 21 | 22 | ifdLen = 12 // Length of an IFD entry in bytes. 23 | ) 24 | 25 | // Data types (p. 14-16 of the spec). 26 | const ( 27 | dtByte = 1 28 | dtASCII = 2 29 | dtShort = 3 30 | dtLong = 4 31 | dtRational = 5 32 | ) 33 | 34 | // The length of one instance of each data type in bytes. 35 | var lengths = [...]uint32{0, 1, 1, 2, 4, 8} 36 | 37 | // Tags (see p. 28-41 of the spec). 38 | const ( 39 | tImageWidth = 256 40 | tImageLength = 257 41 | tBitsPerSample = 258 42 | tCompression = 259 43 | tPhotometricInterpretation = 262 44 | 45 | tStripOffsets = 273 46 | tSamplesPerPixel = 277 47 | tRowsPerStrip = 278 48 | tStripByteCounts = 279 49 | 50 | tTileWidth = 322 51 | tTileLength = 323 52 | tTileOffsets = 324 53 | tTileByteCounts = 325 54 | 55 | tXResolution = 282 56 | tYResolution = 283 57 | tResolutionUnit = 296 58 | 59 | tPredictor = 317 60 | tColorMap = 320 61 | tExtraSamples = 338 62 | tSampleFormat = 339 63 | ) 64 | 65 | // Compression types (defined in various places in the spec and supplements). 66 | const ( 67 | cNone = 1 68 | cCCITT = 2 69 | cG3 = 3 // Group 3 Fax. 70 | cG4 = 4 // Group 4 Fax. 71 | cLZW = 5 72 | cJPEGOld = 6 // Superseded by cJPEG. 73 | cJPEG = 7 74 | cDeflate = 8 // zlib compression. 75 | cPackBits = 32773 76 | cDeflateOld = 32946 // Superseded by cDeflate. 77 | ) 78 | 79 | // Photometric interpretation values (see p. 37 of the spec). 80 | const ( 81 | pWhiteIsZero = 0 82 | pBlackIsZero = 1 83 | pRGB = 2 84 | pPaletted = 3 85 | pTransMask = 4 // transparency mask 86 | pCMYK = 5 87 | pYCbCr = 6 88 | pCIELab = 8 89 | ) 90 | 91 | // Values for the tPredictor tag (page 64-65 of the spec). 92 | const ( 93 | prNone = 1 94 | prHorizontal = 2 95 | ) 96 | 97 | // Values for the tResolutionUnit tag (page 18). 98 | const ( 99 | resNone = 1 100 | resPerInch = 2 // Dots per inch. 101 | resPerCM = 3 // Dots per centimeter. 102 | ) 103 | 104 | // imageMode represents the mode of the image. 105 | type imageMode int 106 | 107 | const ( 108 | mBilevel imageMode = iota 109 | mPaletted 110 | mGray 111 | mGrayInvert 112 | mRGB 113 | mRGBA 114 | mNRGBA 115 | ) 116 | 117 | // CompressionType describes the type of compression used in Options. 118 | type CompressionType int 119 | 120 | const ( 121 | Uncompressed CompressionType = iota 122 | Deflate 123 | ) 124 | 125 | // specValue returns the compression type constant from the TIFF spec that 126 | // is equivalent to c. 127 | func (c CompressionType) specValue() uint32 { 128 | switch c { 129 | case Deflate: 130 | return cDeflate 131 | } 132 | return cNone 133 | } 134 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/rect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | import ( 8 | "fmt" 9 | "math" 10 | ) 11 | 12 | type Rect struct { 13 | Min, Max Coord 14 | } 15 | 16 | // this rect contains nothing 17 | func NilRect() (r Rect) { 18 | r.Min.X = math.Inf(1) 19 | r.Min.Y = math.Inf(1) 20 | r.Max.X = math.Inf(-1) 21 | r.Max.Y = math.Inf(-1) 22 | return 23 | } 24 | 25 | func (r Rect) Width() float64 { 26 | return r.Max.X - r.Min.X 27 | } 28 | 29 | func (r Rect) Height() float64 { 30 | return r.Max.Y - r.Min.Y 31 | } 32 | 33 | func (r Rect) Size() (w, h float64) { 34 | return r.Max.X - r.Min.X, r.Max.Y - r.Min.Y 35 | } 36 | 37 | func (r Rect) Center() (center Coord) { 38 | center.X = 0.5 * (r.Min.X + r.Max.X) 39 | center.Y = 0.5 * (r.Min.Y + r.Max.Y) 40 | return 41 | } 42 | 43 | func (r Rect) ContainsCoord(p Coord) bool { 44 | return r.Min.QuadPP(p) && r.Max.QuadMM(p) 45 | } 46 | 47 | func (r Rect) ContainsRect(o Rect) bool { 48 | return r.ContainsCoord(o.Min) && r.ContainsCoord(o.Max) 49 | } 50 | 51 | func (r *Rect) Translate(offset Coord) { 52 | r.Min = r.Min.Plus(offset) 53 | r.Max = r.Max.Plus(offset) 54 | } 55 | 56 | func (r *Rect) Scale(xf, yf float64) { 57 | r.Min.Scale(xf, yf) 58 | r.Max.Scale(xf, yf) 59 | if xf < 0 { 60 | r.Min.X, r.Max.X = r.Max.X, r.Min.X 61 | } 62 | if yf < 0 { 63 | r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y 64 | } 65 | } 66 | 67 | func (r *Rect) ExpandToContain(ch <-chan Coord) { 68 | for p := range ch { 69 | r.ExpandToContainCoord(p) 70 | } 71 | } 72 | 73 | func (r *Rect) ExpandToContainCoord(p Coord) { 74 | r.Min.X = minf(r.Min.X, p.X) 75 | r.Min.Y = minf(r.Min.Y, p.Y) 76 | r.Max.X = maxf(r.Max.X, p.X) 77 | r.Max.Y = maxf(r.Max.Y, p.Y) 78 | } 79 | 80 | func (r *Rect) ExpandToContainRect(q Rect) { 81 | r.ExpandToContainCoord(q.Min) 82 | r.ExpandToContainCoord(q.Max) 83 | } 84 | 85 | func (r Rect) Bounds() (bounds Rect) { 86 | bounds = r 87 | return 88 | } 89 | 90 | func (r Rect) Equals(oi interface{}) bool { 91 | or, ok := oi.(Rect) 92 | return ok && RectsEqual(r, or) 93 | } 94 | 95 | func RectsIntersect(r1, r2 Rect) bool { 96 | ov := func(min1, max1, min2, max2 float64) (overlap bool) { 97 | if min1 <= min2 && max1 >= min2 { 98 | return true 99 | } 100 | if min1 <= max2 && max1 >= max2 { 101 | return true 102 | } 103 | if min2 <= min1 && max2 >= min1 { 104 | return true 105 | } 106 | if min2 <= max1 && max2 >= max1 { 107 | return true 108 | } 109 | return false 110 | } 111 | dbg("RI(%v, %v)", r1, r2) 112 | xoverlap := ov(r1.Min.X, r1.Max.X, r2.Min.X, r2.Max.X) 113 | yoverlap := ov(r1.Min.Y, r1.Max.Y, r2.Min.Y, r2.Max.Y) 114 | dbg("%v %v", xoverlap, yoverlap) 115 | return xoverlap && yoverlap 116 | } 117 | 118 | func RectsIntersectStrict(r1, r2 Rect) bool { 119 | ov := func(min1, max1, min2, max2 float64) (overlap bool) { 120 | if min1 < min2 && max1 > min2 { 121 | return true 122 | } 123 | if min1 < max2 && max1 > max2 { 124 | return true 125 | } 126 | if min2 < min1 && max2 > min1 { 127 | return true 128 | } 129 | if min2 < max1 && max2 > max1 { 130 | return true 131 | } 132 | return false 133 | } 134 | dbg("RI(%v, %v)", r1, r2) 135 | xoverlap := ov(r1.Min.X, r1.Max.X, r2.Min.X, r2.Max.X) 136 | yoverlap := ov(r1.Min.Y, r1.Max.Y, r2.Min.Y, r2.Max.Y) 137 | dbg("%v %v", xoverlap, yoverlap) 138 | return xoverlap && yoverlap 139 | } 140 | 141 | func RectsIntersection(r1, r2 Rect) (ri Rect) { 142 | ri.Min.X = math.Max(r1.Min.X, r2.Min.X) 143 | ri.Min.Y = math.Max(r1.Min.Y, r2.Min.Y) 144 | ri.Max.X = math.Min(r1.Max.X, r2.Max.X) 145 | ri.Max.Y = math.Min(r1.Max.Y, r2.Max.Y) 146 | return 147 | } 148 | 149 | func RectsEqual(r1, r2 Rect) bool { 150 | if !r1.Min.EqualsCoord(r2.Min) { 151 | return false 152 | } 153 | if !r1.Max.EqualsCoord(r2.Max) { 154 | return false 155 | } 156 | return true 157 | } 158 | 159 | func (r Rect) String() string { 160 | return fmt.Sprintf("{%v %v}", r.Min, r.Max) 161 | } 162 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/serialize.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import ( 18 | "bytes" 19 | "encoding/xml" 20 | "fmt" 21 | "log" 22 | "strconv" 23 | ) 24 | 25 | func Unmarshal(data []byte) (*Root, error) { 26 | d := xml.NewDecoder(bytes.NewReader(data)) 27 | 28 | se, _, err := findNextStart(d, nil) 29 | if err != nil { 30 | return nil, err 31 | } 32 | if se == nil { 33 | return nil, fmt.Errorf("no root element found") 34 | } 35 | 36 | r := &Root{} 37 | err = r.UnmarshalXML(d, *se) 38 | if err != nil { 39 | return nil, err 40 | } 41 | return r, nil 42 | } 43 | 44 | func Marshal(r *Root, pretty bool) ([]byte, error) { 45 | var b bytes.Buffer 46 | 47 | b.WriteString("\n") 48 | //b.WriteString("\n") 49 | 50 | e := xml.NewEncoder(&b) 51 | if pretty { 52 | e.Indent("", " ") 53 | } 54 | 55 | e.Encode(r) 56 | 57 | return b.Bytes(), nil 58 | } 59 | 60 | // findNextStart searches the token stream for the next StartElement. nil is 61 | // returned if there is no NextElement. An error is returned if an unexpected 62 | // EndElement is found. All other data is ignored/dropped (including CharData). 63 | func findNextStart(d *xml.Decoder, se *xml.StartElement) (*xml.StartElement, string, error) { 64 | var chardata string 65 | for { 66 | t, err := d.Token() 67 | if err != nil { 68 | return nil, "", err 69 | } 70 | 71 | switch tt := t.(type) { 72 | case xml.StartElement: 73 | return &tt, chardata, nil 74 | case xml.EndElement: 75 | if se != nil && se.End() == tt { 76 | return nil, chardata, nil 77 | } 78 | return nil, "", fmt.Errorf("unexpected EndElement: %r", tt) 79 | case xml.CharData: 80 | chardata += string(tt) 81 | default: 82 | // Ignore other tokens 83 | break 84 | } 85 | } 86 | } 87 | 88 | // readChildren reads a set of SVG Nodes and returns an array 89 | func readChildren(d *xml.Decoder, se *xml.StartElement) ([]Node, string, error) { 90 | var children []Node 91 | var chardata string 92 | for { 93 | cse, cd, err := findNextStart(d, se) 94 | if err != nil { 95 | return nil, "", err 96 | } 97 | chardata += cd 98 | if cse == nil { 99 | return children, chardata, nil 100 | } 101 | child := CreateNodeFromName(cse.Name) 102 | err = child.UnmarshalXML(d, *cse) 103 | if err != nil { 104 | return nil, "", err 105 | } 106 | children = append(children, child) 107 | } 108 | } 109 | 110 | func MakeStartElement(name string, am AttrMap) xml.StartElement { 111 | return xml.StartElement{ 112 | // So XML Namespaces are totally broken in encoding/xml. Gah 113 | // Name: xml.Name{Space: SvgNs, Local: name}, 114 | Name: xml.Name{Local: name}, 115 | Attr: attrMapSlice(am), 116 | } 117 | } 118 | 119 | func makeAttrMap(attrs []xml.Attr) AttrMap { 120 | r := make(AttrMap) 121 | 122 | for _, a := range attrs { 123 | if len(a.Name.Space) != 0 { 124 | log.Printf("Namespaced attribute, dropping: %s", a.Name) 125 | } 126 | _, ok := r[a.Name.Local] 127 | if ok { 128 | log.Printf("Repeated attr: %s", a) 129 | } 130 | 131 | r[a.Name.Local] = a.Value 132 | } 133 | 134 | return r 135 | } 136 | 137 | func attrMapSlice(am AttrMap) []xml.Attr { 138 | r := make([]xml.Attr, 0, len(am)) 139 | for k, v := range am { 140 | a := xml.Attr{Name: xml.Name{Local: k}, Value: v} 141 | r = append(r, a) 142 | } 143 | return r 144 | } 145 | 146 | func copyAttrMap(am AttrMap) AttrMap { 147 | r := make(AttrMap, len(am)) 148 | for k, v := range am { 149 | r[k] = v 150 | } 151 | return r 152 | } 153 | 154 | func floatToString(f float64) string { 155 | return strconv.FormatFloat(f, 'g', 4, 64) 156 | } 157 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/geom/poly.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The geom Authors. All rights reserved. 2 | // Use of this source code is governed by a license that 3 | // can be found in the LICENSE file. 4 | 5 | package geom 6 | 7 | import ( 8 | "math" 9 | ) 10 | 11 | type Polygon struct { 12 | Path 13 | } 14 | 15 | func wrapIndex(index, length int) (i int) { 16 | i = index % length 17 | if i < 0 { 18 | i = length + i 19 | } 20 | return 21 | } 22 | 23 | func (p *Polygon) Clone() (op *Polygon) { 24 | op = &Polygon{*p.Path.Clone()} 25 | return 26 | } 27 | 28 | func (p *Polygon) Equals(oi interface{}) bool { 29 | o, ok := oi.(*Polygon) 30 | if !ok { 31 | return false 32 | } 33 | return (&p.Path).Equals(&o.Path) 34 | } 35 | 36 | func (p *Polygon) Register(op *Polygon) (offset Coord, match bool) { 37 | offset, match = p.Path.Register(&op.Path) 38 | return 39 | } 40 | 41 | func (me *Polygon) Vertex(index int) (v Coord) { 42 | v = me.vertices[wrapIndex(index, len(me.vertices))] 43 | return 44 | } 45 | 46 | func (me *Polygon) Segment(index int) (s *Segment) { 47 | s = &Segment{me.Vertex(index), me.Vertex(index + 1)} 48 | return 49 | } 50 | 51 | func (me *Polygon) VertexAngle(index int) (r float64) { 52 | a := me.Vertex(index - 1) 53 | b := me.Vertex(index) 54 | c := me.Vertex(index + 1) 55 | r = VertexAngle(a, b, c) 56 | return 57 | } 58 | 59 | func (me *Polygon) WindingOrder() (winding float64) { 60 | for i := 0; i < len(me.vertices); i++ { 61 | winding += me.VertexAngle(i) 62 | } 63 | return 64 | } 65 | 66 | func (me *Polygon) ContainsCoord(p Coord) bool { 67 | fakeSegment := &Segment{p, Coord{p.X, p.Y + 1}} 68 | 69 | above := 0 70 | for i := 0; i < me.Length(); i++ { 71 | s := me.Segment(i) 72 | uh, uv := s.IntersectParameters(fakeSegment) 73 | if uh < 0 || uh >= 1 { 74 | continue 75 | } 76 | if uv > 0 { 77 | above++ 78 | } 79 | } 80 | return above%2 == 1 81 | } 82 | 83 | //bisect a polygon by joining vertices i and j 84 | func (me *Polygon) Bisect(i, j int) (p1, p2 *Polygon) { 85 | i = wrapIndex(i, len(me.vertices)) 86 | j = wrapIndex(j, len(me.vertices)) 87 | 88 | //build the first one, starting at i and ending at j 89 | p1 = &Polygon{} 90 | for c := i; c != wrapIndex(j+1, len(me.vertices)); c = wrapIndex(c+1, len(me.vertices)) { 91 | p1.AddVertex(me.Vertex(c)) 92 | } 93 | 94 | //build the second one, starting at j and ending at i 95 | p2 = &Polygon{} 96 | for c := j; c != wrapIndex(i+1, len(me.vertices)); c = wrapIndex(c+1, len(me.vertices)) { 97 | p2.AddVertex(me.Vertex(c)) 98 | } 99 | 100 | return 101 | } 102 | 103 | func (me *Polygon) Error(other *Polygon) (offset Coord, error float64) { 104 | return me.Path.Error(&other.Path) 105 | } 106 | 107 | func (me *Polygon) Triangles() (tris []Triangle, ok bool) { 108 | dbg("%v.Triangles()", me) 109 | 110 | if me.Length() == 3 { 111 | dbg("already a triangle") 112 | tris = []Triangle{Triangle{me.Vertex(0), me.Vertex(1), me.Vertex(2)}} 113 | ok = true 114 | return 115 | } 116 | 117 | for i := 0; i < me.Length(); i++ { 118 | iv := me.Vertex(i) 119 | v2: 120 | for j := i + 2; j != wrapIndex(i-1, me.Length()); j = wrapIndex(j+1, me.Length()) { 121 | jv := me.Vertex(j) 122 | bisectingSegment := &Segment{iv, jv} 123 | dbg("bisectingSegment(%d, %d) = %v", i, j, bisectingSegment) 124 | 125 | //first check to see that it doesn't intersect any other segments 126 | for si := 0; si < me.Length(); si++ { 127 | s := me.Segment(si) 128 | u1, u2 := s.IntersectParameters(bisectingSegment) 129 | if math.IsNaN(u1) || math.IsNaN(u2) || (u1 > 0 && u1 < 1 && u2 > 0 && u2 < 1) { 130 | dbg(" Segment(%d, %d) %v\n%f %f", si, si+1, s, u1, u2) 131 | continue v2 132 | } else { 133 | dbg(" doesn't intersect %v: %f %f", s, u1, u2) 134 | } 135 | } 136 | 137 | //second check to see that it is in the interior of the polygon 138 | midCoord := bisectingSegment.Extrapolate(0.5) 139 | if !me.ContainsCoord(midCoord) { 140 | dbg(" poly contains %v", midCoord) 141 | continue v2 142 | } 143 | 144 | dbg(" Segment %v is good", bisectingSegment) 145 | 146 | p1, p2 := me.Bisect(i, j) 147 | t1, ok1 := p1.Triangles() 148 | t2, ok2 := p2.Triangles() 149 | tris = append(t1, t2...) 150 | ok = ok1 && ok2 151 | return 152 | } 153 | } 154 | 155 | dbg("failed with %v", me) 156 | //panic("couldn't find any valid bisecting segment") 157 | 158 | return 159 | } 160 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/effects.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "image" 5 | "math" 6 | ) 7 | 8 | func gaussianBlurKernel(x, sigma float64) float64 { 9 | return math.Exp(-(x*x)/(2*sigma*sigma)) / (sigma * math.Sqrt(2*math.Pi)) 10 | } 11 | 12 | // Blur produces a blurred version of the image using a Gaussian function. 13 | // Sigma parameter must be positive and indicates how much the image will be blurred. 14 | // 15 | // Usage example: 16 | // 17 | // dstImage := imaging.Blur(srcImage, 3.5) 18 | // 19 | func Blur(img image.Image, sigma float64) *image.NRGBA { 20 | if sigma <= 0 { 21 | return Clone(img) 22 | } 23 | 24 | radius := int(math.Ceil(sigma * 3.0)) 25 | kernel := make([]float64, radius+1) 26 | 27 | for i := 0; i <= radius; i++ { 28 | kernel[i] = gaussianBlurKernel(float64(i), sigma) 29 | } 30 | 31 | return blurVertical(blurHorizontal(img, kernel), kernel) 32 | } 33 | 34 | func blurHorizontal(img image.Image, kernel []float64) *image.NRGBA { 35 | src := newScanner(img) 36 | dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) 37 | radius := len(kernel) - 1 38 | 39 | parallel(0, src.h, func(ys <-chan int) { 40 | scanLine := make([]uint8, src.w*4) 41 | for y := range ys { 42 | src.scan(0, y, src.w, y+1, scanLine) 43 | for x := 0; x < src.w; x++ { 44 | min := x - radius 45 | if min < 0 { 46 | min = 0 47 | } 48 | max := x + radius 49 | if max > src.w-1 { 50 | max = src.w - 1 51 | } 52 | 53 | var r, g, b, a, wsum float64 54 | for ix := min; ix <= max; ix++ { 55 | i := ix * 4 56 | weight := kernel[absint(x-ix)] 57 | wsum += weight 58 | wa := float64(scanLine[i+3]) * weight 59 | r += float64(scanLine[i+0]) * wa 60 | g += float64(scanLine[i+1]) * wa 61 | b += float64(scanLine[i+2]) * wa 62 | a += wa 63 | } 64 | if a != 0 { 65 | r /= a 66 | g /= a 67 | b /= a 68 | } 69 | 70 | j := y*dst.Stride + x*4 71 | dst.Pix[j+0] = clamp(r) 72 | dst.Pix[j+1] = clamp(g) 73 | dst.Pix[j+2] = clamp(b) 74 | dst.Pix[j+3] = clamp(a / wsum) 75 | } 76 | } 77 | }) 78 | 79 | return dst 80 | } 81 | 82 | func blurVertical(img image.Image, kernel []float64) *image.NRGBA { 83 | src := newScanner(img) 84 | dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) 85 | radius := len(kernel) - 1 86 | 87 | parallel(0, src.w, func(xs <-chan int) { 88 | scanLine := make([]uint8, src.h*4) 89 | for x := range xs { 90 | src.scan(x, 0, x+1, src.h, scanLine) 91 | for y := 0; y < src.h; y++ { 92 | min := y - radius 93 | if min < 0 { 94 | min = 0 95 | } 96 | max := y + radius 97 | if max > src.h-1 { 98 | max = src.h - 1 99 | } 100 | 101 | var r, g, b, a, wsum float64 102 | for iy := min; iy <= max; iy++ { 103 | i := iy * 4 104 | weight := kernel[absint(y-iy)] 105 | wsum += weight 106 | wa := float64(scanLine[i+3]) * weight 107 | r += float64(scanLine[i+0]) * wa 108 | g += float64(scanLine[i+1]) * wa 109 | b += float64(scanLine[i+2]) * wa 110 | a += wa 111 | } 112 | if a != 0 { 113 | r /= a 114 | g /= a 115 | b /= a 116 | } 117 | 118 | j := y*dst.Stride + x*4 119 | dst.Pix[j+0] = clamp(r) 120 | dst.Pix[j+1] = clamp(g) 121 | dst.Pix[j+2] = clamp(b) 122 | dst.Pix[j+3] = clamp(a / wsum) 123 | } 124 | } 125 | }) 126 | 127 | return dst 128 | } 129 | 130 | // Sharpen produces a sharpened version of the image. 131 | // Sigma parameter must be positive and indicates how much the image will be sharpened. 132 | // 133 | // Usage example: 134 | // 135 | // dstImage := imaging.Sharpen(srcImage, 3.5) 136 | // 137 | func Sharpen(img image.Image, sigma float64) *image.NRGBA { 138 | if sigma <= 0 { 139 | return Clone(img) 140 | } 141 | 142 | src := newScanner(img) 143 | dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) 144 | blurred := Blur(img, sigma) 145 | 146 | parallel(0, src.h, func(ys <-chan int) { 147 | scanLine := make([]uint8, src.w*4) 148 | for y := range ys { 149 | src.scan(0, y, src.w, y+1, scanLine) 150 | j := y * dst.Stride 151 | for i := 0; i < src.w*4; i++ { 152 | val := int(scanLine[i])<<1 - int(blurred.Pix[j]) 153 | if val < 0 { 154 | val = 0 155 | } else if val > 0xff { 156 | val = 0xff 157 | } 158 | dst.Pix[j] = uint8(val) 159 | j++ 160 | } 161 | } 162 | }) 163 | 164 | return dst 165 | } 166 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/bmp/writer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package bmp 6 | 7 | import ( 8 | "encoding/binary" 9 | "errors" 10 | "image" 11 | "io" 12 | ) 13 | 14 | type header struct { 15 | sigBM [2]byte 16 | fileSize uint32 17 | resverved [2]uint16 18 | pixOffset uint32 19 | dibHeaderSize uint32 20 | width uint32 21 | height uint32 22 | colorPlane uint16 23 | bpp uint16 24 | compression uint32 25 | imageSize uint32 26 | xPixelsPerMeter uint32 27 | yPixelsPerMeter uint32 28 | colorUse uint32 29 | colorImportant uint32 30 | } 31 | 32 | func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error { 33 | var padding []byte 34 | if dx < step { 35 | padding = make([]byte, step-dx) 36 | } 37 | for y := dy - 1; y >= 0; y-- { 38 | min := y*stride + 0 39 | max := y*stride + dx 40 | if _, err := w.Write(pix[min:max]); err != nil { 41 | return err 42 | } 43 | if padding != nil { 44 | if _, err := w.Write(padding); err != nil { 45 | return err 46 | } 47 | } 48 | } 49 | return nil 50 | } 51 | 52 | func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int) error { 53 | buf := make([]byte, step) 54 | for y := dy - 1; y >= 0; y-- { 55 | min := y*stride + 0 56 | max := y*stride + dx*4 57 | off := 0 58 | for i := min; i < max; i += 4 { 59 | buf[off+2] = pix[i+0] 60 | buf[off+1] = pix[i+1] 61 | buf[off+0] = pix[i+2] 62 | off += 3 63 | } 64 | if _, err := w.Write(buf); err != nil { 65 | return err 66 | } 67 | } 68 | return nil 69 | } 70 | 71 | func encode(w io.Writer, m image.Image, step int) error { 72 | b := m.Bounds() 73 | buf := make([]byte, step) 74 | for y := b.Max.Y - 1; y >= b.Min.Y; y-- { 75 | off := 0 76 | for x := b.Min.X; x < b.Max.X; x++ { 77 | r, g, b, _ := m.At(x, y).RGBA() 78 | buf[off+2] = byte(r >> 8) 79 | buf[off+1] = byte(g >> 8) 80 | buf[off+0] = byte(b >> 8) 81 | off += 3 82 | } 83 | if _, err := w.Write(buf); err != nil { 84 | return err 85 | } 86 | } 87 | return nil 88 | } 89 | 90 | // Encode writes the image m to w in BMP format. 91 | func Encode(w io.Writer, m image.Image) error { 92 | d := m.Bounds().Size() 93 | if d.X < 0 || d.Y < 0 { 94 | return errors.New("bmp: negative bounds") 95 | } 96 | h := &header{ 97 | sigBM: [2]byte{'B', 'M'}, 98 | fileSize: 14 + 40, 99 | pixOffset: 14 + 40, 100 | dibHeaderSize: 40, 101 | width: uint32(d.X), 102 | height: uint32(d.Y), 103 | colorPlane: 1, 104 | } 105 | 106 | var step int 107 | var palette []byte 108 | switch m := m.(type) { 109 | case *image.Gray: 110 | step = (d.X + 3) &^ 3 111 | palette = make([]byte, 1024) 112 | for i := 0; i < 256; i++ { 113 | palette[i*4+0] = uint8(i) 114 | palette[i*4+1] = uint8(i) 115 | palette[i*4+2] = uint8(i) 116 | palette[i*4+3] = 0xFF 117 | } 118 | h.imageSize = uint32(d.Y * step) 119 | h.fileSize += uint32(len(palette)) + h.imageSize 120 | h.pixOffset += uint32(len(palette)) 121 | h.bpp = 8 122 | 123 | case *image.Paletted: 124 | step = (d.X + 3) &^ 3 125 | palette = make([]byte, 1024) 126 | for i := 0; i < len(m.Palette) && i < 256; i++ { 127 | r, g, b, _ := m.Palette[i].RGBA() 128 | palette[i*4+0] = uint8(b >> 8) 129 | palette[i*4+1] = uint8(g >> 8) 130 | palette[i*4+2] = uint8(r >> 8) 131 | palette[i*4+3] = 0xFF 132 | } 133 | h.imageSize = uint32(d.Y * step) 134 | h.fileSize += uint32(len(palette)) + h.imageSize 135 | h.pixOffset += uint32(len(palette)) 136 | h.bpp = 8 137 | default: 138 | step = (3*d.X + 3) &^ 3 139 | h.imageSize = uint32(d.Y * step) 140 | h.fileSize += h.imageSize 141 | h.bpp = 24 142 | } 143 | 144 | if err := binary.Write(w, binary.LittleEndian, h); err != nil { 145 | return err 146 | } 147 | if palette != nil { 148 | if err := binary.Write(w, binary.LittleEndian, palette); err != nil { 149 | return err 150 | } 151 | } 152 | 153 | if d.X == 0 || d.Y == 0 { 154 | return nil 155 | } 156 | 157 | switch m := m.(type) { 158 | case *image.Gray: 159 | return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step) 160 | case *image.Paletted: 161 | return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step) 162 | case *image.RGBA: 163 | return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step) 164 | } 165 | return encode(w, m, step) 166 | } 167 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/stack.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "path" 7 | "runtime" 8 | "strings" 9 | ) 10 | 11 | // Frame represents a program counter inside a stack frame. 12 | type Frame uintptr 13 | 14 | // pc returns the program counter for this frame; 15 | // multiple frames may have the same PC value. 16 | func (f Frame) pc() uintptr { return uintptr(f) - 1 } 17 | 18 | // file returns the full path to the file that contains the 19 | // function for this Frame's pc. 20 | func (f Frame) file() string { 21 | fn := runtime.FuncForPC(f.pc()) 22 | if fn == nil { 23 | return "unknown" 24 | } 25 | file, _ := fn.FileLine(f.pc()) 26 | return file 27 | } 28 | 29 | // line returns the line number of source code of the 30 | // function for this Frame's pc. 31 | func (f Frame) line() int { 32 | fn := runtime.FuncForPC(f.pc()) 33 | if fn == nil { 34 | return 0 35 | } 36 | _, line := fn.FileLine(f.pc()) 37 | return line 38 | } 39 | 40 | // Format formats the frame according to the fmt.Formatter interface. 41 | // 42 | // %s source file 43 | // %d source line 44 | // %n function name 45 | // %v equivalent to %s:%d 46 | // 47 | // Format accepts flags that alter the printing of some verbs, as follows: 48 | // 49 | // %+s path of source file relative to the compile time GOPATH 50 | // %+v equivalent to %+s:%d 51 | func (f Frame) Format(s fmt.State, verb rune) { 52 | switch verb { 53 | case 's': 54 | switch { 55 | case s.Flag('+'): 56 | pc := f.pc() 57 | fn := runtime.FuncForPC(pc) 58 | if fn == nil { 59 | io.WriteString(s, "unknown") 60 | } else { 61 | file, _ := fn.FileLine(pc) 62 | fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) 63 | } 64 | default: 65 | io.WriteString(s, path.Base(f.file())) 66 | } 67 | case 'd': 68 | fmt.Fprintf(s, "%d", f.line()) 69 | case 'n': 70 | name := runtime.FuncForPC(f.pc()).Name() 71 | io.WriteString(s, funcname(name)) 72 | case 'v': 73 | f.Format(s, 's') 74 | io.WriteString(s, ":") 75 | f.Format(s, 'd') 76 | } 77 | } 78 | 79 | // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). 80 | type StackTrace []Frame 81 | 82 | func (st StackTrace) Format(s fmt.State, verb rune) { 83 | switch verb { 84 | case 'v': 85 | switch { 86 | case s.Flag('+'): 87 | for _, f := range st { 88 | fmt.Fprintf(s, "\n%+v", f) 89 | } 90 | case s.Flag('#'): 91 | fmt.Fprintf(s, "%#v", []Frame(st)) 92 | default: 93 | fmt.Fprintf(s, "%v", []Frame(st)) 94 | } 95 | case 's': 96 | fmt.Fprintf(s, "%s", []Frame(st)) 97 | } 98 | } 99 | 100 | // stack represents a stack of program counters. 101 | type stack []uintptr 102 | 103 | func (s *stack) Format(st fmt.State, verb rune) { 104 | switch verb { 105 | case 'v': 106 | switch { 107 | case st.Flag('+'): 108 | for _, pc := range *s { 109 | f := Frame(pc) 110 | fmt.Fprintf(st, "\n%+v", f) 111 | } 112 | } 113 | } 114 | } 115 | 116 | func (s *stack) StackTrace() StackTrace { 117 | f := make([]Frame, len(*s)) 118 | for i := 0; i < len(f); i++ { 119 | f[i] = Frame((*s)[i]) 120 | } 121 | return f 122 | } 123 | 124 | func callers() *stack { 125 | const depth = 32 126 | var pcs [depth]uintptr 127 | n := runtime.Callers(3, pcs[:]) 128 | var st stack = pcs[0:n] 129 | return &st 130 | } 131 | 132 | // funcname removes the path prefix component of a function's name reported by func.Name(). 133 | func funcname(name string) string { 134 | i := strings.LastIndex(name, "/") 135 | name = name[i+1:] 136 | i = strings.Index(name, ".") 137 | return name[i+1:] 138 | } 139 | 140 | func trimGOPATH(name, file string) string { 141 | // Here we want to get the source file path relative to the compile time 142 | // GOPATH. As of Go 1.6.x there is no direct way to know the compiled 143 | // GOPATH at runtime, but we can infer the number of path segments in the 144 | // GOPATH. We note that fn.Name() returns the function name qualified by 145 | // the import path, which does not include the GOPATH. Thus we can trim 146 | // segments from the beginning of the file path until the number of path 147 | // separators remaining is one more than the number of path separators in 148 | // the function name. For example, given: 149 | // 150 | // GOPATH /home/user 151 | // file /home/user/src/pkg/sub/file.go 152 | // fn.Name() pkg/sub.Type.Method 153 | // 154 | // We want to produce: 155 | // 156 | // pkg/sub/file.go 157 | // 158 | // From this we can easily see that fn.Name() has one less path separator 159 | // than our desired output. We count separators from the end of the file 160 | // path until it finds two more than in the function name and then move 161 | // one character forward to preserve the initial path segment without a 162 | // leading separator. 163 | const sep = "/" 164 | goal := strings.Count(name, sep) + 2 165 | i := len(file) 166 | for n := 0; n < goal; n++ { 167 | i = strings.LastIndex(file[:i], sep) 168 | if i == -1 { 169 | // not enough separators found, set i so that the slice expression 170 | // below leaves file unmodified 171 | i = -len(sep) 172 | break 173 | } 174 | } 175 | // get back to 0 or trim the leading separator 176 | file = file[i+len(sep):] 177 | return file 178 | } 179 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/scanner.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | ) 7 | 8 | type scanner struct { 9 | image image.Image 10 | w, h int 11 | palette []color.NRGBA 12 | } 13 | 14 | func newScanner(img image.Image) *scanner { 15 | s := &scanner{ 16 | image: img, 17 | w: img.Bounds().Dx(), 18 | h: img.Bounds().Dy(), 19 | } 20 | if img, ok := img.(*image.Paletted); ok { 21 | s.palette = make([]color.NRGBA, len(img.Palette)) 22 | for i := 0; i < len(img.Palette); i++ { 23 | s.palette[i] = color.NRGBAModel.Convert(img.Palette[i]).(color.NRGBA) 24 | } 25 | } 26 | return s 27 | } 28 | 29 | // scan scans the given rectangular region of the image into dst. 30 | func (s *scanner) scan(x1, y1, x2, y2 int, dst []uint8) { 31 | switch img := s.image.(type) { 32 | case *image.NRGBA: 33 | size := (x2 - x1) * 4 34 | j := 0 35 | i := y1*img.Stride + x1*4 36 | for y := y1; y < y2; y++ { 37 | copy(dst[j:j+size], img.Pix[i:i+size]) 38 | j += size 39 | i += img.Stride 40 | } 41 | 42 | case *image.NRGBA64: 43 | j := 0 44 | for y := y1; y < y2; y++ { 45 | i := y*img.Stride + x1*8 46 | for x := x1; x < x2; x++ { 47 | dst[j+0] = img.Pix[i+0] 48 | dst[j+1] = img.Pix[i+2] 49 | dst[j+2] = img.Pix[i+4] 50 | dst[j+3] = img.Pix[i+6] 51 | j += 4 52 | i += 8 53 | } 54 | } 55 | 56 | case *image.RGBA: 57 | j := 0 58 | for y := y1; y < y2; y++ { 59 | i := y*img.Stride + x1*4 60 | for x := x1; x < x2; x++ { 61 | a := img.Pix[i+3] 62 | switch a { 63 | case 0: 64 | dst[j+0] = 0 65 | dst[j+1] = 0 66 | dst[j+2] = 0 67 | case 0xff: 68 | dst[j+0] = img.Pix[i+0] 69 | dst[j+1] = img.Pix[i+1] 70 | dst[j+2] = img.Pix[i+2] 71 | default: 72 | r16 := uint16(img.Pix[i+0]) 73 | g16 := uint16(img.Pix[i+1]) 74 | b16 := uint16(img.Pix[i+2]) 75 | a16 := uint16(a) 76 | dst[j+0] = uint8(r16 * 0xff / a16) 77 | dst[j+1] = uint8(g16 * 0xff / a16) 78 | dst[j+2] = uint8(b16 * 0xff / a16) 79 | } 80 | dst[j+3] = a 81 | j += 4 82 | i += 4 83 | } 84 | } 85 | 86 | case *image.RGBA64: 87 | j := 0 88 | for y := y1; y < y2; y++ { 89 | i := y*img.Stride + x1*8 90 | for x := x1; x < x2; x++ { 91 | a := img.Pix[i+6] 92 | switch a { 93 | case 0: 94 | dst[j+0] = 0 95 | dst[j+1] = 0 96 | dst[j+2] = 0 97 | case 0xff: 98 | dst[j+0] = img.Pix[i+0] 99 | dst[j+1] = img.Pix[i+2] 100 | dst[j+2] = img.Pix[i+4] 101 | default: 102 | r32 := uint32(img.Pix[i+0])<<8 | uint32(img.Pix[i+1]) 103 | g32 := uint32(img.Pix[i+2])<<8 | uint32(img.Pix[i+3]) 104 | b32 := uint32(img.Pix[i+4])<<8 | uint32(img.Pix[i+5]) 105 | a32 := uint32(img.Pix[i+6])<<8 | uint32(img.Pix[i+7]) 106 | dst[j+0] = uint8((r32 * 0xffff / a32) >> 8) 107 | dst[j+1] = uint8((g32 * 0xffff / a32) >> 8) 108 | dst[j+2] = uint8((b32 * 0xffff / a32) >> 8) 109 | } 110 | dst[j+3] = a 111 | j += 4 112 | i += 8 113 | } 114 | } 115 | 116 | case *image.Gray: 117 | j := 0 118 | for y := y1; y < y2; y++ { 119 | i := y*img.Stride + x1 120 | for x := x1; x < x2; x++ { 121 | c := img.Pix[i] 122 | dst[j+0] = c 123 | dst[j+1] = c 124 | dst[j+2] = c 125 | dst[j+3] = 0xff 126 | j += 4 127 | i++ 128 | } 129 | } 130 | 131 | case *image.Gray16: 132 | j := 0 133 | for y := y1; y < y2; y++ { 134 | i := y*img.Stride + x1*2 135 | for x := x1; x < x2; x++ { 136 | c := img.Pix[i] 137 | dst[j+0] = c 138 | dst[j+1] = c 139 | dst[j+2] = c 140 | dst[j+3] = 0xff 141 | j += 4 142 | i += 2 143 | } 144 | } 145 | 146 | case *image.YCbCr: 147 | j := 0 148 | x1 += img.Rect.Min.X 149 | x2 += img.Rect.Min.X 150 | y1 += img.Rect.Min.Y 151 | y2 += img.Rect.Min.Y 152 | for y := y1; y < y2; y++ { 153 | iy := (y-img.Rect.Min.Y)*img.YStride + (x1 - img.Rect.Min.X) 154 | for x := x1; x < x2; x++ { 155 | var ic int 156 | switch img.SubsampleRatio { 157 | case image.YCbCrSubsampleRatio444: 158 | ic = (y-img.Rect.Min.Y)*img.CStride + (x - img.Rect.Min.X) 159 | case image.YCbCrSubsampleRatio422: 160 | ic = (y-img.Rect.Min.Y)*img.CStride + (x/2 - img.Rect.Min.X/2) 161 | case image.YCbCrSubsampleRatio420: 162 | ic = (y/2-img.Rect.Min.Y/2)*img.CStride + (x/2 - img.Rect.Min.X/2) 163 | case image.YCbCrSubsampleRatio440: 164 | ic = (y/2-img.Rect.Min.Y/2)*img.CStride + (x - img.Rect.Min.X) 165 | default: 166 | ic = img.COffset(x, y) 167 | } 168 | 169 | yy := int(img.Y[iy]) 170 | cb := int(img.Cb[ic]) - 128 171 | cr := int(img.Cr[ic]) - 128 172 | 173 | r := (yy<<16 + 91881*cr + 1<<15) >> 16 174 | if r > 0xff { 175 | r = 0xff 176 | } else if r < 0 { 177 | r = 0 178 | } 179 | 180 | g := (yy<<16 - 22554*cb - 46802*cr + 1<<15) >> 16 181 | if g > 0xff { 182 | g = 0xff 183 | } else if g < 0 { 184 | g = 0 185 | } 186 | 187 | b := (yy<<16 + 116130*cb + 1<<15) >> 16 188 | if b > 0xff { 189 | b = 0xff 190 | } else if b < 0 { 191 | b = 0 192 | } 193 | 194 | dst[j+0] = uint8(r) 195 | dst[j+1] = uint8(g) 196 | dst[j+2] = uint8(b) 197 | dst[j+3] = 0xff 198 | 199 | iy++ 200 | j += 4 201 | } 202 | } 203 | 204 | case *image.Paletted: 205 | j := 0 206 | for y := y1; y < y2; y++ { 207 | i := y*img.Stride + x1 208 | for x := x1; x < x2; x++ { 209 | c := s.palette[img.Pix[i]] 210 | dst[j+0] = c.R 211 | dst[j+1] = c.G 212 | dst[j+2] = c.B 213 | dst[j+3] = c.A 214 | j += 4 215 | i++ 216 | } 217 | } 218 | 219 | default: 220 | j := 0 221 | b := s.image.Bounds() 222 | x1 += b.Min.X 223 | x2 += b.Min.X 224 | y1 += b.Min.Y 225 | y2 += b.Min.Y 226 | for y := y1; y < y2; y++ { 227 | for x := x1; x < x2; x++ { 228 | r16, g16, b16, a16 := s.image.At(x, y).RGBA() 229 | switch a16 { 230 | case 0xffff: 231 | dst[j+0] = uint8(r16 >> 8) 232 | dst[j+1] = uint8(g16 >> 8) 233 | dst[j+2] = uint8(b16 >> 8) 234 | dst[j+3] = 0xff 235 | case 0: 236 | dst[j+0] = 0 237 | dst[j+1] = 0 238 | dst[j+2] = 0 239 | dst[j+3] = 0 240 | default: 241 | dst[j+0] = uint8(((r16 * 0xffff) / a16) >> 8) 242 | dst[j+1] = uint8(((g16 * 0xffff) / a16) >> 8) 243 | dst[j+2] = uint8(((b16 * 0xffff) / a16) >> 8) 244 | dst[j+3] = uint8(a16 >> 8) 245 | } 246 | j += 4 247 | } 248 | } 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/bmp/reader.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package bmp implements a BMP image decoder and encoder. 6 | // 7 | // The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html. 8 | package bmp // import "golang.org/x/image/bmp" 9 | 10 | import ( 11 | "errors" 12 | "image" 13 | "image/color" 14 | "io" 15 | ) 16 | 17 | // ErrUnsupported means that the input BMP image uses a valid but unsupported 18 | // feature. 19 | var ErrUnsupported = errors.New("bmp: unsupported BMP image") 20 | 21 | func readUint16(b []byte) uint16 { 22 | return uint16(b[0]) | uint16(b[1])<<8 23 | } 24 | 25 | func readUint32(b []byte) uint32 { 26 | return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 27 | } 28 | 29 | // decodePaletted reads an 8 bit-per-pixel BMP image from r. 30 | // If topDown is false, the image rows will be read bottom-up. 31 | func decodePaletted(r io.Reader, c image.Config, topDown bool) (image.Image, error) { 32 | paletted := image.NewPaletted(image.Rect(0, 0, c.Width, c.Height), c.ColorModel.(color.Palette)) 33 | if c.Width == 0 || c.Height == 0 { 34 | return paletted, nil 35 | } 36 | var tmp [4]byte 37 | y0, y1, yDelta := c.Height-1, -1, -1 38 | if topDown { 39 | y0, y1, yDelta = 0, c.Height, +1 40 | } 41 | for y := y0; y != y1; y += yDelta { 42 | p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width] 43 | if _, err := io.ReadFull(r, p); err != nil { 44 | return nil, err 45 | } 46 | // Each row is 4-byte aligned. 47 | if c.Width%4 != 0 { 48 | _, err := io.ReadFull(r, tmp[:4-c.Width%4]) 49 | if err != nil { 50 | return nil, err 51 | } 52 | } 53 | } 54 | return paletted, nil 55 | } 56 | 57 | // decodeRGB reads a 24 bit-per-pixel BMP image from r. 58 | // If topDown is false, the image rows will be read bottom-up. 59 | func decodeRGB(r io.Reader, c image.Config, topDown bool) (image.Image, error) { 60 | rgba := image.NewRGBA(image.Rect(0, 0, c.Width, c.Height)) 61 | if c.Width == 0 || c.Height == 0 { 62 | return rgba, nil 63 | } 64 | // There are 3 bytes per pixel, and each row is 4-byte aligned. 65 | b := make([]byte, (3*c.Width+3)&^3) 66 | y0, y1, yDelta := c.Height-1, -1, -1 67 | if topDown { 68 | y0, y1, yDelta = 0, c.Height, +1 69 | } 70 | for y := y0; y != y1; y += yDelta { 71 | if _, err := io.ReadFull(r, b); err != nil { 72 | return nil, err 73 | } 74 | p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4] 75 | for i, j := 0, 0; i < len(p); i, j = i+4, j+3 { 76 | // BMP images are stored in BGR order rather than RGB order. 77 | p[i+0] = b[j+2] 78 | p[i+1] = b[j+1] 79 | p[i+2] = b[j+0] 80 | p[i+3] = 0xFF 81 | } 82 | } 83 | return rgba, nil 84 | } 85 | 86 | // decodeNRGBA reads a 32 bit-per-pixel BMP image from r. 87 | // If topDown is false, the image rows will be read bottom-up. 88 | func decodeNRGBA(r io.Reader, c image.Config, topDown bool) (image.Image, error) { 89 | rgba := image.NewNRGBA(image.Rect(0, 0, c.Width, c.Height)) 90 | if c.Width == 0 || c.Height == 0 { 91 | return rgba, nil 92 | } 93 | y0, y1, yDelta := c.Height-1, -1, -1 94 | if topDown { 95 | y0, y1, yDelta = 0, c.Height, +1 96 | } 97 | for y := y0; y != y1; y += yDelta { 98 | p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4] 99 | if _, err := io.ReadFull(r, p); err != nil { 100 | return nil, err 101 | } 102 | for i := 0; i < len(p); i += 4 { 103 | // BMP images are stored in BGRA order rather than RGBA order. 104 | p[i+0], p[i+2] = p[i+2], p[i+0] 105 | } 106 | } 107 | return rgba, nil 108 | } 109 | 110 | // Decode reads a BMP image from r and returns it as an image.Image. 111 | // Limitation: The file must be 8, 24 or 32 bits per pixel. 112 | func Decode(r io.Reader) (image.Image, error) { 113 | c, bpp, topDown, err := decodeConfig(r) 114 | if err != nil { 115 | return nil, err 116 | } 117 | switch bpp { 118 | case 8: 119 | return decodePaletted(r, c, topDown) 120 | case 24: 121 | return decodeRGB(r, c, topDown) 122 | case 32: 123 | return decodeNRGBA(r, c, topDown) 124 | } 125 | panic("unreachable") 126 | } 127 | 128 | // DecodeConfig returns the color model and dimensions of a BMP image without 129 | // decoding the entire image. 130 | // Limitation: The file must be 8, 24 or 32 bits per pixel. 131 | func DecodeConfig(r io.Reader) (image.Config, error) { 132 | config, _, _, err := decodeConfig(r) 133 | return config, err 134 | } 135 | 136 | func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown bool, err error) { 137 | // We only support those BMP images that are a BITMAPFILEHEADER 138 | // immediately followed by a BITMAPINFOHEADER. 139 | const ( 140 | fileHeaderLen = 14 141 | infoHeaderLen = 40 142 | ) 143 | var b [1024]byte 144 | if _, err := io.ReadFull(r, b[:fileHeaderLen+infoHeaderLen]); err != nil { 145 | return image.Config{}, 0, false, err 146 | } 147 | if string(b[:2]) != "BM" { 148 | return image.Config{}, 0, false, errors.New("bmp: invalid format") 149 | } 150 | offset := readUint32(b[10:14]) 151 | if readUint32(b[14:18]) != infoHeaderLen { 152 | return image.Config{}, 0, false, ErrUnsupported 153 | } 154 | width := int(int32(readUint32(b[18:22]))) 155 | height := int(int32(readUint32(b[22:26]))) 156 | if height < 0 { 157 | height, topDown = -height, true 158 | } 159 | if width < 0 || height < 0 { 160 | return image.Config{}, 0, false, ErrUnsupported 161 | } 162 | // We only support 1 plane, 8 or 24 bits per pixel and no compression. 163 | planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34]) 164 | if planes != 1 || compression != 0 { 165 | return image.Config{}, 0, false, ErrUnsupported 166 | } 167 | switch bpp { 168 | case 8: 169 | if offset != fileHeaderLen+infoHeaderLen+256*4 { 170 | return image.Config{}, 0, false, ErrUnsupported 171 | } 172 | _, err = io.ReadFull(r, b[:256*4]) 173 | if err != nil { 174 | return image.Config{}, 0, false, err 175 | } 176 | pcm := make(color.Palette, 256) 177 | for i := range pcm { 178 | // BMP images are stored in BGR order rather than RGB order. 179 | // Every 4th byte is padding. 180 | pcm[i] = color.RGBA{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF} 181 | } 182 | return image.Config{ColorModel: pcm, Width: width, Height: height}, 8, topDown, nil 183 | case 24: 184 | if offset != fileHeaderLen+infoHeaderLen { 185 | return image.Config{}, 0, false, ErrUnsupported 186 | } 187 | return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, nil 188 | case 32: 189 | if offset != fileHeaderLen+infoHeaderLen { 190 | return image.Config{}, 0, false, ErrUnsupported 191 | } 192 | return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, nil 193 | } 194 | return image.Config{}, 0, false, ErrUnsupported 195 | } 196 | 197 | func init() { 198 | image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig) 199 | } 200 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/tools.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "image" 5 | "math" 6 | ) 7 | 8 | // Anchor is the anchor point for image alignment. 9 | type Anchor int 10 | 11 | // Anchor point positions. 12 | const ( 13 | Center Anchor = iota 14 | TopLeft 15 | Top 16 | TopRight 17 | Left 18 | Right 19 | BottomLeft 20 | Bottom 21 | BottomRight 22 | ) 23 | 24 | func anchorPt(b image.Rectangle, w, h int, anchor Anchor) image.Point { 25 | var x, y int 26 | switch anchor { 27 | case TopLeft: 28 | x = b.Min.X 29 | y = b.Min.Y 30 | case Top: 31 | x = b.Min.X + (b.Dx()-w)/2 32 | y = b.Min.Y 33 | case TopRight: 34 | x = b.Max.X - w 35 | y = b.Min.Y 36 | case Left: 37 | x = b.Min.X 38 | y = b.Min.Y + (b.Dy()-h)/2 39 | case Right: 40 | x = b.Max.X - w 41 | y = b.Min.Y + (b.Dy()-h)/2 42 | case BottomLeft: 43 | x = b.Min.X 44 | y = b.Max.Y - h 45 | case Bottom: 46 | x = b.Min.X + (b.Dx()-w)/2 47 | y = b.Max.Y - h 48 | case BottomRight: 49 | x = b.Max.X - w 50 | y = b.Max.Y - h 51 | default: 52 | x = b.Min.X + (b.Dx()-w)/2 53 | y = b.Min.Y + (b.Dy()-h)/2 54 | } 55 | return image.Pt(x, y) 56 | } 57 | 58 | // Crop cuts out a rectangular region with the specified bounds 59 | // from the image and returns the cropped image. 60 | func Crop(img image.Image, rect image.Rectangle) *image.NRGBA { 61 | r := rect.Intersect(img.Bounds()).Sub(img.Bounds().Min) 62 | if r.Empty() { 63 | return &image.NRGBA{} 64 | } 65 | src := newScanner(img) 66 | dst := image.NewNRGBA(image.Rect(0, 0, r.Dx(), r.Dy())) 67 | rowSize := r.Dx() * 4 68 | parallel(r.Min.Y, r.Max.Y, func(ys <-chan int) { 69 | for y := range ys { 70 | i := (y - r.Min.Y) * dst.Stride 71 | src.scan(r.Min.X, y, r.Max.X, y+1, dst.Pix[i:i+rowSize]) 72 | } 73 | }) 74 | return dst 75 | } 76 | 77 | // CropAnchor cuts out a rectangular region with the specified size 78 | // from the image using the specified anchor point and returns the cropped image. 79 | func CropAnchor(img image.Image, width, height int, anchor Anchor) *image.NRGBA { 80 | srcBounds := img.Bounds() 81 | pt := anchorPt(srcBounds, width, height, anchor) 82 | r := image.Rect(0, 0, width, height).Add(pt) 83 | b := srcBounds.Intersect(r) 84 | return Crop(img, b) 85 | } 86 | 87 | // CropCenter cuts out a rectangular region with the specified size 88 | // from the center of the image and returns the cropped image. 89 | func CropCenter(img image.Image, width, height int) *image.NRGBA { 90 | return CropAnchor(img, width, height, Center) 91 | } 92 | 93 | // Paste pastes the img image to the background image at the specified position and returns the combined image. 94 | func Paste(background, img image.Image, pos image.Point) *image.NRGBA { 95 | dst := Clone(background) 96 | pos = pos.Sub(background.Bounds().Min) 97 | pasteRect := image.Rectangle{Min: pos, Max: pos.Add(img.Bounds().Size())} 98 | interRect := pasteRect.Intersect(dst.Bounds()) 99 | if interRect.Empty() { 100 | return dst 101 | } 102 | src := newScanner(img) 103 | parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) { 104 | for y := range ys { 105 | x1 := interRect.Min.X - pasteRect.Min.X 106 | x2 := interRect.Max.X - pasteRect.Min.X 107 | y1 := y - pasteRect.Min.Y 108 | y2 := y1 + 1 109 | i1 := y*dst.Stride + interRect.Min.X*4 110 | i2 := i1 + interRect.Dx()*4 111 | src.scan(x1, y1, x2, y2, dst.Pix[i1:i2]) 112 | } 113 | }) 114 | return dst 115 | } 116 | 117 | // PasteCenter pastes the img image to the center of the background image and returns the combined image. 118 | func PasteCenter(background, img image.Image) *image.NRGBA { 119 | bgBounds := background.Bounds() 120 | bgW := bgBounds.Dx() 121 | bgH := bgBounds.Dy() 122 | bgMinX := bgBounds.Min.X 123 | bgMinY := bgBounds.Min.Y 124 | 125 | centerX := bgMinX + bgW/2 126 | centerY := bgMinY + bgH/2 127 | 128 | x0 := centerX - img.Bounds().Dx()/2 129 | y0 := centerY - img.Bounds().Dy()/2 130 | 131 | return Paste(background, img, image.Pt(x0, y0)) 132 | } 133 | 134 | // Overlay draws the img image over the background image at given position 135 | // and returns the combined image. Opacity parameter is the opacity of the img 136 | // image layer, used to compose the images, it must be from 0.0 to 1.0. 137 | // 138 | // Usage examples: 139 | // 140 | // // Draw spriteImage over backgroundImage at the given position (x=50, y=50). 141 | // dstImage := imaging.Overlay(backgroundImage, spriteImage, image.Pt(50, 50), 1.0) 142 | // 143 | // // Blend two opaque images of the same size. 144 | // dstImage := imaging.Overlay(imageOne, imageTwo, image.Pt(0, 0), 0.5) 145 | // 146 | func Overlay(background, img image.Image, pos image.Point, opacity float64) *image.NRGBA { 147 | opacity = math.Min(math.Max(opacity, 0.0), 1.0) // Ensure 0.0 <= opacity <= 1.0. 148 | dst := Clone(background) 149 | pos = pos.Sub(background.Bounds().Min) 150 | pasteRect := image.Rectangle{Min: pos, Max: pos.Add(img.Bounds().Size())} 151 | interRect := pasteRect.Intersect(dst.Bounds()) 152 | if interRect.Empty() { 153 | return dst 154 | } 155 | src := newScanner(img) 156 | parallel(interRect.Min.Y, interRect.Max.Y, func(ys <-chan int) { 157 | scanLine := make([]uint8, interRect.Dx()*4) 158 | for y := range ys { 159 | x1 := interRect.Min.X - pasteRect.Min.X 160 | x2 := interRect.Max.X - pasteRect.Min.X 161 | y1 := y - pasteRect.Min.Y 162 | y2 := y1 + 1 163 | src.scan(x1, y1, x2, y2, scanLine) 164 | i := y*dst.Stride + interRect.Min.X*4 165 | j := 0 166 | for x := interRect.Min.X; x < interRect.Max.X; x++ { 167 | r1 := float64(dst.Pix[i+0]) 168 | g1 := float64(dst.Pix[i+1]) 169 | b1 := float64(dst.Pix[i+2]) 170 | a1 := float64(dst.Pix[i+3]) 171 | 172 | r2 := float64(scanLine[j+0]) 173 | g2 := float64(scanLine[j+1]) 174 | b2 := float64(scanLine[j+2]) 175 | a2 := float64(scanLine[j+3]) 176 | 177 | coef2 := opacity * a2 / 255 178 | coef1 := (1 - coef2) * a1 / 255 179 | coefSum := coef1 + coef2 180 | coef1 /= coefSum 181 | coef2 /= coefSum 182 | 183 | dst.Pix[i+0] = uint8(r1*coef1 + r2*coef2) 184 | dst.Pix[i+1] = uint8(g1*coef1 + g2*coef2) 185 | dst.Pix[i+2] = uint8(b1*coef1 + b2*coef2) 186 | dst.Pix[i+3] = uint8(math.Min(a1+a2*opacity*(255-a1)/255, 255)) 187 | 188 | i += 4 189 | j += 4 190 | } 191 | } 192 | }) 193 | return dst 194 | } 195 | 196 | // OverlayCenter overlays the img image to the center of the background image and 197 | // returns the combined image. Opacity parameter is the opacity of the img 198 | // image layer, used to compose the images, it must be from 0.0 to 1.0. 199 | func OverlayCenter(background, img image.Image, opacity float64) *image.NRGBA { 200 | bgBounds := background.Bounds() 201 | bgW := bgBounds.Dx() 202 | bgH := bgBounds.Dy() 203 | bgMinX := bgBounds.Min.X 204 | bgMinY := bgBounds.Min.Y 205 | 206 | centerX := bgMinX + bgW/2 207 | centerY := bgMinY + bgH/2 208 | 209 | x0 := centerX - img.Bounds().Dx()/2 210 | y0 := centerY - img.Bounds().Dy()/2 211 | 212 | return Overlay(background, img, image.Point{x0, y0}, opacity) 213 | } 214 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/adjust.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | "math" 7 | ) 8 | 9 | // Grayscale produces a grayscale version of the image. 10 | func Grayscale(img image.Image) *image.NRGBA { 11 | src := newScanner(img) 12 | dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) 13 | parallel(0, src.h, func(ys <-chan int) { 14 | for y := range ys { 15 | i := y * dst.Stride 16 | src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) 17 | for x := 0; x < src.w; x++ { 18 | r := dst.Pix[i+0] 19 | g := dst.Pix[i+1] 20 | b := dst.Pix[i+2] 21 | f := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b) 22 | y := uint8(f + 0.5) 23 | dst.Pix[i+0] = y 24 | dst.Pix[i+1] = y 25 | dst.Pix[i+2] = y 26 | i += 4 27 | } 28 | } 29 | }) 30 | return dst 31 | } 32 | 33 | // Invert produces an inverted (negated) version of the image. 34 | func Invert(img image.Image) *image.NRGBA { 35 | src := newScanner(img) 36 | dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) 37 | parallel(0, src.h, func(ys <-chan int) { 38 | for y := range ys { 39 | i := y * dst.Stride 40 | src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) 41 | for x := 0; x < src.w; x++ { 42 | dst.Pix[i+0] = 255 - dst.Pix[i+0] 43 | dst.Pix[i+1] = 255 - dst.Pix[i+1] 44 | dst.Pix[i+2] = 255 - dst.Pix[i+2] 45 | i += 4 46 | } 47 | } 48 | }) 49 | return dst 50 | } 51 | 52 | // AdjustContrast changes the contrast of the image using the percentage parameter and returns the adjusted image. 53 | // The percentage must be in range (-100, 100). The percentage = 0 gives the original image. 54 | // The percentage = -100 gives solid gray image. 55 | // 56 | // Examples: 57 | // 58 | // dstImage = imaging.AdjustContrast(srcImage, -10) // decrease image contrast by 10% 59 | // dstImage = imaging.AdjustContrast(srcImage, 20) // increase image contrast by 20% 60 | // 61 | func AdjustContrast(img image.Image, percentage float64) *image.NRGBA { 62 | percentage = math.Min(math.Max(percentage, -100.0), 100.0) 63 | lut := make([]uint8, 256) 64 | 65 | v := (100.0 + percentage) / 100.0 66 | for i := 0; i < 256; i++ { 67 | if 0 <= v && v <= 1 { 68 | lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*v) * 255.0) 69 | } else if 1 < v && v < 2 { 70 | lut[i] = clamp((0.5 + (float64(i)/255.0-0.5)*(1/(2.0-v))) * 255.0) 71 | } else { 72 | lut[i] = uint8(float64(i)/255.0+0.5) * 255 73 | } 74 | } 75 | 76 | return adjustLUT(img, lut) 77 | } 78 | 79 | // AdjustBrightness changes the brightness of the image using the percentage parameter and returns the adjusted image. 80 | // The percentage must be in range (-100, 100). The percentage = 0 gives the original image. 81 | // The percentage = -100 gives solid black image. The percentage = 100 gives solid white image. 82 | // 83 | // Examples: 84 | // 85 | // dstImage = imaging.AdjustBrightness(srcImage, -15) // decrease image brightness by 15% 86 | // dstImage = imaging.AdjustBrightness(srcImage, 10) // increase image brightness by 10% 87 | // 88 | func AdjustBrightness(img image.Image, percentage float64) *image.NRGBA { 89 | percentage = math.Min(math.Max(percentage, -100.0), 100.0) 90 | lut := make([]uint8, 256) 91 | 92 | shift := 255.0 * percentage / 100.0 93 | for i := 0; i < 256; i++ { 94 | lut[i] = clamp(float64(i) + shift) 95 | } 96 | 97 | return adjustLUT(img, lut) 98 | } 99 | 100 | // AdjustGamma performs a gamma correction on the image and returns the adjusted image. 101 | // Gamma parameter must be positive. Gamma = 1.0 gives the original image. 102 | // Gamma less than 1.0 darkens the image and gamma greater than 1.0 lightens it. 103 | // 104 | // Example: 105 | // 106 | // dstImage = imaging.AdjustGamma(srcImage, 0.7) 107 | // 108 | func AdjustGamma(img image.Image, gamma float64) *image.NRGBA { 109 | e := 1.0 / math.Max(gamma, 0.0001) 110 | lut := make([]uint8, 256) 111 | 112 | for i := 0; i < 256; i++ { 113 | lut[i] = clamp(math.Pow(float64(i)/255.0, e) * 255.0) 114 | } 115 | 116 | return adjustLUT(img, lut) 117 | } 118 | 119 | // AdjustSigmoid changes the contrast of the image using a sigmoidal function and returns the adjusted image. 120 | // It's a non-linear contrast change useful for photo adjustments as it preserves highlight and shadow detail. 121 | // The midpoint parameter is the midpoint of contrast that must be between 0 and 1, typically 0.5. 122 | // The factor parameter indicates how much to increase or decrease the contrast, typically in range (-10, 10). 123 | // If the factor parameter is positive the image contrast is increased otherwise the contrast is decreased. 124 | // 125 | // Examples: 126 | // 127 | // dstImage = imaging.AdjustSigmoid(srcImage, 0.5, 3.0) // increase the contrast 128 | // dstImage = imaging.AdjustSigmoid(srcImage, 0.5, -3.0) // decrease the contrast 129 | // 130 | func AdjustSigmoid(img image.Image, midpoint, factor float64) *image.NRGBA { 131 | if factor == 0 { 132 | return Clone(img) 133 | } 134 | 135 | lut := make([]uint8, 256) 136 | a := math.Min(math.Max(midpoint, 0.0), 1.0) 137 | b := math.Abs(factor) 138 | sig0 := sigmoid(a, b, 0) 139 | sig1 := sigmoid(a, b, 1) 140 | e := 1.0e-6 141 | 142 | if factor > 0 { 143 | for i := 0; i < 256; i++ { 144 | x := float64(i) / 255.0 145 | sigX := sigmoid(a, b, x) 146 | f := (sigX - sig0) / (sig1 - sig0) 147 | lut[i] = clamp(f * 255.0) 148 | } 149 | } else { 150 | for i := 0; i < 256; i++ { 151 | x := float64(i) / 255.0 152 | arg := math.Min(math.Max((sig1-sig0)*x+sig0, e), 1.0-e) 153 | f := a - math.Log(1.0/arg-1.0)/b 154 | lut[i] = clamp(f * 255.0) 155 | } 156 | } 157 | 158 | return adjustLUT(img, lut) 159 | } 160 | 161 | func sigmoid(a, b, x float64) float64 { 162 | return 1 / (1 + math.Exp(b*(a-x))) 163 | } 164 | 165 | // adjustLUT applies the given lookup table to the colors of the image. 166 | func adjustLUT(img image.Image, lut []uint8) *image.NRGBA { 167 | src := newScanner(img) 168 | dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) 169 | parallel(0, src.h, func(ys <-chan int) { 170 | for y := range ys { 171 | i := y * dst.Stride 172 | src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) 173 | for x := 0; x < src.w; x++ { 174 | dst.Pix[i+0] = lut[dst.Pix[i+0]] 175 | dst.Pix[i+1] = lut[dst.Pix[i+1]] 176 | dst.Pix[i+2] = lut[dst.Pix[i+2]] 177 | i += 4 178 | } 179 | } 180 | }) 181 | return dst 182 | } 183 | 184 | // AdjustFunc applies the fn function to each pixel of the img image and returns the adjusted image. 185 | // 186 | // Example: 187 | // 188 | // dstImage = imaging.AdjustFunc( 189 | // srcImage, 190 | // func(c color.NRGBA) color.NRGBA { 191 | // // shift the red channel by 16 192 | // r := int(c.R) + 16 193 | // if r > 255 { 194 | // r = 255 195 | // } 196 | // return color.NRGBA{uint8(r), c.G, c.B, c.A} 197 | // } 198 | // ) 199 | // 200 | func AdjustFunc(img image.Image, fn func(c color.NRGBA) color.NRGBA) *image.NRGBA { 201 | src := newScanner(img) 202 | dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) 203 | parallel(0, src.h, func(ys <-chan int) { 204 | for y := range ys { 205 | i := y * dst.Stride 206 | src.scan(0, y, src.w, y+1, dst.Pix[i:i+src.w*4]) 207 | for x := 0; x < src.w; x++ { 208 | r := dst.Pix[i+0] 209 | g := dst.Pix[i+1] 210 | b := dst.Pix[i+2] 211 | a := dst.Pix[i+3] 212 | c := fn(color.NRGBA{r, g, b, a}) 213 | dst.Pix[i+0] = c.R 214 | dst.Pix[i+1] = c.G 215 | dst.Pix[i+2] = c.B 216 | dst.Pix[i+3] = c.A 217 | i += 4 218 | } 219 | } 220 | }) 221 | return dst 222 | } 223 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/helpers.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "errors" 5 | "image" 6 | "image/color" 7 | "image/draw" 8 | "image/gif" 9 | "image/jpeg" 10 | "image/png" 11 | "io" 12 | "os" 13 | "path/filepath" 14 | "strings" 15 | 16 | "golang.org/x/image/bmp" 17 | "golang.org/x/image/tiff" 18 | ) 19 | 20 | // Format is an image file format. 21 | type Format int 22 | 23 | // Image file formats. 24 | const ( 25 | JPEG Format = iota 26 | PNG 27 | GIF 28 | TIFF 29 | BMP 30 | ) 31 | 32 | func (f Format) String() string { 33 | switch f { 34 | case JPEG: 35 | return "JPEG" 36 | case PNG: 37 | return "PNG" 38 | case GIF: 39 | return "GIF" 40 | case TIFF: 41 | return "TIFF" 42 | case BMP: 43 | return "BMP" 44 | default: 45 | return "Unsupported" 46 | } 47 | } 48 | 49 | var ( 50 | // ErrUnsupportedFormat means the given image format (or file extension) is unsupported. 51 | ErrUnsupportedFormat = errors.New("imaging: unsupported image format") 52 | ) 53 | 54 | type fileSystem interface { 55 | Create(string) (io.WriteCloser, error) 56 | Open(string) (io.ReadCloser, error) 57 | } 58 | 59 | type localFS struct{} 60 | 61 | func (localFS) Create(name string) (io.WriteCloser, error) { return os.Create(name) } 62 | func (localFS) Open(name string) (io.ReadCloser, error) { return os.Open(name) } 63 | 64 | var fs fileSystem = localFS{} 65 | 66 | // Decode reads an image from r. 67 | func Decode(r io.Reader) (image.Image, error) { 68 | img, _, err := image.Decode(r) 69 | return img, err 70 | } 71 | 72 | // Open loads an image from file 73 | func Open(filename string) (image.Image, error) { 74 | file, err := fs.Open(filename) 75 | if err != nil { 76 | return nil, err 77 | } 78 | defer file.Close() 79 | return Decode(file) 80 | } 81 | 82 | type encodeConfig struct { 83 | jpegQuality int 84 | gifNumColors int 85 | gifQuantizer draw.Quantizer 86 | gifDrawer draw.Drawer 87 | pngCompressionLevel png.CompressionLevel 88 | } 89 | 90 | var defaultEncodeConfig = encodeConfig{ 91 | jpegQuality: 95, 92 | gifNumColors: 256, 93 | gifQuantizer: nil, 94 | gifDrawer: nil, 95 | pngCompressionLevel: png.DefaultCompression, 96 | } 97 | 98 | // EncodeOption sets an optional parameter for the Encode and Save functions. 99 | type EncodeOption func(*encodeConfig) 100 | 101 | // JPEGQuality returns an EncodeOption that sets the output JPEG quality. 102 | // Quality ranges from 1 to 100 inclusive, higher is better. Default is 95. 103 | func JPEGQuality(quality int) EncodeOption { 104 | return func(c *encodeConfig) { 105 | c.jpegQuality = quality 106 | } 107 | } 108 | 109 | // GIFNumColors returns an EncodeOption that sets the maximum number of colors 110 | // used in the GIF-encoded image. It ranges from 1 to 256. Default is 256. 111 | func GIFNumColors(numColors int) EncodeOption { 112 | return func(c *encodeConfig) { 113 | c.gifNumColors = numColors 114 | } 115 | } 116 | 117 | // GIFQuantizer returns an EncodeOption that sets the quantizer that is used to produce 118 | // a palette of the GIF-encoded image. 119 | func GIFQuantizer(quantizer draw.Quantizer) EncodeOption { 120 | return func(c *encodeConfig) { 121 | c.gifQuantizer = quantizer 122 | } 123 | } 124 | 125 | // GIFDrawer returns an EncodeOption that sets the drawer that is used to convert 126 | // the source image to the desired palette of the GIF-encoded image. 127 | func GIFDrawer(drawer draw.Drawer) EncodeOption { 128 | return func(c *encodeConfig) { 129 | c.gifDrawer = drawer 130 | } 131 | } 132 | 133 | // PNGCompressionLevel returns an EncodeOption that sets the compression level 134 | // of the PNG-encoded image. Default is png.DefaultCompression. 135 | func PNGCompressionLevel(level png.CompressionLevel) EncodeOption { 136 | return func(c *encodeConfig) { 137 | c.pngCompressionLevel = level 138 | } 139 | } 140 | 141 | // Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP). 142 | func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error { 143 | cfg := defaultEncodeConfig 144 | for _, option := range opts { 145 | option(&cfg) 146 | } 147 | 148 | var err error 149 | switch format { 150 | case JPEG: 151 | var rgba *image.RGBA 152 | if nrgba, ok := img.(*image.NRGBA); ok { 153 | if nrgba.Opaque() { 154 | rgba = &image.RGBA{ 155 | Pix: nrgba.Pix, 156 | Stride: nrgba.Stride, 157 | Rect: nrgba.Rect, 158 | } 159 | } 160 | } 161 | if rgba != nil { 162 | err = jpeg.Encode(w, rgba, &jpeg.Options{Quality: cfg.jpegQuality}) 163 | } else { 164 | err = jpeg.Encode(w, img, &jpeg.Options{Quality: cfg.jpegQuality}) 165 | } 166 | 167 | case PNG: 168 | enc := png.Encoder{CompressionLevel: cfg.pngCompressionLevel} 169 | err = enc.Encode(w, img) 170 | 171 | case GIF: 172 | err = gif.Encode(w, img, &gif.Options{ 173 | NumColors: cfg.gifNumColors, 174 | Quantizer: cfg.gifQuantizer, 175 | Drawer: cfg.gifDrawer, 176 | }) 177 | 178 | case TIFF: 179 | err = tiff.Encode(w, img, &tiff.Options{Compression: tiff.Deflate, Predictor: true}) 180 | 181 | case BMP: 182 | err = bmp.Encode(w, img) 183 | 184 | default: 185 | err = ErrUnsupportedFormat 186 | } 187 | return err 188 | } 189 | 190 | // Save saves the image to file with the specified filename. 191 | // The format is determined from the filename extension: "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported. 192 | // 193 | // Examples: 194 | // 195 | // // Save the image as PNG. 196 | // err := imaging.Save(img, "out.png") 197 | // 198 | // // Save the image as JPEG with optional quality parameter set to 80. 199 | // err := imaging.Save(img, "out.jpg", imaging.JPEGQuality(80)) 200 | // 201 | func Save(img image.Image, filename string, opts ...EncodeOption) (err error) { 202 | formats := map[string]Format{ 203 | ".jpg": JPEG, 204 | ".jpeg": JPEG, 205 | ".png": PNG, 206 | ".tif": TIFF, 207 | ".tiff": TIFF, 208 | ".bmp": BMP, 209 | ".gif": GIF, 210 | } 211 | 212 | ext := strings.ToLower(filepath.Ext(filename)) 213 | f, ok := formats[ext] 214 | if !ok { 215 | return ErrUnsupportedFormat 216 | } 217 | 218 | file, err := fs.Create(filename) 219 | if err != nil { 220 | return err 221 | } 222 | 223 | defer func() { 224 | cerr := file.Close() 225 | if err == nil { 226 | err = cerr 227 | } 228 | }() 229 | 230 | return Encode(file, img, f, opts...) 231 | } 232 | 233 | // New creates a new image with the specified width and height, and fills it with the specified color. 234 | func New(width, height int, fillColor color.Color) *image.NRGBA { 235 | if width <= 0 || height <= 0 { 236 | return &image.NRGBA{} 237 | } 238 | 239 | dst := image.NewNRGBA(image.Rect(0, 0, width, height)) 240 | c := color.NRGBAModel.Convert(fillColor).(color.NRGBA) 241 | 242 | if c.R == 0 && c.G == 0 && c.B == 0 && c.A == 0 { 243 | return dst 244 | } 245 | 246 | // Fill the first row. 247 | i := 0 248 | for x := 0; x < width; x++ { 249 | dst.Pix[i+0] = c.R 250 | dst.Pix[i+1] = c.G 251 | dst.Pix[i+2] = c.B 252 | dst.Pix[i+3] = c.A 253 | i += 4 254 | } 255 | 256 | // Copy the first row to other rows. 257 | size := width * 4 258 | parallel(1, height, func(ys <-chan int) { 259 | for y := range ys { 260 | i = y * dst.Stride 261 | copy(dst.Pix[i:i+size], dst.Pix[0:size]) 262 | } 263 | }) 264 | 265 | return dst 266 | } 267 | 268 | // Clone returns a copy of the given image. 269 | func Clone(img image.Image) *image.NRGBA { 270 | src := newScanner(img) 271 | dst := image.NewNRGBA(image.Rect(0, 0, src.w, src.h)) 272 | size := src.w * 4 273 | parallel(0, src.h, func(ys <-chan int) { 274 | for y := range ys { 275 | i := y * dst.Stride 276 | src.scan(0, y, src.w, y+1, dst.Pix[i:i+size]) 277 | } 278 | }) 279 | return dst 280 | } 281 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/README.md: -------------------------------------------------------------------------------- 1 | # Imaging 2 | 3 | [![GoDoc](https://godoc.org/github.com/disintegration/imaging?status.svg)](https://godoc.org/github.com/disintegration/imaging) 4 | [![Build Status](https://travis-ci.org/disintegration/imaging.svg?branch=master)](https://travis-ci.org/disintegration/imaging) 5 | [![Coverage Status](https://coveralls.io/repos/github/disintegration/imaging/badge.svg?branch=master&service=github)](https://coveralls.io/github/disintegration/imaging?branch=master) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/disintegration/imaging)](https://goreportcard.com/report/github.com/disintegration/imaging) 7 | 8 | Package imaging provides basic image processing functions (resize, rotate, crop, brightness/contrast adjustments, etc.). 9 | 10 | All the image processing functions provided by the package accept any image type that implements `image.Image` interface 11 | as an input, and return a new image of `*image.NRGBA` type (32bit RGBA colors, not premultiplied by alpha). 12 | 13 | ## Installation 14 | 15 | go get -u github.com/disintegration/imaging 16 | 17 | ## Documentation 18 | 19 | http://godoc.org/github.com/disintegration/imaging 20 | 21 | ## Usage examples 22 | 23 | A few usage examples can be found below. See the documentation for the full list of supported functions. 24 | 25 | ### Image resizing 26 | 27 | ```go 28 | // Resize srcImage to size = 128x128px using the Lanczos filter. 29 | dstImage128 := imaging.Resize(srcImage, 128, 128, imaging.Lanczos) 30 | 31 | // Resize srcImage to width = 800px preserving the aspect ratio. 32 | dstImage800 := imaging.Resize(srcImage, 800, 0, imaging.Lanczos) 33 | 34 | // Scale down srcImage to fit the 800x600px bounding box. 35 | dstImageFit := imaging.Fit(srcImage, 800, 600, imaging.Lanczos) 36 | 37 | // Resize and crop the srcImage to fill the 100x100px area. 38 | dstImageFill := imaging.Fill(srcImage, 100, 100, imaging.Center, imaging.Lanczos) 39 | ``` 40 | 41 | Imaging supports image resizing using various resampling filters. The most notable ones: 42 | - `NearestNeighbor` - Fastest resampling filter, no antialiasing. 43 | - `Box` - Simple and fast averaging filter appropriate for downscaling. When upscaling it's similar to NearestNeighbor. 44 | - `Linear` - Bilinear filter, smooth and reasonably fast. 45 | - `MitchellNetravali` - А smooth bicubic filter. 46 | - `CatmullRom` - A sharp bicubic filter. 47 | - `Gaussian` - Blurring filter that uses gaussian function, useful for noise removal. 48 | - `Lanczos` - High-quality resampling filter for photographic images yielding sharp results, slower than cubic filters. 49 | 50 | The full list of supported filters: NearestNeighbor, Box, Linear, Hermite, MitchellNetravali, CatmullRom, BSpline, Gaussian, Lanczos, Hann, Hamming, Blackman, Bartlett, Welch, Cosine. Custom filters can be created using ResampleFilter struct. 51 | 52 | **Resampling filters comparison** 53 | 54 | Original image: 55 | 56 | ![srcImage](testdata/branches.png) 57 | 58 | The same image resized from 600x400px to 150x100px using different resampling filters. 59 | From faster (lower quality) to slower (higher quality): 60 | 61 | Filter | Resize result 62 | --------------------------|--------------------------------------------- 63 | `imaging.NearestNeighbor` | ![dstImage](testdata/out_resize_nearest.png) 64 | `imaging.Linear` | ![dstImage](testdata/out_resize_linear.png) 65 | `imaging.CatmullRom` | ![dstImage](testdata/out_resize_catrom.png) 66 | `imaging.Lanczos` | ![dstImage](testdata/out_resize_lanczos.png) 67 | 68 | 69 | ### Gaussian Blur 70 | 71 | ```go 72 | dstImage := imaging.Blur(srcImage, 0.5) 73 | ``` 74 | 75 | Sigma parameter allows to control the strength of the blurring effect. 76 | 77 | Original image | Sigma = 0.5 | Sigma = 1.5 78 | -----------------------------------|----------------------------------------|--------------------------------------- 79 | ![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_blur_0.5.png) | ![dstImage](testdata/out_blur_1.5.png) 80 | 81 | ### Sharpening 82 | 83 | ```go 84 | dstImage := imaging.Sharpen(srcImage, 0.5) 85 | ``` 86 | 87 | `Sharpen` uses gaussian function internally. Sigma parameter allows to control the strength of the sharpening effect. 88 | 89 | Original image | Sigma = 0.5 | Sigma = 1.5 90 | -----------------------------------|-------------------------------------------|------------------------------------------ 91 | ![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_sharpen_0.5.png) | ![dstImage](testdata/out_sharpen_1.5.png) 92 | 93 | ### Gamma correction 94 | 95 | ```go 96 | dstImage := imaging.AdjustGamma(srcImage, 0.75) 97 | ``` 98 | 99 | Original image | Gamma = 0.75 | Gamma = 1.25 100 | -----------------------------------|------------------------------------------|----------------------------------------- 101 | ![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_gamma_0.75.png) | ![dstImage](testdata/out_gamma_1.25.png) 102 | 103 | ### Contrast adjustment 104 | 105 | ```go 106 | dstImage := imaging.AdjustContrast(srcImage, 20) 107 | ``` 108 | 109 | Original image | Contrast = 15 | Contrast = -15 110 | -----------------------------------|--------------------------------------------|------------------------------------------- 111 | ![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_contrast_p15.png) | ![dstImage](testdata/out_contrast_m15.png) 112 | 113 | ### Brightness adjustment 114 | 115 | ```go 116 | dstImage := imaging.AdjustBrightness(srcImage, 20) 117 | ``` 118 | 119 | Original image | Brightness = 10 | Brightness = -10 120 | -----------------------------------|----------------------------------------------|--------------------------------------------- 121 | ![srcImage](testdata/flowers_small.png) | ![dstImage](testdata/out_brightness_p10.png) | ![dstImage](testdata/out_brightness_m10.png) 122 | 123 | ## Example code 124 | 125 | ```go 126 | package main 127 | 128 | import ( 129 | "image" 130 | "image/color" 131 | "log" 132 | 133 | "github.com/disintegration/imaging" 134 | ) 135 | 136 | func main() { 137 | // Open a test image. 138 | src, err := imaging.Open("testdata/flowers.png") 139 | if err != nil { 140 | log.Fatalf("failed to open image: %v", err) 141 | } 142 | 143 | // Crop the original image to 300x300px size using the center anchor. 144 | src = imaging.CropAnchor(src, 300, 300, imaging.Center) 145 | 146 | // Resize the cropped image to width = 200px preserving the aspect ratio. 147 | src = imaging.Resize(src, 200, 0, imaging.Lanczos) 148 | 149 | // Create a blurred version of the image. 150 | img1 := imaging.Blur(src, 5) 151 | 152 | // Create a grayscale version of the image with higher contrast and sharpness. 153 | img2 := imaging.Grayscale(src) 154 | img2 = imaging.AdjustContrast(img2, 20) 155 | img2 = imaging.Sharpen(img2, 2) 156 | 157 | // Create an inverted version of the image. 158 | img3 := imaging.Invert(src) 159 | 160 | // Create an embossed version of the image using a convolution filter. 161 | img4 := imaging.Convolve3x3( 162 | src, 163 | [9]float64{ 164 | -1, -1, 0, 165 | -1, 1, 1, 166 | 0, 1, 1, 167 | }, 168 | nil, 169 | ) 170 | 171 | // Create a new image and paste the four produced images into it. 172 | dst := imaging.New(400, 400, color.NRGBA{0, 0, 0, 0}) 173 | dst = imaging.Paste(dst, img1, image.Pt(0, 0)) 174 | dst = imaging.Paste(dst, img2, image.Pt(0, 200)) 175 | dst = imaging.Paste(dst, img3, image.Pt(200, 0)) 176 | dst = imaging.Paste(dst, img4, image.Pt(200, 200)) 177 | 178 | // Save the resulting image as JPEG. 179 | err = imaging.Save(dst, "testdata/out_example.jpg") 180 | if err != nil { 181 | log.Fatalf("failed to save image: %v", err) 182 | } 183 | } 184 | ``` 185 | 186 | Output: 187 | 188 | ![dstImage](testdata/out_example.jpg) -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/errors.go: -------------------------------------------------------------------------------- 1 | // Package errors provides simple error handling primitives. 2 | // 3 | // The traditional error handling idiom in Go is roughly akin to 4 | // 5 | // if err != nil { 6 | // return err 7 | // } 8 | // 9 | // which applied recursively up the call stack results in error reports 10 | // without context or debugging information. The errors package allows 11 | // programmers to add context to the failure path in their code in a way 12 | // that does not destroy the original value of the error. 13 | // 14 | // Adding context to an error 15 | // 16 | // The errors.Wrap function returns a new error that adds context to the 17 | // original error by recording a stack trace at the point Wrap is called, 18 | // and the supplied message. For example 19 | // 20 | // _, err := ioutil.ReadAll(r) 21 | // if err != nil { 22 | // return errors.Wrap(err, "read failed") 23 | // } 24 | // 25 | // If additional control is required the errors.WithStack and errors.WithMessage 26 | // functions destructure errors.Wrap into its component operations of annotating 27 | // an error with a stack trace and an a message, respectively. 28 | // 29 | // Retrieving the cause of an error 30 | // 31 | // Using errors.Wrap constructs a stack of errors, adding context to the 32 | // preceding error. Depending on the nature of the error it may be necessary 33 | // to reverse the operation of errors.Wrap to retrieve the original error 34 | // for inspection. Any error value which implements this interface 35 | // 36 | // type causer interface { 37 | // Cause() error 38 | // } 39 | // 40 | // can be inspected by errors.Cause. errors.Cause will recursively retrieve 41 | // the topmost error which does not implement causer, which is assumed to be 42 | // the original cause. For example: 43 | // 44 | // switch err := errors.Cause(err).(type) { 45 | // case *MyError: 46 | // // handle specifically 47 | // default: 48 | // // unknown error 49 | // } 50 | // 51 | // causer interface is not exported by this package, but is considered a part 52 | // of stable public API. 53 | // 54 | // Formatted printing of errors 55 | // 56 | // All error values returned from this package implement fmt.Formatter and can 57 | // be formatted by the fmt package. The following verbs are supported 58 | // 59 | // %s print the error. If the error has a Cause it will be 60 | // printed recursively 61 | // %v see %s 62 | // %+v extended format. Each Frame of the error's StackTrace will 63 | // be printed in detail. 64 | // 65 | // Retrieving the stack trace of an error or wrapper 66 | // 67 | // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are 68 | // invoked. This information can be retrieved with the following interface. 69 | // 70 | // type stackTracer interface { 71 | // StackTrace() errors.StackTrace 72 | // } 73 | // 74 | // Where errors.StackTrace is defined as 75 | // 76 | // type StackTrace []Frame 77 | // 78 | // The Frame type represents a call site in the stack trace. Frame supports 79 | // the fmt.Formatter interface that can be used for printing information about 80 | // the stack trace of this error. For example: 81 | // 82 | // if err, ok := err.(stackTracer); ok { 83 | // for _, f := range err.StackTrace() { 84 | // fmt.Printf("%+s:%d", f) 85 | // } 86 | // } 87 | // 88 | // stackTracer interface is not exported by this package, but is considered a part 89 | // of stable public API. 90 | // 91 | // See the documentation for Frame.Format for more details. 92 | package errors 93 | 94 | import ( 95 | "fmt" 96 | "io" 97 | ) 98 | 99 | // New returns an error with the supplied message. 100 | // New also records the stack trace at the point it was called. 101 | func New(message string) error { 102 | return &fundamental{ 103 | msg: message, 104 | stack: callers(), 105 | } 106 | } 107 | 108 | // Errorf formats according to a format specifier and returns the string 109 | // as a value that satisfies error. 110 | // Errorf also records the stack trace at the point it was called. 111 | func Errorf(format string, args ...interface{}) error { 112 | return &fundamental{ 113 | msg: fmt.Sprintf(format, args...), 114 | stack: callers(), 115 | } 116 | } 117 | 118 | // fundamental is an error that has a message and a stack, but no caller. 119 | type fundamental struct { 120 | msg string 121 | *stack 122 | } 123 | 124 | func (f *fundamental) Error() string { return f.msg } 125 | 126 | func (f *fundamental) Format(s fmt.State, verb rune) { 127 | switch verb { 128 | case 'v': 129 | if s.Flag('+') { 130 | io.WriteString(s, f.msg) 131 | f.stack.Format(s, verb) 132 | return 133 | } 134 | fallthrough 135 | case 's': 136 | io.WriteString(s, f.msg) 137 | case 'q': 138 | fmt.Fprintf(s, "%q", f.msg) 139 | } 140 | } 141 | 142 | // WithStack annotates err with a stack trace at the point WithStack was called. 143 | // If err is nil, WithStack returns nil. 144 | func WithStack(err error) error { 145 | if err == nil { 146 | return nil 147 | } 148 | return &withStack{ 149 | err, 150 | callers(), 151 | } 152 | } 153 | 154 | type withStack struct { 155 | error 156 | *stack 157 | } 158 | 159 | func (w *withStack) Cause() error { return w.error } 160 | 161 | func (w *withStack) Format(s fmt.State, verb rune) { 162 | switch verb { 163 | case 'v': 164 | if s.Flag('+') { 165 | fmt.Fprintf(s, "%+v", w.Cause()) 166 | w.stack.Format(s, verb) 167 | return 168 | } 169 | fallthrough 170 | case 's': 171 | io.WriteString(s, w.Error()) 172 | case 'q': 173 | fmt.Fprintf(s, "%q", w.Error()) 174 | } 175 | } 176 | 177 | // Wrap returns an error annotating err with a stack trace 178 | // at the point Wrap is called, and the supplied message. 179 | // If err is nil, Wrap returns nil. 180 | func Wrap(err error, message string) error { 181 | if err == nil { 182 | return nil 183 | } 184 | err = &withMessage{ 185 | cause: err, 186 | msg: message, 187 | } 188 | return &withStack{ 189 | err, 190 | callers(), 191 | } 192 | } 193 | 194 | // Wrapf returns an error annotating err with a stack trace 195 | // at the point Wrapf is call, and the format specifier. 196 | // If err is nil, Wrapf returns nil. 197 | func Wrapf(err error, format string, args ...interface{}) error { 198 | if err == nil { 199 | return nil 200 | } 201 | err = &withMessage{ 202 | cause: err, 203 | msg: fmt.Sprintf(format, args...), 204 | } 205 | return &withStack{ 206 | err, 207 | callers(), 208 | } 209 | } 210 | 211 | // WithMessage annotates err with a new message. 212 | // If err is nil, WithMessage returns nil. 213 | func WithMessage(err error, message string) error { 214 | if err == nil { 215 | return nil 216 | } 217 | return &withMessage{ 218 | cause: err, 219 | msg: message, 220 | } 221 | } 222 | 223 | type withMessage struct { 224 | cause error 225 | msg string 226 | } 227 | 228 | func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } 229 | func (w *withMessage) Cause() error { return w.cause } 230 | 231 | func (w *withMessage) Format(s fmt.State, verb rune) { 232 | switch verb { 233 | case 'v': 234 | if s.Flag('+') { 235 | fmt.Fprintf(s, "%+v\n", w.Cause()) 236 | io.WriteString(s, w.msg) 237 | return 238 | } 239 | fallthrough 240 | case 's', 'q': 241 | io.WriteString(s, w.Error()) 242 | } 243 | } 244 | 245 | // Cause returns the underlying cause of the error, if possible. 246 | // An error value has a cause if it implements the following 247 | // interface: 248 | // 249 | // type causer interface { 250 | // Cause() error 251 | // } 252 | // 253 | // If the error does not implement Cause, the original error will 254 | // be returned. If the error is nil, nil will be returned without further 255 | // investigation. 256 | func Cause(err error) error { 257 | type causer interface { 258 | Cause() error 259 | } 260 | 261 | for err != nil { 262 | cause, ok := err.(causer) 263 | if !ok { 264 | break 265 | } 266 | err = cause.Cause() 267 | } 268 | return err 269 | } 270 | -------------------------------------------------------------------------------- /vendor/github.com/disintegration/imaging/transform.go: -------------------------------------------------------------------------------- 1 | package imaging 2 | 3 | import ( 4 | "image" 5 | "image/color" 6 | "math" 7 | ) 8 | 9 | // FlipH flips the image horizontally (from left to right) and returns the transformed image. 10 | func FlipH(img image.Image) *image.NRGBA { 11 | src := newScanner(img) 12 | dstW := src.w 13 | dstH := src.h 14 | rowSize := dstW * 4 15 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 16 | parallel(0, dstH, func(ys <-chan int) { 17 | for dstY := range ys { 18 | i := dstY * dst.Stride 19 | srcY := dstY 20 | src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize]) 21 | reverse(dst.Pix[i : i+rowSize]) 22 | } 23 | }) 24 | return dst 25 | } 26 | 27 | // FlipV flips the image vertically (from top to bottom) and returns the transformed image. 28 | func FlipV(img image.Image) *image.NRGBA { 29 | src := newScanner(img) 30 | dstW := src.w 31 | dstH := src.h 32 | rowSize := dstW * 4 33 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 34 | parallel(0, dstH, func(ys <-chan int) { 35 | for dstY := range ys { 36 | i := dstY * dst.Stride 37 | srcY := dstH - dstY - 1 38 | src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize]) 39 | } 40 | }) 41 | return dst 42 | } 43 | 44 | // Transpose flips the image horizontally and rotates 90 degrees counter-clockwise. 45 | func Transpose(img image.Image) *image.NRGBA { 46 | src := newScanner(img) 47 | dstW := src.h 48 | dstH := src.w 49 | rowSize := dstW * 4 50 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 51 | parallel(0, dstH, func(ys <-chan int) { 52 | for dstY := range ys { 53 | i := dstY * dst.Stride 54 | srcX := dstY 55 | src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize]) 56 | } 57 | }) 58 | return dst 59 | } 60 | 61 | // Transverse flips the image vertically and rotates 90 degrees counter-clockwise. 62 | func Transverse(img image.Image) *image.NRGBA { 63 | src := newScanner(img) 64 | dstW := src.h 65 | dstH := src.w 66 | rowSize := dstW * 4 67 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 68 | parallel(0, dstH, func(ys <-chan int) { 69 | for dstY := range ys { 70 | i := dstY * dst.Stride 71 | srcX := dstH - dstY - 1 72 | src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize]) 73 | reverse(dst.Pix[i : i+rowSize]) 74 | } 75 | }) 76 | return dst 77 | } 78 | 79 | // Rotate90 rotates the image 90 degrees counter-clockwise and returns the transformed image. 80 | func Rotate90(img image.Image) *image.NRGBA { 81 | src := newScanner(img) 82 | dstW := src.h 83 | dstH := src.w 84 | rowSize := dstW * 4 85 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 86 | parallel(0, dstH, func(ys <-chan int) { 87 | for dstY := range ys { 88 | i := dstY * dst.Stride 89 | srcX := dstH - dstY - 1 90 | src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize]) 91 | } 92 | }) 93 | return dst 94 | } 95 | 96 | // Rotate180 rotates the image 180 degrees counter-clockwise and returns the transformed image. 97 | func Rotate180(img image.Image) *image.NRGBA { 98 | src := newScanner(img) 99 | dstW := src.w 100 | dstH := src.h 101 | rowSize := dstW * 4 102 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 103 | parallel(0, dstH, func(ys <-chan int) { 104 | for dstY := range ys { 105 | i := dstY * dst.Stride 106 | srcY := dstH - dstY - 1 107 | src.scan(0, srcY, src.w, srcY+1, dst.Pix[i:i+rowSize]) 108 | reverse(dst.Pix[i : i+rowSize]) 109 | } 110 | }) 111 | return dst 112 | } 113 | 114 | // Rotate270 rotates the image 270 degrees counter-clockwise and returns the transformed image. 115 | func Rotate270(img image.Image) *image.NRGBA { 116 | src := newScanner(img) 117 | dstW := src.h 118 | dstH := src.w 119 | rowSize := dstW * 4 120 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 121 | parallel(0, dstH, func(ys <-chan int) { 122 | for dstY := range ys { 123 | i := dstY * dst.Stride 124 | srcX := dstY 125 | src.scan(srcX, 0, srcX+1, src.h, dst.Pix[i:i+rowSize]) 126 | reverse(dst.Pix[i : i+rowSize]) 127 | } 128 | }) 129 | return dst 130 | } 131 | 132 | // Rotate rotates an image by the given angle counter-clockwise . 133 | // The angle parameter is the rotation angle in degrees. 134 | // The bgColor parameter specifies the color of the uncovered zone after the rotation. 135 | func Rotate(img image.Image, angle float64, bgColor color.Color) *image.NRGBA { 136 | angle = angle - math.Floor(angle/360)*360 137 | 138 | switch angle { 139 | case 0: 140 | return Clone(img) 141 | case 90: 142 | return Rotate90(img) 143 | case 180: 144 | return Rotate180(img) 145 | case 270: 146 | return Rotate270(img) 147 | } 148 | 149 | src := toNRGBA(img) 150 | srcW := src.Bounds().Max.X 151 | srcH := src.Bounds().Max.Y 152 | dstW, dstH := rotatedSize(srcW, srcH, angle) 153 | dst := image.NewNRGBA(image.Rect(0, 0, dstW, dstH)) 154 | 155 | if dstW <= 0 || dstH <= 0 { 156 | return dst 157 | } 158 | 159 | srcXOff := float64(srcW)/2 - 0.5 160 | srcYOff := float64(srcH)/2 - 0.5 161 | dstXOff := float64(dstW)/2 - 0.5 162 | dstYOff := float64(dstH)/2 - 0.5 163 | 164 | bgColorNRGBA := color.NRGBAModel.Convert(bgColor).(color.NRGBA) 165 | sin, cos := math.Sincos(math.Pi * angle / 180) 166 | 167 | parallel(0, dstH, func(ys <-chan int) { 168 | for dstY := range ys { 169 | for dstX := 0; dstX < dstW; dstX++ { 170 | xf, yf := rotatePoint(float64(dstX)-dstXOff, float64(dstY)-dstYOff, sin, cos) 171 | xf, yf = xf+srcXOff, yf+srcYOff 172 | interpolatePoint(dst, dstX, dstY, src, xf, yf, bgColorNRGBA) 173 | } 174 | } 175 | }) 176 | 177 | return dst 178 | } 179 | 180 | func rotatePoint(x, y, sin, cos float64) (float64, float64) { 181 | return x*cos - y*sin, x*sin + y*cos 182 | } 183 | 184 | func rotatedSize(w, h int, angle float64) (int, int) { 185 | if w <= 0 || h <= 0 { 186 | return 0, 0 187 | } 188 | 189 | sin, cos := math.Sincos(math.Pi * angle / 180) 190 | x1, y1 := rotatePoint(float64(w-1), 0, sin, cos) 191 | x2, y2 := rotatePoint(float64(w-1), float64(h-1), sin, cos) 192 | x3, y3 := rotatePoint(0, float64(h-1), sin, cos) 193 | 194 | minx := math.Min(x1, math.Min(x2, math.Min(x3, 0))) 195 | maxx := math.Max(x1, math.Max(x2, math.Max(x3, 0))) 196 | miny := math.Min(y1, math.Min(y2, math.Min(y3, 0))) 197 | maxy := math.Max(y1, math.Max(y2, math.Max(y3, 0))) 198 | 199 | neww := maxx - minx + 1 200 | if neww-math.Floor(neww) > 0.1 { 201 | neww++ 202 | } 203 | newh := maxy - miny + 1 204 | if newh-math.Floor(newh) > 0.1 { 205 | newh++ 206 | } 207 | 208 | return int(neww), int(newh) 209 | } 210 | 211 | func interpolatePoint(dst *image.NRGBA, dstX, dstY int, src *image.NRGBA, xf, yf float64, bgColor color.NRGBA) { 212 | dstIndex := dstY*dst.Stride + dstX*4 213 | 214 | x0 := int(math.Floor(xf)) 215 | y0 := int(math.Floor(yf)) 216 | bounds := src.Bounds() 217 | if !image.Pt(x0, y0).In(image.Rect(bounds.Min.X-1, bounds.Min.Y-1, bounds.Max.X, bounds.Max.Y)) { 218 | dst.Pix[dstIndex+0] = bgColor.R 219 | dst.Pix[dstIndex+1] = bgColor.G 220 | dst.Pix[dstIndex+2] = bgColor.B 221 | dst.Pix[dstIndex+3] = bgColor.A 222 | return 223 | } 224 | 225 | xq := xf - float64(x0) 226 | yq := yf - float64(y0) 227 | 228 | var pxs [4]color.NRGBA 229 | var cfs [4]float64 230 | 231 | for i := 0; i < 2; i++ { 232 | for j := 0; j < 2; j++ { 233 | k := i*2 + j 234 | pt := image.Pt(x0+j, y0+i) 235 | if pt.In(bounds) { 236 | l := pt.Y*src.Stride + pt.X*4 237 | pxs[k].R = src.Pix[l+0] 238 | pxs[k].G = src.Pix[l+1] 239 | pxs[k].B = src.Pix[l+2] 240 | pxs[k].A = src.Pix[l+3] 241 | } else { 242 | pxs[k] = bgColor 243 | } 244 | } 245 | } 246 | 247 | cfs[0] = (1 - xq) * (1 - yq) 248 | cfs[1] = xq * (1 - yq) 249 | cfs[2] = (1 - xq) * yq 250 | cfs[3] = xq * yq 251 | 252 | var r, g, b, a float64 253 | for i := range pxs { 254 | wa := float64(pxs[i].A) * cfs[i] 255 | r += float64(pxs[i].R) * wa 256 | g += float64(pxs[i].G) * wa 257 | b += float64(pxs[i].B) * wa 258 | a += wa 259 | } 260 | 261 | if a != 0 { 262 | r /= a 263 | g /= a 264 | b /= a 265 | } 266 | 267 | dst.Pix[dstIndex+0] = clamp(r) 268 | dst.Pix[dstIndex+1] = clamp(g) 269 | dst.Pix[dstIndex+2] = clamp(b) 270 | dst.Pix[dstIndex+3] = clamp(a) 271 | } 272 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/tiff/lzw/reader.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package lzw implements the Lempel-Ziv-Welch compressed data format, 6 | // described in T. A. Welch, ``A Technique for High-Performance Data 7 | // Compression'', Computer, 17(6) (June 1984), pp 8-19. 8 | // 9 | // In particular, it implements LZW as used by the TIFF file format, including 10 | // an "off by one" algorithmic difference when compared to standard LZW. 11 | package lzw // import "golang.org/x/image/tiff/lzw" 12 | 13 | /* 14 | This file was branched from src/pkg/compress/lzw/reader.go in the 15 | standard library. Differences from the original are marked with "NOTE". 16 | 17 | The tif_lzw.c file in the libtiff C library has this comment: 18 | 19 | ---- 20 | The 5.0 spec describes a different algorithm than Aldus 21 | implements. Specifically, Aldus does code length transitions 22 | one code earlier than should be done (for real LZW). 23 | Earlier versions of this library implemented the correct 24 | LZW algorithm, but emitted codes in a bit order opposite 25 | to the TIFF spec. Thus, to maintain compatibility w/ Aldus 26 | we interpret MSB-LSB ordered codes to be images written w/ 27 | old versions of this library, but otherwise adhere to the 28 | Aldus "off by one" algorithm. 29 | ---- 30 | 31 | The Go code doesn't read (invalid) TIFF files written by old versions of 32 | libtiff, but the LZW algorithm in this package still differs from the one in 33 | Go's standard package library to accomodate this "off by one" in valid TIFFs. 34 | */ 35 | 36 | import ( 37 | "bufio" 38 | "errors" 39 | "fmt" 40 | "io" 41 | ) 42 | 43 | // Order specifies the bit ordering in an LZW data stream. 44 | type Order int 45 | 46 | const ( 47 | // LSB means Least Significant Bits first, as used in the GIF file format. 48 | LSB Order = iota 49 | // MSB means Most Significant Bits first, as used in the TIFF and PDF 50 | // file formats. 51 | MSB 52 | ) 53 | 54 | const ( 55 | maxWidth = 12 56 | decoderInvalidCode = 0xffff 57 | flushBuffer = 1 << maxWidth 58 | ) 59 | 60 | // decoder is the state from which the readXxx method converts a byte 61 | // stream into a code stream. 62 | type decoder struct { 63 | r io.ByteReader 64 | bits uint32 65 | nBits uint 66 | width uint 67 | read func(*decoder) (uint16, error) // readLSB or readMSB 68 | litWidth int // width in bits of literal codes 69 | err error 70 | 71 | // The first 1<= 1<>= d.width 111 | d.nBits -= d.width 112 | return code, nil 113 | } 114 | 115 | // readMSB returns the next code for "Most Significant Bits first" data. 116 | func (d *decoder) readMSB() (uint16, error) { 117 | for d.nBits < d.width { 118 | x, err := d.r.ReadByte() 119 | if err != nil { 120 | return 0, err 121 | } 122 | d.bits |= uint32(x) << (24 - d.nBits) 123 | d.nBits += 8 124 | } 125 | code := uint16(d.bits >> (32 - d.width)) 126 | d.bits <<= d.width 127 | d.nBits -= d.width 128 | return code, nil 129 | } 130 | 131 | func (d *decoder) Read(b []byte) (int, error) { 132 | for { 133 | if len(d.toRead) > 0 { 134 | n := copy(b, d.toRead) 135 | d.toRead = d.toRead[n:] 136 | return n, nil 137 | } 138 | if d.err != nil { 139 | return 0, d.err 140 | } 141 | d.decode() 142 | } 143 | } 144 | 145 | // decode decompresses bytes from r and leaves them in d.toRead. 146 | // read specifies how to decode bytes into codes. 147 | // litWidth is the width in bits of literal codes. 148 | func (d *decoder) decode() { 149 | // Loop over the code stream, converting codes into decompressed bytes. 150 | loop: 151 | for { 152 | code, err := d.read(d) 153 | if err != nil { 154 | if err == io.EOF { 155 | err = io.ErrUnexpectedEOF 156 | } 157 | d.err = err 158 | break 159 | } 160 | switch { 161 | case code < d.clear: 162 | // We have a literal code. 163 | d.output[d.o] = uint8(code) 164 | d.o++ 165 | if d.last != decoderInvalidCode { 166 | // Save what the hi code expands to. 167 | d.suffix[d.hi] = uint8(code) 168 | d.prefix[d.hi] = d.last 169 | } 170 | case code == d.clear: 171 | d.width = 1 + uint(d.litWidth) 172 | d.hi = d.eof 173 | d.overflow = 1 << d.width 174 | d.last = decoderInvalidCode 175 | continue 176 | case code == d.eof: 177 | d.err = io.EOF 178 | break loop 179 | case code <= d.hi: 180 | c, i := code, len(d.output)-1 181 | if code == d.hi { 182 | // code == hi is a special case which expands to the last expansion 183 | // followed by the head of the last expansion. To find the head, we walk 184 | // the prefix chain until we find a literal code. 185 | c = d.last 186 | for c >= d.clear { 187 | c = d.prefix[c] 188 | } 189 | d.output[i] = uint8(c) 190 | i-- 191 | c = d.last 192 | } 193 | // Copy the suffix chain into output and then write that to w. 194 | for c >= d.clear { 195 | d.output[i] = d.suffix[c] 196 | i-- 197 | c = d.prefix[c] 198 | } 199 | d.output[i] = uint8(c) 200 | d.o += copy(d.output[d.o:], d.output[i:]) 201 | if d.last != decoderInvalidCode { 202 | // Save what the hi code expands to. 203 | d.suffix[d.hi] = uint8(c) 204 | d.prefix[d.hi] = d.last 205 | } 206 | default: 207 | d.err = errors.New("lzw: invalid code") 208 | break loop 209 | } 210 | d.last, d.hi = code, d.hi+1 211 | if d.hi+1 >= d.overflow { // NOTE: the "+1" is where TIFF's LZW differs from the standard algorithm. 212 | if d.width == maxWidth { 213 | d.last = decoderInvalidCode 214 | } else { 215 | d.width++ 216 | d.overflow <<= 1 217 | } 218 | } 219 | if d.o >= flushBuffer { 220 | break 221 | } 222 | } 223 | // Flush pending output. 224 | d.toRead = d.output[:d.o] 225 | d.o = 0 226 | } 227 | 228 | var errClosed = errors.New("lzw: reader/writer is closed") 229 | 230 | func (d *decoder) Close() error { 231 | d.err = errClosed // in case any Reads come along 232 | return nil 233 | } 234 | 235 | // NewReader creates a new io.ReadCloser. 236 | // Reads from the returned io.ReadCloser read and decompress data from r. 237 | // If r does not also implement io.ByteReader, 238 | // the decompressor may read more data than necessary from r. 239 | // It is the caller's responsibility to call Close on the ReadCloser when 240 | // finished reading. 241 | // The number of bits to use for literal codes, litWidth, must be in the 242 | // range [2,8] and is typically 8. It must equal the litWidth 243 | // used during compression. 244 | func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser { 245 | d := new(decoder) 246 | switch order { 247 | case LSB: 248 | d.read = (*decoder).readLSB 249 | case MSB: 250 | d.read = (*decoder).readMSB 251 | default: 252 | d.err = errors.New("lzw: unknown order") 253 | return d 254 | } 255 | if litWidth < 2 || 8 < litWidth { 256 | d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth) 257 | return d 258 | } 259 | if br, ok := r.(io.ByteReader); ok { 260 | d.r = br 261 | } else { 262 | d.r = bufio.NewReader(r) 263 | } 264 | d.litWidth = litWidth 265 | d.width = 1 + uint(litWidth) 266 | d.clear = uint16(1) << uint(litWidth) 267 | d.eof, d.hi = d.clear+1, d.clear+1 268 | d.overflow = uint16(1) << d.width 269 | d.last = decoderInvalidCode 270 | 271 | return d 272 | } 273 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/path.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Joe Beda 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package svgdata 16 | 17 | import ( 18 | "bytes" 19 | "regexp" 20 | "strconv" 21 | "strings" 22 | 23 | "github.com/pkg/errors" 24 | ) 25 | 26 | type Path struct { 27 | nodeImpl 28 | SubPaths []SubPath 29 | } 30 | 31 | type SubPath struct { 32 | Commands []PathCommand 33 | startX, startY float64 // The start of the path 34 | endX, endY float64 // The end of the path 35 | } 36 | 37 | type PathCommand struct { 38 | Command byte // The single character command 39 | Params []float64 // The parameters to the command 40 | startX, startY float64 // The start point 41 | endX, endY float64 // The point that the command ends on 42 | } 43 | 44 | func init() { 45 | RegisterNodeCreator("path", func() Node { return NewPath() }) 46 | } 47 | 48 | func NewPath() *Path { 49 | p := &Path{} 50 | p.nodeImpl.name = "path" 51 | p.nodeImpl.onMarshalAttrs = p.marshalAttrs 52 | p.nodeImpl.onUnmarshalAttrs = p.unmarshalAttrs 53 | return p 54 | } 55 | 56 | func (p *Path) marshalAttrs(am AttrMap) { 57 | am["d"] = SavePathString(p.SubPaths) 58 | } 59 | 60 | func (p *Path) unmarshalAttrs(am AttrMap) error { 61 | var err error 62 | p.SubPaths, err = ParsePathString(am["d"]) 63 | if err != nil { 64 | return err 65 | } 66 | delete(am, "d") 67 | 68 | return nil 69 | } 70 | 71 | var commandLengths map[byte]int = map[byte]int{ 72 | 'm': 2, // move to 73 | 'M': 2, 74 | 'z': 0, // close path 75 | 'Z': 0, 76 | 'l': 2, // line to 77 | 'L': 2, 78 | 'h': 1, // hori line to 79 | 'H': 1, 80 | 'v': 1, // vert line to 81 | 'V': 1, 82 | 'c': 6, // cubic bezier curve to 83 | 'C': 6, 84 | 's': 4, // smooth cubic bezier curve to 85 | 'S': 4, 86 | 'q': 4, // quad bezier curve to 87 | 'Q': 4, 88 | 't': 2, // smooth quad bezier curve to 89 | 'T': 2, 90 | 'a': 7, // arc to 91 | 'A': 7, 92 | } 93 | 94 | func isEOD(t pathToken) bool { 95 | _, ok := t.(eodToken) 96 | return ok 97 | } 98 | 99 | type pathParser struct { 100 | currX, currY float64 101 | subPaths []SubPath 102 | currSubPath *SubPath 103 | } 104 | 105 | // ParsePathString parses an SVG path string. Each command represents a single 106 | // instance of the command. This is to enable easier further processing. 107 | func ParsePathString(d string) ([]SubPath, error) { 108 | pp := pathParser{} 109 | return pp.parse(d) 110 | } 111 | 112 | func SavePathString(sps []SubPath) string { 113 | var buf bytes.Buffer 114 | for _, sp := range sps { 115 | for i := 0; i < len(sp.Commands); i++ { 116 | c := sp.Commands[i] 117 | buf.WriteByte(c.Command) 118 | for j, p := range c.Params { 119 | buf.WriteString(strconv.FormatFloat(p, 'f', -1, 64)) 120 | if j != len(c.Params)-1 { 121 | buf.WriteByte(' ') 122 | } 123 | } 124 | } 125 | } 126 | 127 | return buf.String() 128 | } 129 | 130 | func (pp *pathParser) parse(d string) ([]SubPath, error) { 131 | cmds, err := parsePathCommands(d) 132 | if err != nil { 133 | return nil, err 134 | } 135 | 136 | for _, c := range cmds { 137 | // If we see a start path or don't have a current subpath then we start a 138 | // new subpath 139 | if pp.currSubPath == nil || c.Command == 'm' || c.Command == 'M' { 140 | pp.subPaths = append(pp.subPaths, SubPath{}) 141 | pp.currSubPath = &pp.subPaths[len(pp.subPaths)-1] 142 | 143 | // If the current command isn't 'M' then we inject one 144 | if c.Command != 'm' && c.Command != 'M' { 145 | pp.currSubPath.Commands = append(pp.currSubPath.Commands, 146 | PathCommand{Command: 'M', Params: []float64{pp.currX, pp.currY}}) 147 | pp.updatePositions(&pp.currSubPath.Commands[0]) 148 | } 149 | } 150 | 151 | pp.currSubPath.Commands = append(pp.currSubPath.Commands, c) 152 | pp.updatePositions(&pp.currSubPath.Commands[len(pp.currSubPath.Commands)-1]) 153 | 154 | // If we see a Z then we close out the subpath 155 | if c.Command == 'z' || c.Command == 'Z' { 156 | pp.currSubPath = nil 157 | } 158 | } 159 | 160 | return pp.subPaths, nil 161 | } 162 | 163 | // updatePositions updates any begin/end positions on the command and subpath 164 | // based on current context. 165 | func (pp *pathParser) updatePositions(c *PathCommand) { 166 | c.startX, c.startY = pp.currX, pp.currY 167 | 168 | switch c.Command { 169 | case 'm': 170 | pp.currX, pp.currY = (pp.currX + c.Params[0]), (pp.currY + c.Params[1]) 171 | pp.currSubPath.startX, pp.currSubPath.startY = pp.currX, pp.currY 172 | case 'M': 173 | pp.currX, pp.currY = c.Params[0], c.Params[1] 174 | pp.currSubPath.startX, pp.currSubPath.startY = pp.currX, pp.currY 175 | case 'z': 176 | fallthrough 177 | case 'Z': 178 | pp.currX, pp.currY = pp.currSubPath.startX, pp.currSubPath.startY 179 | case 'l': 180 | pp.currX, pp.currY = (pp.currX + c.Params[0]), (pp.currY + c.Params[1]) 181 | case 'L': 182 | pp.currX, pp.currY = c.Params[0], c.Params[1] 183 | case 'h': 184 | pp.currX = pp.currX + c.Params[0] 185 | case 'H': 186 | pp.currX = c.Params[0] 187 | case 'v': 188 | pp.currY = pp.currY + c.Params[0] 189 | case 'V': 190 | pp.currY = c.Params[0] 191 | case 'c': 192 | pp.currX, pp.currY = (pp.currX + c.Params[4]), (pp.currY + c.Params[5]) 193 | case 'C': 194 | pp.currX, pp.currY = c.Params[4], c.Params[5] 195 | case 's': 196 | pp.currX, pp.currY = (pp.currX + c.Params[2]), (pp.currY + c.Params[3]) 197 | case 'S': 198 | pp.currX, pp.currY = c.Params[2], c.Params[3] 199 | case 'q': 200 | pp.currX, pp.currY = (pp.currX + c.Params[2]), (pp.currY + c.Params[3]) 201 | case 'Q': 202 | pp.currX, pp.currY = c.Params[2], c.Params[3] 203 | case 't': 204 | pp.currX, pp.currY = (pp.currX + c.Params[0]), (pp.currY + c.Params[1]) 205 | case 'T': 206 | pp.currX, pp.currY = c.Params[0], c.Params[1] 207 | case 'a': 208 | pp.currX, pp.currY = (pp.currX + c.Params[5]), (pp.currY + c.Params[6]) 209 | case 'A': 210 | pp.currX, pp.currY = c.Params[5], c.Params[6] 211 | } 212 | 213 | c.endX, c.endY = pp.currX, pp.currY 214 | pp.currSubPath.endX, pp.currSubPath.endY = pp.currX, pp.currY 215 | } 216 | 217 | func parsePathCommands(d string) ([]PathCommand, error) { 218 | r := []PathCommand{} 219 | 220 | pts, err := pathTokenize(d) 221 | if err != nil { 222 | return nil, err 223 | } 224 | 225 | t, pts := pts[0], pts[1:] 226 | var currentCommand byte = 'L' 227 | 228 | // If we have a blank input then just exit now 229 | if isEOD(t) { 230 | return r, nil 231 | } 232 | 233 | for !isEOD(t) { 234 | // See if this is a command token. If so, then it becomes our current 235 | // command. 236 | ct, ok := t.(commandToken) 237 | if ok { 238 | currentCommand = ct.command 239 | t, pts = pts[0], pts[1:] 240 | } 241 | 242 | c := PathCommand{Command: currentCommand} 243 | 244 | commandLength := commandLengths[currentCommand] 245 | if len(pts) < commandLength { 246 | return nil, errors.Errorf("Path command (%c) doesn't have enough parameters (%d)", currentCommand, len(pts)) 247 | } 248 | 249 | for i := 0; i < commandLength; i++ { 250 | n, ok := t.(numberToken) 251 | if !ok { 252 | return nil, errors.Errorf("Path command (%c) doesn't have enough parameters", currentCommand) 253 | } 254 | c.Params = append(c.Params, n.number) 255 | t, pts = pts[0], pts[1:] 256 | } 257 | 258 | r = append(r, c) 259 | 260 | // Any extra parameters after M are the corresponding L 261 | if currentCommand == 'm' { 262 | currentCommand = 'l' 263 | } 264 | if currentCommand == 'M' { 265 | currentCommand = 'L' 266 | } 267 | } 268 | 269 | return r, nil 270 | } 271 | 272 | // Path tokenizer 273 | 274 | type pathToken interface{} 275 | type commandToken struct { 276 | command byte 277 | } 278 | type numberToken struct { 279 | number float64 280 | } 281 | type eodToken struct{} 282 | 283 | var floatRE *regexp.Regexp = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?`) 284 | 285 | func pathTokenize(d string) ([]pathToken, error) { 286 | var r []pathToken 287 | for len(d) > 0 { 288 | // Trim any whitespace and commas 289 | d = strings.TrimLeft(d, " \t\r\n,") 290 | if len(d) == 0 { 291 | break 292 | } 293 | 294 | // Look for a float 295 | loc := floatRE.FindStringIndex(d) 296 | if loc != nil { 297 | f, err := strconv.ParseFloat(d[loc[0]:loc[1]], 64) 298 | if err != nil { 299 | return nil, errors.WithStack(err) 300 | } 301 | d = d[loc[1]:] 302 | r = append(r, numberToken{f}) 303 | } else { 304 | // Assume it is a command 305 | c := d[0] 306 | if _, ok := commandLengths[c]; !ok { 307 | return nil, errors.Errorf("Unknown command in path: %c", c) 308 | } 309 | d = d[1:] 310 | r = append(r, commandToken{c}) 311 | } 312 | } 313 | r = append(r, eodToken{}) 314 | return r, nil 315 | } 316 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /vendor/github.com/jbeda/svgdata-go/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /vendor/golang.org/x/image/tiff/writer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | import ( 8 | "bytes" 9 | "compress/zlib" 10 | "encoding/binary" 11 | "image" 12 | "io" 13 | "sort" 14 | ) 15 | 16 | // The TIFF format allows to choose the order of the different elements freely. 17 | // The basic structure of a TIFF file written by this package is: 18 | // 19 | // 1. Header (8 bytes). 20 | // 2. Image data. 21 | // 3. Image File Directory (IFD). 22 | // 4. "Pointer area" for larger entries in the IFD. 23 | 24 | // We only write little-endian TIFF files. 25 | var enc = binary.LittleEndian 26 | 27 | // An ifdEntry is a single entry in an Image File Directory. 28 | // A value of type dtRational is composed of two 32-bit values, 29 | // thus data contains two uints (numerator and denominator) for a single number. 30 | type ifdEntry struct { 31 | tag int 32 | datatype int 33 | data []uint32 34 | } 35 | 36 | func (e ifdEntry) putData(p []byte) { 37 | for _, d := range e.data { 38 | switch e.datatype { 39 | case dtByte, dtASCII: 40 | p[0] = byte(d) 41 | p = p[1:] 42 | case dtShort: 43 | enc.PutUint16(p, uint16(d)) 44 | p = p[2:] 45 | case dtLong, dtRational: 46 | enc.PutUint32(p, uint32(d)) 47 | p = p[4:] 48 | } 49 | } 50 | } 51 | 52 | type byTag []ifdEntry 53 | 54 | func (d byTag) Len() int { return len(d) } 55 | func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag } 56 | func (d byTag) Swap(i, j int) { d[i], d[j] = d[j], d[i] } 57 | 58 | func encodeGray(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { 59 | if !predictor { 60 | return writePix(w, pix, dy, dx, stride) 61 | } 62 | buf := make([]byte, dx) 63 | for y := 0; y < dy; y++ { 64 | min := y*stride + 0 65 | max := y*stride + dx 66 | off := 0 67 | var v0 uint8 68 | for i := min; i < max; i++ { 69 | v1 := pix[i] 70 | buf[off] = v1 - v0 71 | v0 = v1 72 | off++ 73 | } 74 | if _, err := w.Write(buf); err != nil { 75 | return err 76 | } 77 | } 78 | return nil 79 | } 80 | 81 | func encodeGray16(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { 82 | buf := make([]byte, dx*2) 83 | for y := 0; y < dy; y++ { 84 | min := y*stride + 0 85 | max := y*stride + dx*2 86 | off := 0 87 | var v0 uint16 88 | for i := min; i < max; i += 2 { 89 | // An image.Gray16's Pix is in big-endian order. 90 | v1 := uint16(pix[i])<<8 | uint16(pix[i+1]) 91 | if predictor { 92 | v0, v1 = v1, v1-v0 93 | } 94 | // We only write little-endian TIFF files. 95 | buf[off+0] = byte(v1) 96 | buf[off+1] = byte(v1 >> 8) 97 | off += 2 98 | } 99 | if _, err := w.Write(buf); err != nil { 100 | return err 101 | } 102 | } 103 | return nil 104 | } 105 | 106 | func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { 107 | if !predictor { 108 | return writePix(w, pix, dy, dx*4, stride) 109 | } 110 | buf := make([]byte, dx*4) 111 | for y := 0; y < dy; y++ { 112 | min := y*stride + 0 113 | max := y*stride + dx*4 114 | off := 0 115 | var r0, g0, b0, a0 uint8 116 | for i := min; i < max; i += 4 { 117 | r1, g1, b1, a1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3] 118 | buf[off+0] = r1 - r0 119 | buf[off+1] = g1 - g0 120 | buf[off+2] = b1 - b0 121 | buf[off+3] = a1 - a0 122 | off += 4 123 | r0, g0, b0, a0 = r1, g1, b1, a1 124 | } 125 | if _, err := w.Write(buf); err != nil { 126 | return err 127 | } 128 | } 129 | return nil 130 | } 131 | 132 | func encodeRGBA64(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error { 133 | buf := make([]byte, dx*8) 134 | for y := 0; y < dy; y++ { 135 | min := y*stride + 0 136 | max := y*stride + dx*8 137 | off := 0 138 | var r0, g0, b0, a0 uint16 139 | for i := min; i < max; i += 8 { 140 | // An image.RGBA64's Pix is in big-endian order. 141 | r1 := uint16(pix[i+0])<<8 | uint16(pix[i+1]) 142 | g1 := uint16(pix[i+2])<<8 | uint16(pix[i+3]) 143 | b1 := uint16(pix[i+4])<<8 | uint16(pix[i+5]) 144 | a1 := uint16(pix[i+6])<<8 | uint16(pix[i+7]) 145 | if predictor { 146 | r0, r1 = r1, r1-r0 147 | g0, g1 = g1, g1-g0 148 | b0, b1 = b1, b1-b0 149 | a0, a1 = a1, a1-a0 150 | } 151 | // We only write little-endian TIFF files. 152 | buf[off+0] = byte(r1) 153 | buf[off+1] = byte(r1 >> 8) 154 | buf[off+2] = byte(g1) 155 | buf[off+3] = byte(g1 >> 8) 156 | buf[off+4] = byte(b1) 157 | buf[off+5] = byte(b1 >> 8) 158 | buf[off+6] = byte(a1) 159 | buf[off+7] = byte(a1 >> 8) 160 | off += 8 161 | } 162 | if _, err := w.Write(buf); err != nil { 163 | return err 164 | } 165 | } 166 | return nil 167 | } 168 | 169 | func encode(w io.Writer, m image.Image, predictor bool) error { 170 | bounds := m.Bounds() 171 | buf := make([]byte, 4*bounds.Dx()) 172 | for y := bounds.Min.Y; y < bounds.Max.Y; y++ { 173 | off := 0 174 | if predictor { 175 | var r0, g0, b0, a0 uint8 176 | for x := bounds.Min.X; x < bounds.Max.X; x++ { 177 | r, g, b, a := m.At(x, y).RGBA() 178 | r1 := uint8(r >> 8) 179 | g1 := uint8(g >> 8) 180 | b1 := uint8(b >> 8) 181 | a1 := uint8(a >> 8) 182 | buf[off+0] = r1 - r0 183 | buf[off+1] = g1 - g0 184 | buf[off+2] = b1 - b0 185 | buf[off+3] = a1 - a0 186 | off += 4 187 | r0, g0, b0, a0 = r1, g1, b1, a1 188 | } 189 | } else { 190 | for x := bounds.Min.X; x < bounds.Max.X; x++ { 191 | r, g, b, a := m.At(x, y).RGBA() 192 | buf[off+0] = uint8(r >> 8) 193 | buf[off+1] = uint8(g >> 8) 194 | buf[off+2] = uint8(b >> 8) 195 | buf[off+3] = uint8(a >> 8) 196 | off += 4 197 | } 198 | } 199 | if _, err := w.Write(buf); err != nil { 200 | return err 201 | } 202 | } 203 | return nil 204 | } 205 | 206 | // writePix writes the internal byte array of an image to w. It is less general 207 | // but much faster then encode. writePix is used when pix directly 208 | // corresponds to one of the TIFF image types. 209 | func writePix(w io.Writer, pix []byte, nrows, length, stride int) error { 210 | if length == stride { 211 | _, err := w.Write(pix[:nrows*length]) 212 | return err 213 | } 214 | for ; nrows > 0; nrows-- { 215 | if _, err := w.Write(pix[:length]); err != nil { 216 | return err 217 | } 218 | pix = pix[stride:] 219 | } 220 | return nil 221 | } 222 | 223 | func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error { 224 | var buf [ifdLen]byte 225 | // Make space for "pointer area" containing IFD entry data 226 | // longer than 4 bytes. 227 | parea := make([]byte, 1024) 228 | pstart := ifdOffset + ifdLen*len(d) + 6 229 | var o int // Current offset in parea. 230 | 231 | // The IFD has to be written with the tags in ascending order. 232 | sort.Sort(byTag(d)) 233 | 234 | // Write the number of entries in this IFD. 235 | if err := binary.Write(w, enc, uint16(len(d))); err != nil { 236 | return err 237 | } 238 | for _, ent := range d { 239 | enc.PutUint16(buf[0:2], uint16(ent.tag)) 240 | enc.PutUint16(buf[2:4], uint16(ent.datatype)) 241 | count := uint32(len(ent.data)) 242 | if ent.datatype == dtRational { 243 | count /= 2 244 | } 245 | enc.PutUint32(buf[4:8], count) 246 | datalen := int(count * lengths[ent.datatype]) 247 | if datalen <= 4 { 248 | ent.putData(buf[8:12]) 249 | } else { 250 | if (o + datalen) > len(parea) { 251 | newlen := len(parea) + 1024 252 | for (o + datalen) > newlen { 253 | newlen += 1024 254 | } 255 | newarea := make([]byte, newlen) 256 | copy(newarea, parea) 257 | parea = newarea 258 | } 259 | ent.putData(parea[o : o+datalen]) 260 | enc.PutUint32(buf[8:12], uint32(pstart+o)) 261 | o += datalen 262 | } 263 | if _, err := w.Write(buf[:]); err != nil { 264 | return err 265 | } 266 | } 267 | // The IFD ends with the offset of the next IFD in the file, 268 | // or zero if it is the last one (page 14). 269 | if err := binary.Write(w, enc, uint32(0)); err != nil { 270 | return err 271 | } 272 | _, err := w.Write(parea[:o]) 273 | return err 274 | } 275 | 276 | // Options are the encoding parameters. 277 | type Options struct { 278 | // Compression is the type of compression used. 279 | Compression CompressionType 280 | // Predictor determines whether a differencing predictor is used; 281 | // if true, instead of each pixel's color, the color difference to the 282 | // preceding one is saved. This improves the compression for certain 283 | // types of images and compressors. For example, it works well for 284 | // photos with Deflate compression. 285 | Predictor bool 286 | } 287 | 288 | // Encode writes the image m to w. opt determines the options used for 289 | // encoding, such as the compression type. If opt is nil, an uncompressed 290 | // image is written. 291 | func Encode(w io.Writer, m image.Image, opt *Options) error { 292 | d := m.Bounds().Size() 293 | 294 | compression := uint32(cNone) 295 | predictor := false 296 | if opt != nil { 297 | compression = opt.Compression.specValue() 298 | // The predictor field is only used with LZW. See page 64 of the spec. 299 | predictor = opt.Predictor && compression == cLZW 300 | } 301 | 302 | _, err := io.WriteString(w, leHeader) 303 | if err != nil { 304 | return err 305 | } 306 | 307 | // Compressed data is written into a buffer first, so that we 308 | // know the compressed size. 309 | var buf bytes.Buffer 310 | // dst holds the destination for the pixel data of the image -- 311 | // either w or a writer to buf. 312 | var dst io.Writer 313 | // imageLen is the length of the pixel data in bytes. 314 | // The offset of the IFD is imageLen + 8 header bytes. 315 | var imageLen int 316 | 317 | switch compression { 318 | case cNone: 319 | dst = w 320 | // Write IFD offset before outputting pixel data. 321 | switch m.(type) { 322 | case *image.Paletted: 323 | imageLen = d.X * d.Y * 1 324 | case *image.Gray: 325 | imageLen = d.X * d.Y * 1 326 | case *image.Gray16: 327 | imageLen = d.X * d.Y * 2 328 | case *image.RGBA64: 329 | imageLen = d.X * d.Y * 8 330 | case *image.NRGBA64: 331 | imageLen = d.X * d.Y * 8 332 | default: 333 | imageLen = d.X * d.Y * 4 334 | } 335 | err = binary.Write(w, enc, uint32(imageLen+8)) 336 | if err != nil { 337 | return err 338 | } 339 | case cDeflate: 340 | dst = zlib.NewWriter(&buf) 341 | } 342 | 343 | pr := uint32(prNone) 344 | photometricInterpretation := uint32(pRGB) 345 | samplesPerPixel := uint32(4) 346 | bitsPerSample := []uint32{8, 8, 8, 8} 347 | extraSamples := uint32(0) 348 | colorMap := []uint32{} 349 | 350 | if predictor { 351 | pr = prHorizontal 352 | } 353 | switch m := m.(type) { 354 | case *image.Paletted: 355 | photometricInterpretation = pPaletted 356 | samplesPerPixel = 1 357 | bitsPerSample = []uint32{8} 358 | colorMap = make([]uint32, 256*3) 359 | for i := 0; i < 256 && i < len(m.Palette); i++ { 360 | r, g, b, _ := m.Palette[i].RGBA() 361 | colorMap[i+0*256] = uint32(r) 362 | colorMap[i+1*256] = uint32(g) 363 | colorMap[i+2*256] = uint32(b) 364 | } 365 | err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor) 366 | case *image.Gray: 367 | photometricInterpretation = pBlackIsZero 368 | samplesPerPixel = 1 369 | bitsPerSample = []uint32{8} 370 | err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor) 371 | case *image.Gray16: 372 | photometricInterpretation = pBlackIsZero 373 | samplesPerPixel = 1 374 | bitsPerSample = []uint32{16} 375 | err = encodeGray16(dst, m.Pix, d.X, d.Y, m.Stride, predictor) 376 | case *image.NRGBA: 377 | extraSamples = 2 // Unassociated alpha. 378 | err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor) 379 | case *image.NRGBA64: 380 | extraSamples = 2 // Unassociated alpha. 381 | bitsPerSample = []uint32{16, 16, 16, 16} 382 | err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor) 383 | case *image.RGBA: 384 | extraSamples = 1 // Associated alpha. 385 | err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor) 386 | case *image.RGBA64: 387 | extraSamples = 1 // Associated alpha. 388 | bitsPerSample = []uint32{16, 16, 16, 16} 389 | err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor) 390 | default: 391 | extraSamples = 1 // Associated alpha. 392 | err = encode(dst, m, predictor) 393 | } 394 | if err != nil { 395 | return err 396 | } 397 | 398 | if compression != cNone { 399 | if err = dst.(io.Closer).Close(); err != nil { 400 | return err 401 | } 402 | imageLen = buf.Len() 403 | if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil { 404 | return err 405 | } 406 | if _, err = buf.WriteTo(w); err != nil { 407 | return err 408 | } 409 | } 410 | 411 | ifd := []ifdEntry{ 412 | {tImageWidth, dtShort, []uint32{uint32(d.X)}}, 413 | {tImageLength, dtShort, []uint32{uint32(d.Y)}}, 414 | {tBitsPerSample, dtShort, bitsPerSample}, 415 | {tCompression, dtShort, []uint32{compression}}, 416 | {tPhotometricInterpretation, dtShort, []uint32{photometricInterpretation}}, 417 | {tStripOffsets, dtLong, []uint32{8}}, 418 | {tSamplesPerPixel, dtShort, []uint32{samplesPerPixel}}, 419 | {tRowsPerStrip, dtShort, []uint32{uint32(d.Y)}}, 420 | {tStripByteCounts, dtLong, []uint32{uint32(imageLen)}}, 421 | // There is currently no support for storing the image 422 | // resolution, so give a bogus value of 72x72 dpi. 423 | {tXResolution, dtRational, []uint32{72, 1}}, 424 | {tYResolution, dtRational, []uint32{72, 1}}, 425 | {tResolutionUnit, dtShort, []uint32{resPerInch}}, 426 | } 427 | if pr != prNone { 428 | ifd = append(ifd, ifdEntry{tPredictor, dtShort, []uint32{pr}}) 429 | } 430 | if len(colorMap) != 0 { 431 | ifd = append(ifd, ifdEntry{tColorMap, dtShort, colorMap}) 432 | } 433 | if extraSamples > 0 { 434 | ifd = append(ifd, ifdEntry{tExtraSamples, dtShort, []uint32{extraSamples}}) 435 | } 436 | 437 | return writeIFD(w, imageLen+8, ifd) 438 | } 439 | --------------------------------------------------------------------------------