vendor: update golang.org/x/image

This commit is contained in:
mappu 2018-12-31 16:50:06 +13:00
parent 92e0c58b22
commit 161914c34c
192 changed files with 0 additions and 146726 deletions

View File

@ -1,10 +0,0 @@
# Treat all files in this repo as binary, with no git magic updating
# line endings. Windows users contributing to Go will need to use a
# modern version of git and editors capable of LF line endings.
#
# We'll prevent accidental CRLF line endings from entering the repo
# via the git-review gofmt checks.
#
# See golang.org/issue/9281
* -text

View File

@ -1,2 +0,0 @@
# Add no patterns to .hgignore except for files generated by the build.
last-change

View File

@ -1,26 +0,0 @@
# Contributing to Go
Go is an open source project.
It is the work of hundreds of contributors. We appreciate your help!
## Filing issues
When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
1. What version of Go are you using (`go version`)?
2. What operating system and processor architecture are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
## Contributing code
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
before sending patches.
Unless otherwise noted, the Go source files are distributed under
the BSD-style license found in the LICENSE file.

17
vendor/golang.org/x/image/README.md generated vendored
View File

@ -1,17 +0,0 @@
# Go Images
This repository holds supplementary Go image libraries.
## Download/Install
The easiest way to install is to run `go get -u golang.org/x/image/...`. You can
also manually git clone the repository to `$GOPATH/src/golang.org/x/image`.
## Report Issues / Send Patches
This repository uses Gerrit for code changes. To learn how to submit changes to
this repository, see https://golang.org/doc/contribute.html.
The main issue tracker for the image repository is located at
https://github.com/golang/go/issues. Prefix your issue with "x/image:" in the
subject line, so it is easy to find.

View File

@ -1,75 +0,0 @@
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bmp
import (
"fmt"
"image"
"os"
"testing"
_ "image/png"
)
const testdataDir = "../testdata/"
func compare(t *testing.T, img0, img1 image.Image) error {
b := img1.Bounds()
if !b.Eq(img0.Bounds()) {
return fmt.Errorf("wrong image size: want %s, got %s", img0.Bounds(), b)
}
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
c0 := img0.At(x, y)
c1 := img1.At(x, y)
r0, g0, b0, a0 := c0.RGBA()
r1, g1, b1, a1 := c1.RGBA()
if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
return fmt.Errorf("pixel at (%d, %d) has wrong color: want %v, got %v", x, y, c0, c1)
}
}
}
return nil
}
// TestDecode tests that decoding a PNG image and a BMP image result in the
// same pixel data.
func TestDecode(t *testing.T) {
testCases := []string{
"video-001",
"yellow_rose-small",
}
for _, tc := range testCases {
f0, err := os.Open(testdataDir + tc + ".png")
if err != nil {
t.Errorf("%s: Open PNG: %v", tc, err)
continue
}
defer f0.Close()
img0, _, err := image.Decode(f0)
if err != nil {
t.Errorf("%s: Decode PNG: %v", tc, err)
continue
}
f1, err := os.Open(testdataDir + tc + ".bmp")
if err != nil {
t.Errorf("%s: Open BMP: %v", tc, err)
continue
}
defer f1.Close()
img1, _, err := image.Decode(f1)
if err != nil {
t.Errorf("%s: Decode BMP: %v", tc, err)
continue
}
if err := compare(t, img0, img1); err != nil {
t.Errorf("%s: %v", tc, err)
continue
}
}
}

View File

@ -1,91 +0,0 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bmp
import (
"bytes"
"fmt"
"image"
"io/ioutil"
"os"
"testing"
"time"
)
func openImage(filename string) (image.Image, error) {
f, err := os.Open(testdataDir + filename)
if err != nil {
return nil, err
}
defer f.Close()
return Decode(f)
}
func TestEncode(t *testing.T) {
img0, err := openImage("video-001.bmp")
if err != nil {
t.Fatal(err)
}
buf := new(bytes.Buffer)
err = Encode(buf, img0)
if err != nil {
t.Fatal(err)
}
img1, err := Decode(buf)
if err != nil {
t.Fatal(err)
}
compare(t, img0, img1)
}
// TestZeroWidthVeryLargeHeight tests that encoding and decoding a degenerate
// image with zero width but over one billion pixels in height is faster than
// naively calling an io.Reader or io.Writer method once per row.
func TestZeroWidthVeryLargeHeight(t *testing.T) {
c := make(chan error, 1)
go func() {
b := image.Rect(0, 0, 0, 0x3fffffff)
var buf bytes.Buffer
if err := Encode(&buf, image.NewRGBA(b)); err != nil {
c <- err
return
}
m, err := Decode(&buf)
if err != nil {
c <- err
return
}
if got := m.Bounds(); got != b {
c <- fmt.Errorf("bounds: got %v, want %v", got, b)
return
}
c <- nil
}()
select {
case err := <-c:
if err != nil {
t.Fatal(err)
}
case <-time.After(3 * time.Second):
t.Fatalf("timed out")
}
}
// BenchmarkEncode benchmarks the encoding of an image.
func BenchmarkEncode(b *testing.B) {
img, err := openImage("video-001.bmp")
if err != nil {
b.Fatal(err)
}
s := img.Bounds().Size()
b.SetBytes(int64(s.X * s.Y * 4))
b.ResetTimer()
for i := 0; i < b.N; i++ {
Encode(ioutil.Discard, img)
}
}

View File

@ -1,215 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
//
// This build tag means that "go install golang.org/x/image/..." doesn't
// install this manual test. Use "go run main.go" to explicitly run it.
// Program webp-manual-test checks that the Go WEBP library's decodings match
// the C WEBP library's.
package main // import "golang.org/x/image/cmd/webp-manual-test"
import (
"bytes"
"encoding/hex"
"flag"
"fmt"
"image"
"io"
"log"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"golang.org/x/image/webp"
)
var (
dwebp = flag.String("dwebp", "/usr/bin/dwebp", "path to the dwebp program "+
"installed from https://developers.google.com/speed/webp/download")
testdata = flag.String("testdata", "", "path to the libwebp-test-data directory "+
"checked out from https://chromium.googlesource.com/webm/libwebp-test-data")
)
func main() {
flag.Parse()
if err := checkDwebp(); err != nil {
flag.Usage()
log.Fatal(err)
}
if *testdata == "" {
flag.Usage()
log.Fatal("testdata flag was not specified")
}
f, err := os.Open(*testdata)
if err != nil {
log.Fatalf("Open: %v", err)
}
defer f.Close()
names, err := f.Readdirnames(-1)
if err != nil {
log.Fatalf("Readdirnames: %v", err)
}
sort.Strings(names)
nFail, nPass := 0, 0
for _, name := range names {
if !strings.HasSuffix(name, "webp") {
continue
}
if err := test(name); err != nil {
fmt.Printf("FAIL\t%s\t%v\n", name, err)
nFail++
} else {
fmt.Printf("PASS\t%s\n", name)
nPass++
}
}
fmt.Printf("%d PASS, %d FAIL, %d TOTAL\n", nPass, nFail, nPass+nFail)
if nFail != 0 {
os.Exit(1)
}
}
func checkDwebp() error {
if *dwebp == "" {
return fmt.Errorf("dwebp flag was not specified")
}
if _, err := os.Stat(*dwebp); err != nil {
return fmt.Errorf("could not find dwebp program at %q", *dwebp)
}
b, err := exec.Command(*dwebp, "-version").Output()
if err != nil {
return fmt.Errorf("could not determine the dwebp program version for %q: %v", *dwebp, err)
}
switch s := string(bytes.TrimSpace(b)); s {
case "0.4.0", "0.4.1", "0.4.2":
return fmt.Errorf("the dwebp program version %q for %q has a known bug "+
"(https://bugs.chromium.org/p/webp/issues/detail?id=239). Please use a newer version.", s, *dwebp)
}
return nil
}
// test tests a single WEBP image.
func test(name string) error {
filename := filepath.Join(*testdata, name)
f, err := os.Open(filename)
if err != nil {
return fmt.Errorf("Open: %v", err)
}
defer f.Close()
gotImage, err := webp.Decode(f)
if err != nil {
return fmt.Errorf("Decode: %v", err)
}
format, encode := "-pgm", encodePGM
if _, lossless := gotImage.(*image.NRGBA); lossless {
format, encode = "-pam", encodePAM
}
got, err := encode(gotImage)
if err != nil {
return fmt.Errorf("encode: %v", err)
}
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
c := exec.Command(*dwebp, filename, format, "-o", "/dev/stdout")
c.Stdout = stdout
c.Stderr = stderr
if err := c.Run(); err != nil {
os.Stderr.Write(stderr.Bytes())
return fmt.Errorf("executing dwebp: %v", err)
}
want := stdout.Bytes()
if len(got) != len(want) {
return fmt.Errorf("encodings have different length: got %d, want %d", len(got), len(want))
}
for i, g := range got {
if w := want[i]; g != w {
return fmt.Errorf("encodings differ at position 0x%x: got 0x%02x, want 0x%02x", i, g, w)
}
}
return nil
}
// encodePAM encodes gotImage in the PAM format.
func encodePAM(gotImage image.Image) ([]byte, error) {
m, ok := gotImage.(*image.NRGBA)
if !ok {
return nil, fmt.Errorf("lossless image did not decode to an *image.NRGBA")
}
b := m.Bounds()
w, h := b.Dx(), b.Dy()
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n", w, h)
for y := b.Min.Y; y < b.Max.Y; y++ {
o := m.PixOffset(b.Min.X, y)
buf.Write(m.Pix[o : o+4*w])
}
return buf.Bytes(), nil
}
// encodePGM encodes gotImage in the PGM format in the IMC4 layout.
func encodePGM(gotImage image.Image) ([]byte, error) {
var (
m *image.YCbCr
ma *image.NYCbCrA
)
switch g := gotImage.(type) {
case *image.YCbCr:
m = g
case *image.NYCbCrA:
m = &g.YCbCr
ma = g
default:
return nil, fmt.Errorf("lossy image did not decode to an *image.YCbCr")
}
if m.SubsampleRatio != image.YCbCrSubsampleRatio420 {
return nil, fmt.Errorf("lossy image did not decode to a 4:2:0 YCbCr")
}
b := m.Bounds()
w, h := b.Dx(), b.Dy()
w2, h2 := (w+1)/2, (h+1)/2
outW, outH := 2*w2, h+h2
if ma != nil {
outH += h
}
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "P5\n%d %d\n255\n", outW, outH)
for y := b.Min.Y; y < b.Max.Y; y++ {
o := m.YOffset(b.Min.X, y)
buf.Write(m.Y[o : o+w])
if w&1 != 0 {
buf.WriteByte(0x00)
}
}
for y := b.Min.Y; y < b.Max.Y; y += 2 {
o := m.COffset(b.Min.X, y)
buf.Write(m.Cb[o : o+w2])
buf.Write(m.Cr[o : o+w2])
}
if ma != nil {
for y := b.Min.Y; y < b.Max.Y; y++ {
o := ma.AOffset(b.Min.X, y)
buf.Write(ma.A[o : o+w])
if w&1 != 0 {
buf.WriteByte(0x00)
}
}
}
return buf.Bytes(), nil
}
// dump can be useful for debugging.
func dump(w io.Writer, b []byte) {
h := hex.Dumper(w)
h.Write(b)
h.Close()
}

View File

@ -1 +0,0 @@
issuerepo: golang/go

View File

@ -1,10 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go
// Package colornames provides named colors as defined in the SVG 1.1 spec.
//
// See http://www.w3.org/TR/SVG/types.html#ColorKeywords
package colornames

View File

@ -1,42 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package colornames
import (
"image/color"
"testing"
)
func TestColornames(t *testing.T) {
if len(Map) != len(Names) {
t.Fatalf("Map and Names have different length: %d vs %d", len(Map), len(Names))
}
for name, want := range testCases {
got, ok := Map[name]
if !ok {
t.Errorf("Did not find %s", name)
continue
}
if got != want {
t.Errorf("%s:\ngot %v\nwant %v", name, got, want)
}
}
}
var testCases = map[string]color.RGBA{
"aliceblue": color.RGBA{240, 248, 255, 255},
"crimson": color.RGBA{220, 20, 60, 255},
"darkorange": color.RGBA{255, 140, 0, 255},
"deepskyblue": color.RGBA{0, 191, 255, 255},
"greenyellow": color.RGBA{173, 255, 47, 255},
"lightgrey": color.RGBA{211, 211, 211, 255},
"lightpink": color.RGBA{255, 182, 193, 255},
"mediumseagreen": color.RGBA{60, 179, 113, 255},
"olivedrab": color.RGBA{107, 142, 35, 255},
"purple": color.RGBA{128, 0, 128, 255},
"slategrey": color.RGBA{112, 128, 144, 255},
"yellowgreen": color.RGBA{154, 205, 50, 255},
}

View File

@ -1,197 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// This program generates table.go from
// http://www.w3.org/TR/SVG/types.html#ColorKeywords
package main
import (
"bytes"
"fmt"
"go/format"
"image/color"
"io"
"io/ioutil"
"log"
"net/http"
"regexp"
"sort"
"strconv"
"strings"
"golang.org/x/net/html"
"golang.org/x/net/html/atom"
)
// matchFunc matches HTML nodes.
type matchFunc func(*html.Node) bool
// appendAll recursively traverses the parse tree rooted under the provided
// node and appends all nodes matched by the matchFunc to dst.
func appendAll(dst []*html.Node, n *html.Node, mf matchFunc) []*html.Node {
if mf(n) {
dst = append(dst, n)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
dst = appendAll(dst, c, mf)
}
return dst
}
// matchAtom returns a matchFunc that matches a Node with the specified Atom.
func matchAtom(a atom.Atom) matchFunc {
return func(n *html.Node) bool {
return n.DataAtom == a
}
}
// matchAtomAttr returns a matchFunc that matches a Node with the specified
// Atom and a html.Attribute's namespace, key and value.
func matchAtomAttr(a atom.Atom, namespace, key, value string) matchFunc {
return func(n *html.Node) bool {
return n.DataAtom == a && getAttr(n, namespace, key) == value
}
}
// getAttr fetches the value of a html.Attribute for a given namespace and key.
func getAttr(n *html.Node, namespace, key string) string {
for _, attr := range n.Attr {
if attr.Namespace == namespace && attr.Key == key {
return attr.Val
}
}
return ""
}
// re extracts RGB values from strings like "rgb( 0, 223, 128)".
var re = regexp.MustCompile(`rgb\(\s*([0-9]+),\s*([0-9]+),\s*([0-9]+)\)`)
// parseRGB parses a color from a string like "rgb( 0, 233, 128)". It sets
// the alpha value of the color to full opacity.
func parseRGB(s string) (color.RGBA, error) {
m := re.FindStringSubmatch(s)
if m == nil {
return color.RGBA{}, fmt.Errorf("malformed color: %q", s)
}
var rgb [3]uint8
for i, t := range m[1:] {
num, err := strconv.ParseUint(t, 10, 8)
if err != nil {
return color.RGBA{}, fmt.Errorf("malformed value %q in %q: %s", t, s, err)
}
rgb[i] = uint8(num)
}
return color.RGBA{rgb[0], rgb[1], rgb[2], 0xFF}, nil
}
// extractSVGColors extracts named colors from the parse tree of the SVG 1.1
// spec HTML document "Chapter 4: Basic data types and interfaces".
func extractSVGColors(tree *html.Node) (map[string]color.RGBA, error) {
ret := make(map[string]color.RGBA)
// Find the tables which store the color keywords in the parse tree.
colorTables := appendAll(nil, tree, func(n *html.Node) bool {
return n.DataAtom == atom.Table && strings.Contains(getAttr(n, "", "summary"), "color keywords part")
})
for _, table := range colorTables {
// Color names and values are stored in TextNodes within spans in each row.
for _, tr := range appendAll(nil, table, matchAtom(atom.Tr)) {
nameSpan := appendAll(nil, tr, matchAtomAttr(atom.Span, "", "class", "prop-value"))
valueSpan := appendAll(nil, tr, matchAtomAttr(atom.Span, "", "class", "color-keyword-value"))
// Since SVG 1.1 defines an odd number of colors, the last row
// in the second table does not have contents. We skip it.
if len(nameSpan) != 1 || len(valueSpan) != 1 {
continue
}
n, v := nameSpan[0].FirstChild, valueSpan[0].FirstChild
// This sanity checks for the existence of TextNodes under spans.
if n == nil || n.Type != html.TextNode || v == nil || v.Type != html.TextNode {
return nil, fmt.Errorf("extractSVGColors: couldn't find name/value text nodes")
}
val, err := parseRGB(v.Data)
if err != nil {
return nil, fmt.Errorf("extractSVGColors: couldn't parse name/value %q/%q: %s", n.Data, v.Data, err)
}
ret[n.Data] = val
}
}
return ret, nil
}
const preamble = `// generated by go generate; DO NOT EDIT.
package colornames
import "image/color"
`
// WriteColorNames writes table.go.
func writeColorNames(w io.Writer, m map[string]color.RGBA) {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
fmt.Fprintln(w, preamble)
fmt.Fprintln(w, "// Map contains named colors defined in the SVG 1.1 spec.")
fmt.Fprintln(w, "var Map = map[string]color.RGBA{")
for _, k := range keys {
c := m[k]
fmt.Fprintf(w, "%q:color.RGBA{%#02x, %#02x, %#02x, %#02x}, // rgb(%d, %d, %d)\n",
k, c.R, c.G, c.B, c.A, c.R, c.G, c.B)
}
fmt.Fprintln(w, "}\n")
fmt.Fprintln(w, "// Names contains the color names defined in the SVG 1.1 spec.")
fmt.Fprintln(w, "var Names = []string{")
for _, k := range keys {
fmt.Fprintf(w, "%q,\n", k)
}
fmt.Fprintln(w, "}\n")
fmt.Fprintln(w, "var (")
for _, k := range keys {
c := m[k]
// Make the upper case version of k: "Darkred" instead of "darkred".
k = string(k[0]-0x20) + k[1:]
fmt.Fprintf(w, "%s=color.RGBA{%#02x, %#02x, %#02x, %#02x} // rgb(%d, %d, %d)\n",
k, c.R, c.G, c.B, c.A, c.R, c.G, c.B)
}
fmt.Fprintln(w, ")")
}
const url = "http://www.w3.org/TR/SVG/types.html"
func main() {
res, err := http.Get(url)
if err != nil {
log.Fatalf("Couldn't read from %s: %s\n", url, err)
}
defer res.Body.Close()
tree, err := html.Parse(res.Body)
if err != nil {
log.Fatalf("Couldn't parse %s: %s\n", url, err)
}
colors, err := extractSVGColors(tree)
if err != nil {
log.Fatalf("Couldn't extract colors: %s\n", err)
}
buf := &bytes.Buffer{}
writeColorNames(buf, colors)
fmted, err := format.Source(buf.Bytes())
if err != nil {
log.Fatalf("Error while formatting code: %s\n", err)
}
if err := ioutil.WriteFile("table.go", fmted, 0644); err != nil {
log.Fatalf("Error writing table.go: %s\n", err)
}
}

View File

@ -1,457 +0,0 @@
// generated by go generate; DO NOT EDIT.
package colornames
import "image/color"
// Map contains named colors defined in the SVG 1.1 spec.
var Map = map[string]color.RGBA{
"aliceblue": color.RGBA{0xf0, 0xf8, 0xff, 0xff}, // rgb(240, 248, 255)
"antiquewhite": color.RGBA{0xfa, 0xeb, 0xd7, 0xff}, // rgb(250, 235, 215)
"aqua": color.RGBA{0x00, 0xff, 0xff, 0xff}, // rgb(0, 255, 255)
"aquamarine": color.RGBA{0x7f, 0xff, 0xd4, 0xff}, // rgb(127, 255, 212)
"azure": color.RGBA{0xf0, 0xff, 0xff, 0xff}, // rgb(240, 255, 255)
"beige": color.RGBA{0xf5, 0xf5, 0xdc, 0xff}, // rgb(245, 245, 220)
"bisque": color.RGBA{0xff, 0xe4, 0xc4, 0xff}, // rgb(255, 228, 196)
"black": color.RGBA{0x00, 0x00, 0x00, 0xff}, // rgb(0, 0, 0)
"blanchedalmond": color.RGBA{0xff, 0xeb, 0xcd, 0xff}, // rgb(255, 235, 205)
"blue": color.RGBA{0x00, 0x00, 0xff, 0xff}, // rgb(0, 0, 255)
"blueviolet": color.RGBA{0x8a, 0x2b, 0xe2, 0xff}, // rgb(138, 43, 226)
"brown": color.RGBA{0xa5, 0x2a, 0x2a, 0xff}, // rgb(165, 42, 42)
"burlywood": color.RGBA{0xde, 0xb8, 0x87, 0xff}, // rgb(222, 184, 135)
"cadetblue": color.RGBA{0x5f, 0x9e, 0xa0, 0xff}, // rgb(95, 158, 160)
"chartreuse": color.RGBA{0x7f, 0xff, 0x00, 0xff}, // rgb(127, 255, 0)
"chocolate": color.RGBA{0xd2, 0x69, 0x1e, 0xff}, // rgb(210, 105, 30)
"coral": color.RGBA{0xff, 0x7f, 0x50, 0xff}, // rgb(255, 127, 80)
"cornflowerblue": color.RGBA{0x64, 0x95, 0xed, 0xff}, // rgb(100, 149, 237)
"cornsilk": color.RGBA{0xff, 0xf8, 0xdc, 0xff}, // rgb(255, 248, 220)
"crimson": color.RGBA{0xdc, 0x14, 0x3c, 0xff}, // rgb(220, 20, 60)
"cyan": color.RGBA{0x00, 0xff, 0xff, 0xff}, // rgb(0, 255, 255)
"darkblue": color.RGBA{0x00, 0x00, 0x8b, 0xff}, // rgb(0, 0, 139)
"darkcyan": color.RGBA{0x00, 0x8b, 0x8b, 0xff}, // rgb(0, 139, 139)
"darkgoldenrod": color.RGBA{0xb8, 0x86, 0x0b, 0xff}, // rgb(184, 134, 11)
"darkgray": color.RGBA{0xa9, 0xa9, 0xa9, 0xff}, // rgb(169, 169, 169)
"darkgreen": color.RGBA{0x00, 0x64, 0x00, 0xff}, // rgb(0, 100, 0)
"darkgrey": color.RGBA{0xa9, 0xa9, 0xa9, 0xff}, // rgb(169, 169, 169)
"darkkhaki": color.RGBA{0xbd, 0xb7, 0x6b, 0xff}, // rgb(189, 183, 107)
"darkmagenta": color.RGBA{0x8b, 0x00, 0x8b, 0xff}, // rgb(139, 0, 139)
"darkolivegreen": color.RGBA{0x55, 0x6b, 0x2f, 0xff}, // rgb(85, 107, 47)
"darkorange": color.RGBA{0xff, 0x8c, 0x00, 0xff}, // rgb(255, 140, 0)
"darkorchid": color.RGBA{0x99, 0x32, 0xcc, 0xff}, // rgb(153, 50, 204)
"darkred": color.RGBA{0x8b, 0x00, 0x00, 0xff}, // rgb(139, 0, 0)
"darksalmon": color.RGBA{0xe9, 0x96, 0x7a, 0xff}, // rgb(233, 150, 122)
"darkseagreen": color.RGBA{0x8f, 0xbc, 0x8f, 0xff}, // rgb(143, 188, 143)
"darkslateblue": color.RGBA{0x48, 0x3d, 0x8b, 0xff}, // rgb(72, 61, 139)
"darkslategray": color.RGBA{0x2f, 0x4f, 0x4f, 0xff}, // rgb(47, 79, 79)
"darkslategrey": color.RGBA{0x2f, 0x4f, 0x4f, 0xff}, // rgb(47, 79, 79)
"darkturquoise": color.RGBA{0x00, 0xce, 0xd1, 0xff}, // rgb(0, 206, 209)
"darkviolet": color.RGBA{0x94, 0x00, 0xd3, 0xff}, // rgb(148, 0, 211)
"deeppink": color.RGBA{0xff, 0x14, 0x93, 0xff}, // rgb(255, 20, 147)
"deepskyblue": color.RGBA{0x00, 0xbf, 0xff, 0xff}, // rgb(0, 191, 255)
"dimgray": color.RGBA{0x69, 0x69, 0x69, 0xff}, // rgb(105, 105, 105)
"dimgrey": color.RGBA{0x69, 0x69, 0x69, 0xff}, // rgb(105, 105, 105)
"dodgerblue": color.RGBA{0x1e, 0x90, 0xff, 0xff}, // rgb(30, 144, 255)
"firebrick": color.RGBA{0xb2, 0x22, 0x22, 0xff}, // rgb(178, 34, 34)
"floralwhite": color.RGBA{0xff, 0xfa, 0xf0, 0xff}, // rgb(255, 250, 240)
"forestgreen": color.RGBA{0x22, 0x8b, 0x22, 0xff}, // rgb(34, 139, 34)
"fuchsia": color.RGBA{0xff, 0x00, 0xff, 0xff}, // rgb(255, 0, 255)
"gainsboro": color.RGBA{0xdc, 0xdc, 0xdc, 0xff}, // rgb(220, 220, 220)
"ghostwhite": color.RGBA{0xf8, 0xf8, 0xff, 0xff}, // rgb(248, 248, 255)
"gold": color.RGBA{0xff, 0xd7, 0x00, 0xff}, // rgb(255, 215, 0)
"goldenrod": color.RGBA{0xda, 0xa5, 0x20, 0xff}, // rgb(218, 165, 32)
"gray": color.RGBA{0x80, 0x80, 0x80, 0xff}, // rgb(128, 128, 128)
"green": color.RGBA{0x00, 0x80, 0x00, 0xff}, // rgb(0, 128, 0)
"greenyellow": color.RGBA{0xad, 0xff, 0x2f, 0xff}, // rgb(173, 255, 47)
"grey": color.RGBA{0x80, 0x80, 0x80, 0xff}, // rgb(128, 128, 128)
"honeydew": color.RGBA{0xf0, 0xff, 0xf0, 0xff}, // rgb(240, 255, 240)
"hotpink": color.RGBA{0xff, 0x69, 0xb4, 0xff}, // rgb(255, 105, 180)
"indianred": color.RGBA{0xcd, 0x5c, 0x5c, 0xff}, // rgb(205, 92, 92)
"indigo": color.RGBA{0x4b, 0x00, 0x82, 0xff}, // rgb(75, 0, 130)
"ivory": color.RGBA{0xff, 0xff, 0xf0, 0xff}, // rgb(255, 255, 240)
"khaki": color.RGBA{0xf0, 0xe6, 0x8c, 0xff}, // rgb(240, 230, 140)
"lavender": color.RGBA{0xe6, 0xe6, 0xfa, 0xff}, // rgb(230, 230, 250)
"lavenderblush": color.RGBA{0xff, 0xf0, 0xf5, 0xff}, // rgb(255, 240, 245)
"lawngreen": color.RGBA{0x7c, 0xfc, 0x00, 0xff}, // rgb(124, 252, 0)
"lemonchiffon": color.RGBA{0xff, 0xfa, 0xcd, 0xff}, // rgb(255, 250, 205)
"lightblue": color.RGBA{0xad, 0xd8, 0xe6, 0xff}, // rgb(173, 216, 230)
"lightcoral": color.RGBA{0xf0, 0x80, 0x80, 0xff}, // rgb(240, 128, 128)
"lightcyan": color.RGBA{0xe0, 0xff, 0xff, 0xff}, // rgb(224, 255, 255)
"lightgoldenrodyellow": color.RGBA{0xfa, 0xfa, 0xd2, 0xff}, // rgb(250, 250, 210)
"lightgray": color.RGBA{0xd3, 0xd3, 0xd3, 0xff}, // rgb(211, 211, 211)
"lightgreen": color.RGBA{0x90, 0xee, 0x90, 0xff}, // rgb(144, 238, 144)
"lightgrey": color.RGBA{0xd3, 0xd3, 0xd3, 0xff}, // rgb(211, 211, 211)
"lightpink": color.RGBA{0xff, 0xb6, 0xc1, 0xff}, // rgb(255, 182, 193)
"lightsalmon": color.RGBA{0xff, 0xa0, 0x7a, 0xff}, // rgb(255, 160, 122)
"lightseagreen": color.RGBA{0x20, 0xb2, 0xaa, 0xff}, // rgb(32, 178, 170)
"lightskyblue": color.RGBA{0x87, 0xce, 0xfa, 0xff}, // rgb(135, 206, 250)
"lightslategray": color.RGBA{0x77, 0x88, 0x99, 0xff}, // rgb(119, 136, 153)
"lightslategrey": color.RGBA{0x77, 0x88, 0x99, 0xff}, // rgb(119, 136, 153)
"lightsteelblue": color.RGBA{0xb0, 0xc4, 0xde, 0xff}, // rgb(176, 196, 222)
"lightyellow": color.RGBA{0xff, 0xff, 0xe0, 0xff}, // rgb(255, 255, 224)
"lime": color.RGBA{0x00, 0xff, 0x00, 0xff}, // rgb(0, 255, 0)
"limegreen": color.RGBA{0x32, 0xcd, 0x32, 0xff}, // rgb(50, 205, 50)
"linen": color.RGBA{0xfa, 0xf0, 0xe6, 0xff}, // rgb(250, 240, 230)
"magenta": color.RGBA{0xff, 0x00, 0xff, 0xff}, // rgb(255, 0, 255)
"maroon": color.RGBA{0x80, 0x00, 0x00, 0xff}, // rgb(128, 0, 0)
"mediumaquamarine": color.RGBA{0x66, 0xcd, 0xaa, 0xff}, // rgb(102, 205, 170)
"mediumblue": color.RGBA{0x00, 0x00, 0xcd, 0xff}, // rgb(0, 0, 205)
"mediumorchid": color.RGBA{0xba, 0x55, 0xd3, 0xff}, // rgb(186, 85, 211)
"mediumpurple": color.RGBA{0x93, 0x70, 0xdb, 0xff}, // rgb(147, 112, 219)
"mediumseagreen": color.RGBA{0x3c, 0xb3, 0x71, 0xff}, // rgb(60, 179, 113)
"mediumslateblue": color.RGBA{0x7b, 0x68, 0xee, 0xff}, // rgb(123, 104, 238)
"mediumspringgreen": color.RGBA{0x00, 0xfa, 0x9a, 0xff}, // rgb(0, 250, 154)
"mediumturquoise": color.RGBA{0x48, 0xd1, 0xcc, 0xff}, // rgb(72, 209, 204)
"mediumvioletred": color.RGBA{0xc7, 0x15, 0x85, 0xff}, // rgb(199, 21, 133)
"midnightblue": color.RGBA{0x19, 0x19, 0x70, 0xff}, // rgb(25, 25, 112)
"mintcream": color.RGBA{0xf5, 0xff, 0xfa, 0xff}, // rgb(245, 255, 250)
"mistyrose": color.RGBA{0xff, 0xe4, 0xe1, 0xff}, // rgb(255, 228, 225)
"moccasin": color.RGBA{0xff, 0xe4, 0xb5, 0xff}, // rgb(255, 228, 181)
"navajowhite": color.RGBA{0xff, 0xde, 0xad, 0xff}, // rgb(255, 222, 173)
"navy": color.RGBA{0x00, 0x00, 0x80, 0xff}, // rgb(0, 0, 128)
"oldlace": color.RGBA{0xfd, 0xf5, 0xe6, 0xff}, // rgb(253, 245, 230)
"olive": color.RGBA{0x80, 0x80, 0x00, 0xff}, // rgb(128, 128, 0)
"olivedrab": color.RGBA{0x6b, 0x8e, 0x23, 0xff}, // rgb(107, 142, 35)
"orange": color.RGBA{0xff, 0xa5, 0x00, 0xff}, // rgb(255, 165, 0)
"orangered": color.RGBA{0xff, 0x45, 0x00, 0xff}, // rgb(255, 69, 0)
"orchid": color.RGBA{0xda, 0x70, 0xd6, 0xff}, // rgb(218, 112, 214)
"palegoldenrod": color.RGBA{0xee, 0xe8, 0xaa, 0xff}, // rgb(238, 232, 170)
"palegreen": color.RGBA{0x98, 0xfb, 0x98, 0xff}, // rgb(152, 251, 152)
"paleturquoise": color.RGBA{0xaf, 0xee, 0xee, 0xff}, // rgb(175, 238, 238)
"palevioletred": color.RGBA{0xdb, 0x70, 0x93, 0xff}, // rgb(219, 112, 147)
"papayawhip": color.RGBA{0xff, 0xef, 0xd5, 0xff}, // rgb(255, 239, 213)
"peachpuff": color.RGBA{0xff, 0xda, 0xb9, 0xff}, // rgb(255, 218, 185)
"peru": color.RGBA{0xcd, 0x85, 0x3f, 0xff}, // rgb(205, 133, 63)
"pink": color.RGBA{0xff, 0xc0, 0xcb, 0xff}, // rgb(255, 192, 203)
"plum": color.RGBA{0xdd, 0xa0, 0xdd, 0xff}, // rgb(221, 160, 221)
"powderblue": color.RGBA{0xb0, 0xe0, 0xe6, 0xff}, // rgb(176, 224, 230)
"purple": color.RGBA{0x80, 0x00, 0x80, 0xff}, // rgb(128, 0, 128)
"red": color.RGBA{0xff, 0x00, 0x00, 0xff}, // rgb(255, 0, 0)
"rosybrown": color.RGBA{0xbc, 0x8f, 0x8f, 0xff}, // rgb(188, 143, 143)
"royalblue": color.RGBA{0x41, 0x69, 0xe1, 0xff}, // rgb(65, 105, 225)
"saddlebrown": color.RGBA{0x8b, 0x45, 0x13, 0xff}, // rgb(139, 69, 19)
"salmon": color.RGBA{0xfa, 0x80, 0x72, 0xff}, // rgb(250, 128, 114)
"sandybrown": color.RGBA{0xf4, 0xa4, 0x60, 0xff}, // rgb(244, 164, 96)
"seagreen": color.RGBA{0x2e, 0x8b, 0x57, 0xff}, // rgb(46, 139, 87)
"seashell": color.RGBA{0xff, 0xf5, 0xee, 0xff}, // rgb(255, 245, 238)
"sienna": color.RGBA{0xa0, 0x52, 0x2d, 0xff}, // rgb(160, 82, 45)
"silver": color.RGBA{0xc0, 0xc0, 0xc0, 0xff}, // rgb(192, 192, 192)
"skyblue": color.RGBA{0x87, 0xce, 0xeb, 0xff}, // rgb(135, 206, 235)
"slateblue": color.RGBA{0x6a, 0x5a, 0xcd, 0xff}, // rgb(106, 90, 205)
"slategray": color.RGBA{0x70, 0x80, 0x90, 0xff}, // rgb(112, 128, 144)
"slategrey": color.RGBA{0x70, 0x80, 0x90, 0xff}, // rgb(112, 128, 144)
"snow": color.RGBA{0xff, 0xfa, 0xfa, 0xff}, // rgb(255, 250, 250)
"springgreen": color.RGBA{0x00, 0xff, 0x7f, 0xff}, // rgb(0, 255, 127)
"steelblue": color.RGBA{0x46, 0x82, 0xb4, 0xff}, // rgb(70, 130, 180)
"tan": color.RGBA{0xd2, 0xb4, 0x8c, 0xff}, // rgb(210, 180, 140)
"teal": color.RGBA{0x00, 0x80, 0x80, 0xff}, // rgb(0, 128, 128)
"thistle": color.RGBA{0xd8, 0xbf, 0xd8, 0xff}, // rgb(216, 191, 216)
"tomato": color.RGBA{0xff, 0x63, 0x47, 0xff}, // rgb(255, 99, 71)
"turquoise": color.RGBA{0x40, 0xe0, 0xd0, 0xff}, // rgb(64, 224, 208)
"violet": color.RGBA{0xee, 0x82, 0xee, 0xff}, // rgb(238, 130, 238)
"wheat": color.RGBA{0xf5, 0xde, 0xb3, 0xff}, // rgb(245, 222, 179)
"white": color.RGBA{0xff, 0xff, 0xff, 0xff}, // rgb(255, 255, 255)
"whitesmoke": color.RGBA{0xf5, 0xf5, 0xf5, 0xff}, // rgb(245, 245, 245)
"yellow": color.RGBA{0xff, 0xff, 0x00, 0xff}, // rgb(255, 255, 0)
"yellowgreen": color.RGBA{0x9a, 0xcd, 0x32, 0xff}, // rgb(154, 205, 50)
}
// Names contains the color names defined in the SVG 1.1 spec.
var Names = []string{
"aliceblue",
"antiquewhite",
"aqua",
"aquamarine",
"azure",
"beige",
"bisque",
"black",
"blanchedalmond",
"blue",
"blueviolet",
"brown",
"burlywood",
"cadetblue",
"chartreuse",
"chocolate",
"coral",
"cornflowerblue",
"cornsilk",
"crimson",
"cyan",
"darkblue",
"darkcyan",
"darkgoldenrod",
"darkgray",
"darkgreen",
"darkgrey",
"darkkhaki",
"darkmagenta",
"darkolivegreen",
"darkorange",
"darkorchid",
"darkred",
"darksalmon",
"darkseagreen",
"darkslateblue",
"darkslategray",
"darkslategrey",
"darkturquoise",
"darkviolet",
"deeppink",
"deepskyblue",
"dimgray",
"dimgrey",
"dodgerblue",
"firebrick",
"floralwhite",
"forestgreen",
"fuchsia",
"gainsboro",
"ghostwhite",
"gold",
"goldenrod",
"gray",
"green",
"greenyellow",
"grey",
"honeydew",
"hotpink",
"indianred",
"indigo",
"ivory",
"khaki",
"lavender",
"lavenderblush",
"lawngreen",
"lemonchiffon",
"lightblue",
"lightcoral",
"lightcyan",
"lightgoldenrodyellow",
"lightgray",
"lightgreen",
"lightgrey",
"lightpink",
"lightsalmon",
"lightseagreen",
"lightskyblue",
"lightslategray",
"lightslategrey",
"lightsteelblue",
"lightyellow",
"lime",
"limegreen",
"linen",
"magenta",
"maroon",
"mediumaquamarine",
"mediumblue",
"mediumorchid",
"mediumpurple",
"mediumseagreen",
"mediumslateblue",
"mediumspringgreen",
"mediumturquoise",
"mediumvioletred",
"midnightblue",
"mintcream",
"mistyrose",
"moccasin",
"navajowhite",
"navy",
"oldlace",
"olive",
"olivedrab",
"orange",
"orangered",
"orchid",
"palegoldenrod",
"palegreen",
"paleturquoise",
"palevioletred",
"papayawhip",
"peachpuff",
"peru",
"pink",
"plum",
"powderblue",
"purple",
"red",
"rosybrown",
"royalblue",
"saddlebrown",
"salmon",
"sandybrown",
"seagreen",
"seashell",
"sienna",
"silver",
"skyblue",
"slateblue",
"slategray",
"slategrey",
"snow",
"springgreen",
"steelblue",
"tan",
"teal",
"thistle",
"tomato",
"turquoise",
"violet",
"wheat",
"white",
"whitesmoke",
"yellow",
"yellowgreen",
}
var (
Aliceblue = color.RGBA{0xf0, 0xf8, 0xff, 0xff} // rgb(240, 248, 255)
Antiquewhite = color.RGBA{0xfa, 0xeb, 0xd7, 0xff} // rgb(250, 235, 215)
Aqua = color.RGBA{0x00, 0xff, 0xff, 0xff} // rgb(0, 255, 255)
Aquamarine = color.RGBA{0x7f, 0xff, 0xd4, 0xff} // rgb(127, 255, 212)
Azure = color.RGBA{0xf0, 0xff, 0xff, 0xff} // rgb(240, 255, 255)
Beige = color.RGBA{0xf5, 0xf5, 0xdc, 0xff} // rgb(245, 245, 220)
Bisque = color.RGBA{0xff, 0xe4, 0xc4, 0xff} // rgb(255, 228, 196)
Black = color.RGBA{0x00, 0x00, 0x00, 0xff} // rgb(0, 0, 0)
Blanchedalmond = color.RGBA{0xff, 0xeb, 0xcd, 0xff} // rgb(255, 235, 205)
Blue = color.RGBA{0x00, 0x00, 0xff, 0xff} // rgb(0, 0, 255)
Blueviolet = color.RGBA{0x8a, 0x2b, 0xe2, 0xff} // rgb(138, 43, 226)
Brown = color.RGBA{0xa5, 0x2a, 0x2a, 0xff} // rgb(165, 42, 42)
Burlywood = color.RGBA{0xde, 0xb8, 0x87, 0xff} // rgb(222, 184, 135)
Cadetblue = color.RGBA{0x5f, 0x9e, 0xa0, 0xff} // rgb(95, 158, 160)
Chartreuse = color.RGBA{0x7f, 0xff, 0x00, 0xff} // rgb(127, 255, 0)
Chocolate = color.RGBA{0xd2, 0x69, 0x1e, 0xff} // rgb(210, 105, 30)
Coral = color.RGBA{0xff, 0x7f, 0x50, 0xff} // rgb(255, 127, 80)
Cornflowerblue = color.RGBA{0x64, 0x95, 0xed, 0xff} // rgb(100, 149, 237)
Cornsilk = color.RGBA{0xff, 0xf8, 0xdc, 0xff} // rgb(255, 248, 220)
Crimson = color.RGBA{0xdc, 0x14, 0x3c, 0xff} // rgb(220, 20, 60)
Cyan = color.RGBA{0x00, 0xff, 0xff, 0xff} // rgb(0, 255, 255)
Darkblue = color.RGBA{0x00, 0x00, 0x8b, 0xff} // rgb(0, 0, 139)
Darkcyan = color.RGBA{0x00, 0x8b, 0x8b, 0xff} // rgb(0, 139, 139)
Darkgoldenrod = color.RGBA{0xb8, 0x86, 0x0b, 0xff} // rgb(184, 134, 11)
Darkgray = color.RGBA{0xa9, 0xa9, 0xa9, 0xff} // rgb(169, 169, 169)
Darkgreen = color.RGBA{0x00, 0x64, 0x00, 0xff} // rgb(0, 100, 0)
Darkgrey = color.RGBA{0xa9, 0xa9, 0xa9, 0xff} // rgb(169, 169, 169)
Darkkhaki = color.RGBA{0xbd, 0xb7, 0x6b, 0xff} // rgb(189, 183, 107)
Darkmagenta = color.RGBA{0x8b, 0x00, 0x8b, 0xff} // rgb(139, 0, 139)
Darkolivegreen = color.RGBA{0x55, 0x6b, 0x2f, 0xff} // rgb(85, 107, 47)
Darkorange = color.RGBA{0xff, 0x8c, 0x00, 0xff} // rgb(255, 140, 0)
Darkorchid = color.RGBA{0x99, 0x32, 0xcc, 0xff} // rgb(153, 50, 204)
Darkred = color.RGBA{0x8b, 0x00, 0x00, 0xff} // rgb(139, 0, 0)
Darksalmon = color.RGBA{0xe9, 0x96, 0x7a, 0xff} // rgb(233, 150, 122)
Darkseagreen = color.RGBA{0x8f, 0xbc, 0x8f, 0xff} // rgb(143, 188, 143)
Darkslateblue = color.RGBA{0x48, 0x3d, 0x8b, 0xff} // rgb(72, 61, 139)
Darkslategray = color.RGBA{0x2f, 0x4f, 0x4f, 0xff} // rgb(47, 79, 79)
Darkslategrey = color.RGBA{0x2f, 0x4f, 0x4f, 0xff} // rgb(47, 79, 79)
Darkturquoise = color.RGBA{0x00, 0xce, 0xd1, 0xff} // rgb(0, 206, 209)
Darkviolet = color.RGBA{0x94, 0x00, 0xd3, 0xff} // rgb(148, 0, 211)
Deeppink = color.RGBA{0xff, 0x14, 0x93, 0xff} // rgb(255, 20, 147)
Deepskyblue = color.RGBA{0x00, 0xbf, 0xff, 0xff} // rgb(0, 191, 255)
Dimgray = color.RGBA{0x69, 0x69, 0x69, 0xff} // rgb(105, 105, 105)
Dimgrey = color.RGBA{0x69, 0x69, 0x69, 0xff} // rgb(105, 105, 105)
Dodgerblue = color.RGBA{0x1e, 0x90, 0xff, 0xff} // rgb(30, 144, 255)
Firebrick = color.RGBA{0xb2, 0x22, 0x22, 0xff} // rgb(178, 34, 34)
Floralwhite = color.RGBA{0xff, 0xfa, 0xf0, 0xff} // rgb(255, 250, 240)
Forestgreen = color.RGBA{0x22, 0x8b, 0x22, 0xff} // rgb(34, 139, 34)
Fuchsia = color.RGBA{0xff, 0x00, 0xff, 0xff} // rgb(255, 0, 255)
Gainsboro = color.RGBA{0xdc, 0xdc, 0xdc, 0xff} // rgb(220, 220, 220)
Ghostwhite = color.RGBA{0xf8, 0xf8, 0xff, 0xff} // rgb(248, 248, 255)
Gold = color.RGBA{0xff, 0xd7, 0x00, 0xff} // rgb(255, 215, 0)
Goldenrod = color.RGBA{0xda, 0xa5, 0x20, 0xff} // rgb(218, 165, 32)
Gray = color.RGBA{0x80, 0x80, 0x80, 0xff} // rgb(128, 128, 128)
Green = color.RGBA{0x00, 0x80, 0x00, 0xff} // rgb(0, 128, 0)
Greenyellow = color.RGBA{0xad, 0xff, 0x2f, 0xff} // rgb(173, 255, 47)
Grey = color.RGBA{0x80, 0x80, 0x80, 0xff} // rgb(128, 128, 128)
Honeydew = color.RGBA{0xf0, 0xff, 0xf0, 0xff} // rgb(240, 255, 240)
Hotpink = color.RGBA{0xff, 0x69, 0xb4, 0xff} // rgb(255, 105, 180)
Indianred = color.RGBA{0xcd, 0x5c, 0x5c, 0xff} // rgb(205, 92, 92)
Indigo = color.RGBA{0x4b, 0x00, 0x82, 0xff} // rgb(75, 0, 130)
Ivory = color.RGBA{0xff, 0xff, 0xf0, 0xff} // rgb(255, 255, 240)
Khaki = color.RGBA{0xf0, 0xe6, 0x8c, 0xff} // rgb(240, 230, 140)
Lavender = color.RGBA{0xe6, 0xe6, 0xfa, 0xff} // rgb(230, 230, 250)
Lavenderblush = color.RGBA{0xff, 0xf0, 0xf5, 0xff} // rgb(255, 240, 245)
Lawngreen = color.RGBA{0x7c, 0xfc, 0x00, 0xff} // rgb(124, 252, 0)
Lemonchiffon = color.RGBA{0xff, 0xfa, 0xcd, 0xff} // rgb(255, 250, 205)
Lightblue = color.RGBA{0xad, 0xd8, 0xe6, 0xff} // rgb(173, 216, 230)
Lightcoral = color.RGBA{0xf0, 0x80, 0x80, 0xff} // rgb(240, 128, 128)
Lightcyan = color.RGBA{0xe0, 0xff, 0xff, 0xff} // rgb(224, 255, 255)
Lightgoldenrodyellow = color.RGBA{0xfa, 0xfa, 0xd2, 0xff} // rgb(250, 250, 210)
Lightgray = color.RGBA{0xd3, 0xd3, 0xd3, 0xff} // rgb(211, 211, 211)
Lightgreen = color.RGBA{0x90, 0xee, 0x90, 0xff} // rgb(144, 238, 144)
Lightgrey = color.RGBA{0xd3, 0xd3, 0xd3, 0xff} // rgb(211, 211, 211)
Lightpink = color.RGBA{0xff, 0xb6, 0xc1, 0xff} // rgb(255, 182, 193)
Lightsalmon = color.RGBA{0xff, 0xa0, 0x7a, 0xff} // rgb(255, 160, 122)
Lightseagreen = color.RGBA{0x20, 0xb2, 0xaa, 0xff} // rgb(32, 178, 170)
Lightskyblue = color.RGBA{0x87, 0xce, 0xfa, 0xff} // rgb(135, 206, 250)
Lightslategray = color.RGBA{0x77, 0x88, 0x99, 0xff} // rgb(119, 136, 153)
Lightslategrey = color.RGBA{0x77, 0x88, 0x99, 0xff} // rgb(119, 136, 153)
Lightsteelblue = color.RGBA{0xb0, 0xc4, 0xde, 0xff} // rgb(176, 196, 222)
Lightyellow = color.RGBA{0xff, 0xff, 0xe0, 0xff} // rgb(255, 255, 224)
Lime = color.RGBA{0x00, 0xff, 0x00, 0xff} // rgb(0, 255, 0)
Limegreen = color.RGBA{0x32, 0xcd, 0x32, 0xff} // rgb(50, 205, 50)
Linen = color.RGBA{0xfa, 0xf0, 0xe6, 0xff} // rgb(250, 240, 230)
Magenta = color.RGBA{0xff, 0x00, 0xff, 0xff} // rgb(255, 0, 255)
Maroon = color.RGBA{0x80, 0x00, 0x00, 0xff} // rgb(128, 0, 0)
Mediumaquamarine = color.RGBA{0x66, 0xcd, 0xaa, 0xff} // rgb(102, 205, 170)
Mediumblue = color.RGBA{0x00, 0x00, 0xcd, 0xff} // rgb(0, 0, 205)
Mediumorchid = color.RGBA{0xba, 0x55, 0xd3, 0xff} // rgb(186, 85, 211)
Mediumpurple = color.RGBA{0x93, 0x70, 0xdb, 0xff} // rgb(147, 112, 219)
Mediumseagreen = color.RGBA{0x3c, 0xb3, 0x71, 0xff} // rgb(60, 179, 113)
Mediumslateblue = color.RGBA{0x7b, 0x68, 0xee, 0xff} // rgb(123, 104, 238)
Mediumspringgreen = color.RGBA{0x00, 0xfa, 0x9a, 0xff} // rgb(0, 250, 154)
Mediumturquoise = color.RGBA{0x48, 0xd1, 0xcc, 0xff} // rgb(72, 209, 204)
Mediumvioletred = color.RGBA{0xc7, 0x15, 0x85, 0xff} // rgb(199, 21, 133)
Midnightblue = color.RGBA{0x19, 0x19, 0x70, 0xff} // rgb(25, 25, 112)
Mintcream = color.RGBA{0xf5, 0xff, 0xfa, 0xff} // rgb(245, 255, 250)
Mistyrose = color.RGBA{0xff, 0xe4, 0xe1, 0xff} // rgb(255, 228, 225)
Moccasin = color.RGBA{0xff, 0xe4, 0xb5, 0xff} // rgb(255, 228, 181)
Navajowhite = color.RGBA{0xff, 0xde, 0xad, 0xff} // rgb(255, 222, 173)
Navy = color.RGBA{0x00, 0x00, 0x80, 0xff} // rgb(0, 0, 128)
Oldlace = color.RGBA{0xfd, 0xf5, 0xe6, 0xff} // rgb(253, 245, 230)
Olive = color.RGBA{0x80, 0x80, 0x00, 0xff} // rgb(128, 128, 0)
Olivedrab = color.RGBA{0x6b, 0x8e, 0x23, 0xff} // rgb(107, 142, 35)
Orange = color.RGBA{0xff, 0xa5, 0x00, 0xff} // rgb(255, 165, 0)
Orangered = color.RGBA{0xff, 0x45, 0x00, 0xff} // rgb(255, 69, 0)
Orchid = color.RGBA{0xda, 0x70, 0xd6, 0xff} // rgb(218, 112, 214)
Palegoldenrod = color.RGBA{0xee, 0xe8, 0xaa, 0xff} // rgb(238, 232, 170)
Palegreen = color.RGBA{0x98, 0xfb, 0x98, 0xff} // rgb(152, 251, 152)
Paleturquoise = color.RGBA{0xaf, 0xee, 0xee, 0xff} // rgb(175, 238, 238)
Palevioletred = color.RGBA{0xdb, 0x70, 0x93, 0xff} // rgb(219, 112, 147)
Papayawhip = color.RGBA{0xff, 0xef, 0xd5, 0xff} // rgb(255, 239, 213)
Peachpuff = color.RGBA{0xff, 0xda, 0xb9, 0xff} // rgb(255, 218, 185)
Peru = color.RGBA{0xcd, 0x85, 0x3f, 0xff} // rgb(205, 133, 63)
Pink = color.RGBA{0xff, 0xc0, 0xcb, 0xff} // rgb(255, 192, 203)
Plum = color.RGBA{0xdd, 0xa0, 0xdd, 0xff} // rgb(221, 160, 221)
Powderblue = color.RGBA{0xb0, 0xe0, 0xe6, 0xff} // rgb(176, 224, 230)
Purple = color.RGBA{0x80, 0x00, 0x80, 0xff} // rgb(128, 0, 128)
Red = color.RGBA{0xff, 0x00, 0x00, 0xff} // rgb(255, 0, 0)
Rosybrown = color.RGBA{0xbc, 0x8f, 0x8f, 0xff} // rgb(188, 143, 143)
Royalblue = color.RGBA{0x41, 0x69, 0xe1, 0xff} // rgb(65, 105, 225)
Saddlebrown = color.RGBA{0x8b, 0x45, 0x13, 0xff} // rgb(139, 69, 19)
Salmon = color.RGBA{0xfa, 0x80, 0x72, 0xff} // rgb(250, 128, 114)
Sandybrown = color.RGBA{0xf4, 0xa4, 0x60, 0xff} // rgb(244, 164, 96)
Seagreen = color.RGBA{0x2e, 0x8b, 0x57, 0xff} // rgb(46, 139, 87)
Seashell = color.RGBA{0xff, 0xf5, 0xee, 0xff} // rgb(255, 245, 238)
Sienna = color.RGBA{0xa0, 0x52, 0x2d, 0xff} // rgb(160, 82, 45)
Silver = color.RGBA{0xc0, 0xc0, 0xc0, 0xff} // rgb(192, 192, 192)
Skyblue = color.RGBA{0x87, 0xce, 0xeb, 0xff} // rgb(135, 206, 235)
Slateblue = color.RGBA{0x6a, 0x5a, 0xcd, 0xff} // rgb(106, 90, 205)
Slategray = color.RGBA{0x70, 0x80, 0x90, 0xff} // rgb(112, 128, 144)
Slategrey = color.RGBA{0x70, 0x80, 0x90, 0xff} // rgb(112, 128, 144)
Snow = color.RGBA{0xff, 0xfa, 0xfa, 0xff} // rgb(255, 250, 250)
Springgreen = color.RGBA{0x00, 0xff, 0x7f, 0xff} // rgb(0, 255, 127)
Steelblue = color.RGBA{0x46, 0x82, 0xb4, 0xff} // rgb(70, 130, 180)
Tan = color.RGBA{0xd2, 0xb4, 0x8c, 0xff} // rgb(210, 180, 140)
Teal = color.RGBA{0x00, 0x80, 0x80, 0xff} // rgb(0, 128, 128)
Thistle = color.RGBA{0xd8, 0xbf, 0xd8, 0xff} // rgb(216, 191, 216)
Tomato = color.RGBA{0xff, 0x63, 0x47, 0xff} // rgb(255, 99, 71)
Turquoise = color.RGBA{0x40, 0xe0, 0xd0, 0xff} // rgb(64, 224, 208)
Violet = color.RGBA{0xee, 0x82, 0xee, 0xff} // rgb(238, 130, 238)
Wheat = color.RGBA{0xf5, 0xde, 0xb3, 0xff} // rgb(245, 222, 179)
White = color.RGBA{0xff, 0xff, 0xff, 0xff} // rgb(255, 255, 255)
Whitesmoke = color.RGBA{0xf5, 0xf5, 0xf5, 0xff} // rgb(245, 245, 245)
Yellow = color.RGBA{0xff, 0xff, 0x00, 0xff} // rgb(255, 255, 0)
Yellowgreen = color.RGBA{0x9a, 0xcd, 0x32, 0xff} // rgb(154, 205, 50)
)

View File

@ -1,118 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package draw_test
import (
"fmt"
"image"
"image/color"
"image/png"
"log"
"math"
"os"
"golang.org/x/image/draw"
"golang.org/x/image/math/f64"
)
func ExampleDraw() {
fSrc, err := os.Open("../testdata/blue-purple-pink.png")
if err != nil {
log.Fatal(err)
}
defer fSrc.Close()
src, err := png.Decode(fSrc)
if err != nil {
log.Fatal(err)
}
dst := image.NewRGBA(image.Rect(0, 0, 400, 300))
green := image.NewUniform(color.RGBA{0x00, 0x1f, 0x00, 0xff})
draw.Copy(dst, image.Point{}, green, dst.Bounds(), draw.Src, nil)
qs := []draw.Interpolator{
draw.NearestNeighbor,
draw.ApproxBiLinear,
draw.CatmullRom,
}
const cos60, sin60 = 0.5, 0.866025404
t := f64.Aff3{
+2 * cos60, -2 * sin60, 100,
+2 * sin60, +2 * cos60, 100,
}
draw.Copy(dst, image.Point{20, 30}, src, src.Bounds(), draw.Over, nil)
for i, q := range qs {
q.Scale(dst, image.Rect(200+10*i, 100*i, 600+10*i, 150+100*i), src, src.Bounds(), draw.Over, nil)
}
draw.NearestNeighbor.Transform(dst, t, src, src.Bounds(), draw.Over, nil)
red := image.NewNRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
red.SetNRGBA(x, y, color.NRGBA{
R: uint8(x * 0x11),
A: uint8(y * 0x11),
})
}
}
red.SetNRGBA(0, 0, color.NRGBA{0xff, 0xff, 0x00, 0xff})
red.SetNRGBA(15, 15, color.NRGBA{0xff, 0xff, 0x00, 0xff})
ops := []draw.Op{
draw.Over,
draw.Src,
}
for i, op := range ops {
dr := image.Rect(120+10*i, 150+60*i, 170+10*i, 200+60*i)
draw.NearestNeighbor.Scale(dst, dr, red, red.Bounds(), op, nil)
t := f64.Aff3{
+cos60, -sin60, float64(190 + 10*i),
+sin60, +cos60, float64(140 + 50*i),
}
draw.NearestNeighbor.Transform(dst, t, red, red.Bounds(), op, nil)
}
dr := image.Rect(0, 0, 128, 128)
checkerboard := image.NewAlpha(dr)
for y := dr.Min.Y; y < dr.Max.Y; y++ {
for x := dr.Min.X; x < dr.Max.X; x++ {
if (x/20)%2 == (y/20)%2 {
checkerboard.SetAlpha(x, y, color.Alpha{0xff})
}
}
}
sr := image.Rect(0, 0, 16, 16)
circle := image.NewAlpha(sr)
for y := sr.Min.Y; y < sr.Max.Y; y++ {
for x := sr.Min.X; x < sr.Max.X; x++ {
dx, dy := x-10, y-8
if d := 32 * math.Sqrt(float64(dx*dx)+float64(dy*dy)); d < 0xff {
circle.SetAlpha(x, y, color.Alpha{0xff - uint8(d)})
}
}
}
cyan := image.NewUniform(color.RGBA{0x00, 0xff, 0xff, 0xff})
draw.NearestNeighbor.Scale(dst, dr, cyan, sr, draw.Over, &draw.Options{
DstMask: checkerboard,
SrcMask: circle,
})
// Change false to true to write the resultant image to disk.
if false {
fDst, err := os.Create("out.png")
if err != nil {
log.Fatal(err)
}
defer fDst.Close()
err = png.Encode(fDst, dst)
if err != nil {
log.Fatal(err)
}
}
fmt.Printf("dst has bounds %v.\n", dst.Bounds())
// Output:
// dst has bounds (0,0)-(400,300).
}

View File

@ -1,742 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package draw
import (
"bytes"
"flag"
"fmt"
"image"
"image/color"
"image/png"
"math/rand"
"os"
"reflect"
"testing"
"golang.org/x/image/math/f64"
_ "image/jpeg"
)
var genGoldenFiles = flag.Bool("gen_golden_files", false, "whether to generate the TestXxx golden files.")
var transformMatrix = func(scale, tx, ty float64) f64.Aff3 {
const cos30, sin30 = 0.866025404, 0.5
return f64.Aff3{
+scale * cos30, -scale * sin30, tx,
+scale * sin30, +scale * cos30, ty,
}
}
func encode(filename string, m image.Image) error {
f, err := os.Create(filename)
if err != nil {
return fmt.Errorf("Create: %v", err)
}
defer f.Close()
if err := png.Encode(f, m); err != nil {
return fmt.Errorf("Encode: %v", err)
}
return nil
}
// testInterp tests that interpolating the source image gives the exact
// destination image. This is to ensure that any refactoring or optimization of
// the interpolation code doesn't change the behavior. Changing the actual
// algorithm or kernel used by any particular quality setting will obviously
// change the resultant pixels. In such a case, use the gen_golden_files flag
// to regenerate the golden files.
func testInterp(t *testing.T, w int, h int, direction, prefix, suffix string) {
f, err := os.Open("../testdata/" + prefix + suffix)
if err != nil {
t.Fatalf("Open: %v", err)
}
defer f.Close()
src, _, err := image.Decode(f)
if err != nil {
t.Fatalf("Decode: %v", err)
}
op, scale := Src, 3.75
if prefix == "tux" {
op, scale = Over, 0.125
}
green := image.NewUniform(color.RGBA{0x00, 0x22, 0x11, 0xff})
testCases := map[string]Interpolator{
"nn": NearestNeighbor,
"ab": ApproxBiLinear,
"bl": BiLinear,
"cr": CatmullRom,
}
for name, q := range testCases {
goldenFilename := fmt.Sprintf("../testdata/%s-%s-%s.png", prefix, direction, name)
got := image.NewRGBA(image.Rect(0, 0, w, h))
Copy(got, image.Point{}, green, got.Bounds(), Src, nil)
if direction == "rotate" {
q.Transform(got, transformMatrix(scale, 40, 10), src, src.Bounds(), op, nil)
} else {
q.Scale(got, got.Bounds(), src, src.Bounds(), op, nil)
}
if *genGoldenFiles {
if err := encode(goldenFilename, got); err != nil {
t.Error(err)
}
continue
}
g, err := os.Open(goldenFilename)
if err != nil {
t.Errorf("Open: %v", err)
continue
}
defer g.Close()
wantRaw, err := png.Decode(g)
if err != nil {
t.Errorf("Decode: %v", err)
continue
}
// convert wantRaw to RGBA.
want, ok := wantRaw.(*image.RGBA)
if !ok {
b := wantRaw.Bounds()
want = image.NewRGBA(b)
Draw(want, b, wantRaw, b.Min, Src)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: actual image differs from golden image", goldenFilename)
continue
}
}
}
func TestScaleDown(t *testing.T) { testInterp(t, 100, 100, "down", "go-turns-two", "-280x360.jpeg") }
func TestScaleUp(t *testing.T) { testInterp(t, 75, 100, "up", "go-turns-two", "-14x18.png") }
func TestTformSrc(t *testing.T) { testInterp(t, 100, 100, "rotate", "go-turns-two", "-14x18.png") }
func TestTformOver(t *testing.T) { testInterp(t, 100, 100, "rotate", "tux", ".png") }
// TestSimpleTransforms tests Scale and Transform calls that simplify to Copy
// or Scale calls.
func TestSimpleTransforms(t *testing.T) {
f, err := os.Open("../testdata/testpattern.png") // A 100x100 image.
if err != nil {
t.Fatalf("Open: %v", err)
}
defer f.Close()
src, _, err := image.Decode(f)
if err != nil {
t.Fatalf("Decode: %v", err)
}
dst0 := image.NewRGBA(image.Rect(0, 0, 120, 150))
dst1 := image.NewRGBA(image.Rect(0, 0, 120, 150))
for _, op := range []string{"scale/copy", "tform/copy", "tform/scale"} {
for _, epsilon := range []float64{0, 1e-50, 1e-1} {
Copy(dst0, image.Point{}, image.Transparent, dst0.Bounds(), Src, nil)
Copy(dst1, image.Point{}, image.Transparent, dst1.Bounds(), Src, nil)
switch op {
case "scale/copy":
dr := image.Rect(10, 30, 10+100, 30+100)
if epsilon > 1e-10 {
dr.Max.X++
}
Copy(dst0, image.Point{10, 30}, src, src.Bounds(), Src, nil)
ApproxBiLinear.Scale(dst1, dr, src, src.Bounds(), Src, nil)
case "tform/copy":
Copy(dst0, image.Point{10, 30}, src, src.Bounds(), Src, nil)
ApproxBiLinear.Transform(dst1, f64.Aff3{
1, 0 + epsilon, 10,
0, 1, 30,
}, src, src.Bounds(), Src, nil)
case "tform/scale":
ApproxBiLinear.Scale(dst0, image.Rect(10, 50, 10+50, 50+50), src, src.Bounds(), Src, nil)
ApproxBiLinear.Transform(dst1, f64.Aff3{
0.5, 0.0 + epsilon, 10,
0.0, 0.5, 50,
}, src, src.Bounds(), Src, nil)
}
differ := !bytes.Equal(dst0.Pix, dst1.Pix)
if epsilon > 1e-10 {
if !differ {
t.Errorf("%s yielded same pixels, want different pixels: epsilon=%v", op, epsilon)
}
} else {
if differ {
t.Errorf("%s yielded different pixels, want same pixels: epsilon=%v", op, epsilon)
}
}
}
}
}
func BenchmarkSimpleScaleCopy(b *testing.B) {
dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
src := image.NewRGBA(image.Rect(0, 0, 400, 300))
b.ResetTimer()
for i := 0; i < b.N; i++ {
ApproxBiLinear.Scale(dst, image.Rect(10, 20, 10+400, 20+300), src, src.Bounds(), Src, nil)
}
}
func BenchmarkSimpleTransformCopy(b *testing.B) {
dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
src := image.NewRGBA(image.Rect(0, 0, 400, 300))
b.ResetTimer()
for i := 0; i < b.N; i++ {
ApproxBiLinear.Transform(dst, f64.Aff3{
1, 0, 10,
0, 1, 20,
}, src, src.Bounds(), Src, nil)
}
}
func BenchmarkSimpleTransformScale(b *testing.B) {
dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
src := image.NewRGBA(image.Rect(0, 0, 400, 300))
b.ResetTimer()
for i := 0; i < b.N; i++ {
ApproxBiLinear.Transform(dst, f64.Aff3{
0.5, 0.0, 10,
0.0, 0.5, 20,
}, src, src.Bounds(), Src, nil)
}
}
func TestOps(t *testing.T) {
blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
testCases := map[Op]color.RGBA{
Over: color.RGBA{0x7f, 0x00, 0x80, 0xff},
Src: color.RGBA{0x7f, 0x00, 0x00, 0x7f},
}
for op, want := range testCases {
dst := image.NewRGBA(image.Rect(0, 0, 2, 2))
Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
src := image.NewRGBA(image.Rect(0, 0, 1, 1))
src.SetRGBA(0, 0, color.RGBA{0x7f, 0x00, 0x00, 0x7f})
NearestNeighbor.Scale(dst, dst.Bounds(), src, src.Bounds(), op, nil)
if got := dst.RGBAAt(0, 0); got != want {
t.Errorf("op=%v: got %v, want %v", op, got, want)
}
}
}
// TestNegativeWeights tests that scaling by a kernel that produces negative
// weights, such as the Catmull-Rom kernel, doesn't produce an invalid color
// according to Go's alpha-premultiplied model.
func TestNegativeWeights(t *testing.T) {
check := func(m *image.RGBA) error {
b := m.Bounds()
for y := b.Min.Y; y < b.Max.Y; y++ {
for x := b.Min.X; x < b.Max.X; x++ {
if c := m.RGBAAt(x, y); c.R > c.A || c.G > c.A || c.B > c.A {
return fmt.Errorf("invalid color.RGBA at (%d, %d): %v", x, y, c)
}
}
}
return nil
}
src := image.NewRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
a := y * 0x11
src.Set(x, y, color.RGBA{
R: uint8(x * 0x11 * a / 0xff),
A: uint8(a),
})
}
}
if err := check(src); err != nil {
t.Fatalf("src image: %v", err)
}
dst := image.NewRGBA(image.Rect(0, 0, 32, 32))
CatmullRom.Scale(dst, dst.Bounds(), src, src.Bounds(), Over, nil)
if err := check(dst); err != nil {
t.Fatalf("dst image: %v", err)
}
}
func fillPix(r *rand.Rand, pixs ...[]byte) {
for _, pix := range pixs {
for i := range pix {
pix[i] = uint8(r.Intn(256))
}
}
}
func TestInterpClipCommute(t *testing.T) {
src := image.NewNRGBA(image.Rect(0, 0, 20, 20))
fillPix(rand.New(rand.NewSource(0)), src.Pix)
outer := image.Rect(1, 1, 8, 5)
inner := image.Rect(2, 3, 6, 5)
qs := []Interpolator{
NearestNeighbor,
ApproxBiLinear,
CatmullRom,
}
for _, transform := range []bool{false, true} {
for _, q := range qs {
dst0 := image.NewRGBA(image.Rect(1, 1, 10, 10))
dst1 := image.NewRGBA(image.Rect(1, 1, 10, 10))
for i := range dst0.Pix {
dst0.Pix[i] = uint8(i / 4)
dst1.Pix[i] = uint8(i / 4)
}
var interp func(dst *image.RGBA)
if transform {
interp = func(dst *image.RGBA) {
q.Transform(dst, transformMatrix(3.75, 2, 1), src, src.Bounds(), Over, nil)
}
} else {
interp = func(dst *image.RGBA) {
q.Scale(dst, outer, src, src.Bounds(), Over, nil)
}
}
// Interpolate then clip.
interp(dst0)
dst0 = dst0.SubImage(inner).(*image.RGBA)
// Clip then interpolate.
dst1 = dst1.SubImage(inner).(*image.RGBA)
interp(dst1)
loop:
for y := inner.Min.Y; y < inner.Max.Y; y++ {
for x := inner.Min.X; x < inner.Max.X; x++ {
if c0, c1 := dst0.RGBAAt(x, y), dst1.RGBAAt(x, y); c0 != c1 {
t.Errorf("q=%T: at (%d, %d): c0=%v, c1=%v", q, x, y, c0, c1)
break loop
}
}
}
}
}
}
// translatedImage is an image m translated by t.
type translatedImage struct {
m image.Image
t image.Point
}
func (t *translatedImage) At(x, y int) color.Color { return t.m.At(x-t.t.X, y-t.t.Y) }
func (t *translatedImage) Bounds() image.Rectangle { return t.m.Bounds().Add(t.t) }
func (t *translatedImage) ColorModel() color.Model { return t.m.ColorModel() }
// TestSrcTranslationInvariance tests that Scale and Transform are invariant
// under src translations. Specifically, when some source pixels are not in the
// bottom-right quadrant of src coordinate space, we consistently round down,
// not round towards zero.
func TestSrcTranslationInvariance(t *testing.T) {
f, err := os.Open("../testdata/testpattern.png")
if err != nil {
t.Fatalf("Open: %v", err)
}
defer f.Close()
src, _, err := image.Decode(f)
if err != nil {
t.Fatalf("Decode: %v", err)
}
sr := image.Rect(2, 3, 16, 12)
if !sr.In(src.Bounds()) {
t.Fatalf("src bounds too small: got %v", src.Bounds())
}
qs := []Interpolator{
NearestNeighbor,
ApproxBiLinear,
CatmullRom,
}
deltas := []image.Point{
{+0, +0},
{+0, +5},
{+0, -5},
{+5, +0},
{-5, +0},
{+8, +8},
{+8, -8},
{-8, +8},
{-8, -8},
}
m00 := transformMatrix(3.75, 0, 0)
for _, transform := range []bool{false, true} {
for _, q := range qs {
want := image.NewRGBA(image.Rect(0, 0, 20, 20))
if transform {
q.Transform(want, m00, src, sr, Over, nil)
} else {
q.Scale(want, want.Bounds(), src, sr, Over, nil)
}
for _, delta := range deltas {
tsrc := &translatedImage{src, delta}
got := image.NewRGBA(image.Rect(0, 0, 20, 20))
if transform {
m := matMul(&m00, &f64.Aff3{
1, 0, -float64(delta.X),
0, 1, -float64(delta.Y),
})
q.Transform(got, m, tsrc, sr.Add(delta), Over, nil)
} else {
q.Scale(got, got.Bounds(), tsrc, sr.Add(delta), Over, nil)
}
if !bytes.Equal(got.Pix, want.Pix) {
t.Errorf("pix differ for delta=%v, transform=%t, q=%T", delta, transform, q)
}
}
}
}
}
func TestSrcMask(t *testing.T) {
srcMask := image.NewRGBA(image.Rect(0, 0, 23, 1))
srcMask.SetRGBA(19, 0, color.RGBA{0x00, 0x00, 0x00, 0x7f})
srcMask.SetRGBA(20, 0, color.RGBA{0x00, 0x00, 0x00, 0xff})
srcMask.SetRGBA(21, 0, color.RGBA{0x00, 0x00, 0x00, 0x3f})
srcMask.SetRGBA(22, 0, color.RGBA{0x00, 0x00, 0x00, 0x00})
red := image.NewUniform(color.RGBA{0xff, 0x00, 0x00, 0xff})
blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
dst := image.NewRGBA(image.Rect(0, 0, 6, 1))
Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
NearestNeighbor.Scale(dst, dst.Bounds(), red, image.Rect(0, 0, 3, 1), Over, &Options{
SrcMask: srcMask,
SrcMaskP: image.Point{20, 0},
})
got := [6]color.RGBA{
dst.RGBAAt(0, 0),
dst.RGBAAt(1, 0),
dst.RGBAAt(2, 0),
dst.RGBAAt(3, 0),
dst.RGBAAt(4, 0),
dst.RGBAAt(5, 0),
}
want := [6]color.RGBA{
{0xff, 0x00, 0x00, 0xff},
{0xff, 0x00, 0x00, 0xff},
{0x3f, 0x00, 0xc0, 0xff},
{0x3f, 0x00, 0xc0, 0xff},
{0x00, 0x00, 0xff, 0xff},
{0x00, 0x00, 0xff, 0xff},
}
if got != want {
t.Errorf("\ngot %v\nwant %v", got, want)
}
}
func TestDstMask(t *testing.T) {
dstMask := image.NewRGBA(image.Rect(0, 0, 23, 1))
dstMask.SetRGBA(19, 0, color.RGBA{0x00, 0x00, 0x00, 0x7f})
dstMask.SetRGBA(20, 0, color.RGBA{0x00, 0x00, 0x00, 0xff})
dstMask.SetRGBA(21, 0, color.RGBA{0x00, 0x00, 0x00, 0x3f})
dstMask.SetRGBA(22, 0, color.RGBA{0x00, 0x00, 0x00, 0x00})
red := image.NewRGBA(image.Rect(0, 0, 1, 1))
red.SetRGBA(0, 0, color.RGBA{0xff, 0x00, 0x00, 0xff})
blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
qs := []Interpolator{
NearestNeighbor,
ApproxBiLinear,
CatmullRom,
}
for _, q := range qs {
dst := image.NewRGBA(image.Rect(0, 0, 3, 1))
Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
q.Scale(dst, dst.Bounds(), red, red.Bounds(), Over, &Options{
DstMask: dstMask,
DstMaskP: image.Point{20, 0},
})
got := [3]color.RGBA{
dst.RGBAAt(0, 0),
dst.RGBAAt(1, 0),
dst.RGBAAt(2, 0),
}
want := [3]color.RGBA{
{0xff, 0x00, 0x00, 0xff},
{0x3f, 0x00, 0xc0, 0xff},
{0x00, 0x00, 0xff, 0xff},
}
if got != want {
t.Errorf("q=%T:\ngot %v\nwant %v", q, got, want)
}
}
}
func TestRectDstMask(t *testing.T) {
f, err := os.Open("../testdata/testpattern.png")
if err != nil {
t.Fatalf("Open: %v", err)
}
defer f.Close()
src, _, err := image.Decode(f)
if err != nil {
t.Fatalf("Decode: %v", err)
}
m00 := transformMatrix(1, 0, 0)
bounds := image.Rect(0, 0, 50, 50)
dstOutside := image.NewRGBA(bounds)
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
dstOutside.SetRGBA(x, y, color.RGBA{uint8(5 * x), uint8(5 * y), 0x00, 0xff})
}
}
mk := func(q Transformer, dstMask image.Image, dstMaskP image.Point) *image.RGBA {
m := image.NewRGBA(bounds)
Copy(m, bounds.Min, dstOutside, bounds, Src, nil)
q.Transform(m, m00, src, src.Bounds(), Over, &Options{
DstMask: dstMask,
DstMaskP: dstMaskP,
})
return m
}
qs := []Interpolator{
NearestNeighbor,
ApproxBiLinear,
CatmullRom,
}
dstMaskPs := []image.Point{
{0, 0},
{5, 7},
{-3, 0},
}
rect := image.Rect(10, 10, 30, 40)
for _, q := range qs {
for _, dstMaskP := range dstMaskPs {
dstInside := mk(q, nil, image.Point{})
for _, wrap := range []bool{false, true} {
// TODO: replace "rectImage(rect)" with "rect" once Go 1.5 is
// released, where an image.Rectangle implements image.Image.
dstMask := image.Image(rectImage(rect))
if wrap {
dstMask = srcWrapper{dstMask}
}
dst := mk(q, dstMask, dstMaskP)
nError := 0
loop:
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
which := dstOutside
if (image.Point{x, y}).Add(dstMaskP).In(rect) {
which = dstInside
}
if got, want := dst.RGBAAt(x, y), which.RGBAAt(x, y); got != want {
if nError == 10 {
t.Errorf("q=%T dmp=%v wrap=%v: ...and more errors", q, dstMaskP, wrap)
break loop
}
nError++
t.Errorf("q=%T dmp=%v wrap=%v: x=%3d y=%3d: got %v, want %v",
q, dstMaskP, wrap, x, y, got, want)
}
}
}
}
}
}
}
func TestDstMaskSameSizeCopy(t *testing.T) {
bounds := image.Rect(0, 0, 42, 42)
src := image.Opaque
dst := image.NewRGBA(bounds)
mask := image.NewRGBA(bounds)
Copy(dst, image.ZP, src, bounds, Src, &Options{
DstMask: mask,
})
}
// TODO: delete this wrapper type once Go 1.5 is released, where an
// image.Rectangle implements image.Image.
type rectImage image.Rectangle
func (r rectImage) ColorModel() color.Model { return color.Alpha16Model }
func (r rectImage) Bounds() image.Rectangle { return image.Rectangle(r) }
func (r rectImage) At(x, y int) color.Color {
if (image.Point{x, y}).In(image.Rectangle(r)) {
return color.Opaque
}
return color.Transparent
}
// The fooWrapper types wrap the dst or src image to avoid triggering the
// type-specific fast path implementations.
type (
dstWrapper struct{ Image }
srcWrapper struct{ image.Image }
)
func srcGray(boundsHint image.Rectangle) (image.Image, error) {
m := image.NewGray(boundsHint)
fillPix(rand.New(rand.NewSource(0)), m.Pix)
return m, nil
}
func srcNRGBA(boundsHint image.Rectangle) (image.Image, error) {
m := image.NewNRGBA(boundsHint)
fillPix(rand.New(rand.NewSource(1)), m.Pix)
return m, nil
}
func srcRGBA(boundsHint image.Rectangle) (image.Image, error) {
m := image.NewRGBA(boundsHint)
fillPix(rand.New(rand.NewSource(2)), m.Pix)
// RGBA is alpha-premultiplied, so the R, G and B values should
// be <= the A values.
for i := 0; i < len(m.Pix); i += 4 {
m.Pix[i+0] = uint8(uint32(m.Pix[i+0]) * uint32(m.Pix[i+3]) / 0xff)
m.Pix[i+1] = uint8(uint32(m.Pix[i+1]) * uint32(m.Pix[i+3]) / 0xff)
m.Pix[i+2] = uint8(uint32(m.Pix[i+2]) * uint32(m.Pix[i+3]) / 0xff)
}
return m, nil
}
func srcUnif(boundsHint image.Rectangle) (image.Image, error) {
return image.NewUniform(color.RGBA64{0x1234, 0x5555, 0x9181, 0xbeef}), nil
}
func srcYCbCr(boundsHint image.Rectangle) (image.Image, error) {
m := image.NewYCbCr(boundsHint, image.YCbCrSubsampleRatio420)
fillPix(rand.New(rand.NewSource(3)), m.Y, m.Cb, m.Cr)
return m, nil
}
func srcLarge(boundsHint image.Rectangle) (image.Image, error) {
// 3072 x 2304 is over 7 million pixels at 4:3, comparable to a
// 2015 smart-phone camera's output.
return srcYCbCr(image.Rect(0, 0, 3072, 2304))
}
func srcTux(boundsHint image.Rectangle) (image.Image, error) {
// tux.png is a 386 x 395 image.
f, err := os.Open("../testdata/tux.png")
if err != nil {
return nil, fmt.Errorf("Open: %v", err)
}
defer f.Close()
src, err := png.Decode(f)
if err != nil {
return nil, fmt.Errorf("Decode: %v", err)
}
return src, nil
}
func benchScale(b *testing.B, w int, h int, op Op, srcf func(image.Rectangle) (image.Image, error), q Interpolator) {
dst := image.NewRGBA(image.Rect(0, 0, w, h))
src, err := srcf(image.Rect(0, 0, 1024, 768))
if err != nil {
b.Fatal(err)
}
dr, sr := dst.Bounds(), src.Bounds()
scaler := Scaler(q)
if n, ok := q.(interface {
NewScaler(int, int, int, int) Scaler
}); ok {
scaler = n.NewScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy())
}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
scaler.Scale(dst, dr, src, sr, op, nil)
}
}
func benchTform(b *testing.B, w int, h int, op Op, srcf func(image.Rectangle) (image.Image, error), q Interpolator) {
dst := image.NewRGBA(image.Rect(0, 0, w, h))
src, err := srcf(image.Rect(0, 0, 1024, 768))
if err != nil {
b.Fatal(err)
}
sr := src.Bounds()
m := transformMatrix(3.75, 40, 10)
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
q.Transform(dst, m, src, sr, op, nil)
}
}
func BenchmarkScaleNNLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, NearestNeighbor) }
func BenchmarkScaleABLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, ApproxBiLinear) }
func BenchmarkScaleBLLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, BiLinear) }
func BenchmarkScaleCRLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, CatmullRom) }
func BenchmarkScaleNNDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, NearestNeighbor) }
func BenchmarkScaleABDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, ApproxBiLinear) }
func BenchmarkScaleBLDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, BiLinear) }
func BenchmarkScaleCRDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, CatmullRom) }
func BenchmarkScaleNNUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, NearestNeighbor) }
func BenchmarkScaleABUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, ApproxBiLinear) }
func BenchmarkScaleBLUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, BiLinear) }
func BenchmarkScaleCRUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, CatmullRom) }
func BenchmarkScaleNNSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, NearestNeighbor) }
func BenchmarkScaleNNSrcUnif(b *testing.B) { benchScale(b, 200, 150, Src, srcUnif, NearestNeighbor) }
func BenchmarkScaleNNOverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, NearestNeighbor) }
func BenchmarkScaleNNOverUnif(b *testing.B) { benchScale(b, 200, 150, Over, srcUnif, NearestNeighbor) }
func BenchmarkTformNNSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, NearestNeighbor) }
func BenchmarkTformNNSrcUnif(b *testing.B) { benchTform(b, 200, 150, Src, srcUnif, NearestNeighbor) }
func BenchmarkTformNNOverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, NearestNeighbor) }
func BenchmarkTformNNOverUnif(b *testing.B) { benchTform(b, 200, 150, Over, srcUnif, NearestNeighbor) }
func BenchmarkScaleABSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, ApproxBiLinear) }
func BenchmarkScaleABSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) }
func BenchmarkScaleABSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, ApproxBiLinear) }
func BenchmarkScaleABSrcYCbCr(b *testing.B) { benchScale(b, 200, 150, Src, srcYCbCr, ApproxBiLinear) }
func BenchmarkScaleABOverGray(b *testing.B) { benchScale(b, 200, 150, Over, srcGray, ApproxBiLinear) }
func BenchmarkScaleABOverNRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcNRGBA, ApproxBiLinear) }
func BenchmarkScaleABOverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, ApproxBiLinear) }
func BenchmarkScaleABOverYCbCr(b *testing.B) { benchScale(b, 200, 150, Over, srcYCbCr, ApproxBiLinear) }
func BenchmarkTformABSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, ApproxBiLinear) }
func BenchmarkTformABSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) }
func BenchmarkTformABSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, ApproxBiLinear) }
func BenchmarkTformABSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, ApproxBiLinear) }
func BenchmarkTformABOverGray(b *testing.B) { benchTform(b, 200, 150, Over, srcGray, ApproxBiLinear) }
func BenchmarkTformABOverNRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcNRGBA, ApproxBiLinear) }
func BenchmarkTformABOverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, ApproxBiLinear) }
func BenchmarkTformABOverYCbCr(b *testing.B) { benchTform(b, 200, 150, Over, srcYCbCr, ApproxBiLinear) }
func BenchmarkScaleCRSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, CatmullRom) }
func BenchmarkScaleCRSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, CatmullRom) }
func BenchmarkScaleCRSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, CatmullRom) }
func BenchmarkScaleCRSrcYCbCr(b *testing.B) { benchScale(b, 200, 150, Src, srcYCbCr, CatmullRom) }
func BenchmarkScaleCROverGray(b *testing.B) { benchScale(b, 200, 150, Over, srcGray, CatmullRom) }
func BenchmarkScaleCROverNRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcNRGBA, CatmullRom) }
func BenchmarkScaleCROverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, CatmullRom) }
func BenchmarkScaleCROverYCbCr(b *testing.B) { benchScale(b, 200, 150, Over, srcYCbCr, CatmullRom) }
func BenchmarkTformCRSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, CatmullRom) }
func BenchmarkTformCRSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, CatmullRom) }
func BenchmarkTformCRSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, CatmullRom) }
func BenchmarkTformCRSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, CatmullRom) }
func BenchmarkTformCROverGray(b *testing.B) { benchTform(b, 200, 150, Over, srcGray, CatmullRom) }
func BenchmarkTformCROverNRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcNRGBA, CatmullRom) }
func BenchmarkTformCROverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, CatmullRom) }
func BenchmarkTformCROverYCbCr(b *testing.B) { benchTform(b, 200, 150, Over, srcYCbCr, CatmullRom) }

View File

@ -1,96 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.9
package draw
// This file contains tests that depend on the exact behavior of the
// image/color package in the standard library. The color conversion formula
// from YCbCr to RGBA changed between Go 1.4 and Go 1.5, and between Go 1.8 and
// Go 1.9, so this file's tests are only enabled for Go 1.9 and above.
import (
"bytes"
"image"
"image/color"
"testing"
)
// TestFastPaths tests that the fast path implementations produce identical
// results to the generic implementation.
func TestFastPaths(t *testing.T) {
drs := []image.Rectangle{
image.Rect(0, 0, 10, 10), // The dst bounds.
image.Rect(3, 4, 8, 6), // A strict subset of the dst bounds.
image.Rect(-3, -5, 2, 4), // Partial out-of-bounds #0.
image.Rect(4, -2, 6, 12), // Partial out-of-bounds #1.
image.Rect(12, 14, 23, 45), // Complete out-of-bounds.
image.Rect(5, 5, 5, 5), // Empty.
}
srs := []image.Rectangle{
image.Rect(0, 0, 12, 9), // The src bounds.
image.Rect(2, 2, 10, 8), // A strict subset of the src bounds.
image.Rect(10, 5, 20, 20), // Partial out-of-bounds #0.
image.Rect(-40, 0, 40, 8), // Partial out-of-bounds #1.
image.Rect(-8, -8, -4, -4), // Complete out-of-bounds.
image.Rect(5, 5, 5, 5), // Empty.
}
srcfs := []func(image.Rectangle) (image.Image, error){
srcGray,
srcNRGBA,
srcRGBA,
srcUnif,
srcYCbCr,
}
var srcs []image.Image
for _, srcf := range srcfs {
src, err := srcf(srs[0])
if err != nil {
t.Fatal(err)
}
srcs = append(srcs, src)
}
qs := []Interpolator{
NearestNeighbor,
ApproxBiLinear,
CatmullRom,
}
ops := []Op{
Over,
Src,
}
blue := image.NewUniform(color.RGBA{0x11, 0x22, 0x44, 0x7f})
for _, dr := range drs {
for _, src := range srcs {
for _, sr := range srs {
for _, transform := range []bool{false, true} {
for _, q := range qs {
for _, op := range ops {
dst0 := image.NewRGBA(drs[0])
dst1 := image.NewRGBA(drs[0])
Draw(dst0, dst0.Bounds(), blue, image.Point{}, Src)
Draw(dstWrapper{dst1}, dst1.Bounds(), srcWrapper{blue}, image.Point{}, Src)
if transform {
m := transformMatrix(3.75, 2, 1)
q.Transform(dst0, m, src, sr, op, nil)
q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, op, nil)
} else {
q.Scale(dst0, dr, src, sr, op, nil)
q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, op, nil)
}
if !bytes.Equal(dst0.Pix, dst1.Pix) {
t.Errorf("pix differ for dr=%v, src=%T, sr=%v, transform=%t, q=%T",
dr, src, sr, transform, q)
}
}
}
}
}
}
}
}

View File

@ -1,106 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build example
//
// This build tag means that "go install golang.org/x/image/..." doesn't
// install this example program. Use "go run main.go" to run it or "go install
// -tags=example" to install it.
// Font is a basic example of using fonts.
package main
import (
"flag"
"image"
"image/color"
"image/draw"
"image/png"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"golang.org/x/image/font"
"golang.org/x/image/font/plan9font"
"golang.org/x/image/math/fixed"
)
var (
fontFlag = flag.String("font", "",
`filename of the Plan 9 font or subfont file, such as "lucsans/unicode.8.font" or "lucsans/lsr.14"`)
firstRuneFlag = flag.Int("firstrune", 0, "the Unicode code point of the first rune in the subfont file")
)
func pt(p fixed.Point26_6) image.Point {
return image.Point{
X: int(p.X+32) >> 6,
Y: int(p.Y+32) >> 6,
}
}
func main() {
flag.Parse()
// TODO: mmap the files.
if *fontFlag == "" {
flag.Usage()
log.Fatal("no font specified")
}
var face font.Face
if strings.HasSuffix(*fontFlag, ".font") {
fontData, err := ioutil.ReadFile(*fontFlag)
if err != nil {
log.Fatal(err)
}
dir := filepath.Dir(*fontFlag)
face, err = plan9font.ParseFont(fontData, func(name string) ([]byte, error) {
return ioutil.ReadFile(filepath.Join(dir, filepath.FromSlash(name)))
})
if err != nil {
log.Fatal(err)
}
} else {
fontData, err := ioutil.ReadFile(*fontFlag)
if err != nil {
log.Fatal(err)
}
face, err = plan9font.ParseSubfont(fontData, rune(*firstRuneFlag))
if err != nil {
log.Fatal(err)
}
}
dst := image.NewRGBA(image.Rect(0, 0, 800, 300))
draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src)
d := &font.Drawer{
Dst: dst,
Src: image.White,
Face: face,
}
ss := []string{
"The quick brown fox jumps over the lazy dog.",
"Hello, 世界.",
"U+FFFD is \ufffd.",
}
for i, s := range ss {
d.Dot = fixed.P(20, 100*i+80)
dot0 := pt(d.Dot)
d.DrawString(s)
dot1 := pt(d.Dot)
dst.SetRGBA(dot0.X, dot0.Y, color.RGBA{0xff, 0x00, 0x00, 0xff})
dst.SetRGBA(dot1.X, dot1.Y, color.RGBA{0x00, 0x00, 0xff, 0xff})
}
out, err := os.Create("out.png")
if err != nil {
log.Fatal(err)
}
defer out.Close()
if err := png.Encode(out, dst); err != nil {
log.Fatal(err)
}
}

View File

@ -1,126 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go
// Package basicfont provides fixed-size font faces.
package basicfont // import "golang.org/x/image/font/basicfont"
import (
"image"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
// Range maps a contiguous range of runes to vertically adjacent sub-images of
// a Face's Mask image. The rune range is inclusive on the low end and
// exclusive on the high end.
//
// If Low <= r && r < High, then the rune r is mapped to the sub-image of
// Face.Mask whose bounds are image.Rect(0, y*h, Face.Width, (y+1)*h),
// where y = (int(r-Low) + Offset) and h = (Face.Ascent + Face.Descent).
type Range struct {
Low, High rune
Offset int
}
// Face7x13 is a Face derived from the public domain X11 misc-fixed font files.
//
// At the moment, it holds the printable characters in ASCII starting with
// space, and the Unicode replacement character U+FFFD.
//
// Its data is entirely self-contained and does not require loading from
// separate files.
var Face7x13 = &Face{
Advance: 7,
Width: 6,
Height: 13,
Ascent: 11,
Descent: 2,
Mask: mask7x13,
Ranges: []Range{
{'\u0020', '\u007f', 0},
{'\ufffd', '\ufffe', 95},
},
}
// Face is a basic font face whose glyphs all have the same metrics.
//
// It is safe to use concurrently.
type Face struct {
// Advance is the glyph advance, in pixels.
Advance int
// Width is the glyph width, in pixels.
Width int
// Height is the inter-line height, in pixels.
Height int
// Ascent is the glyph ascent, in pixels.
Ascent int
// Descent is the glyph descent, in pixels.
Descent int
// Left is the left side bearing, in pixels. A positive value means that
// all of a glyph is to the right of the dot.
Left int
// Mask contains all of the glyph masks. Its width is typically the Face's
// Width, and its height a multiple of the Face's Height.
Mask image.Image
// Ranges map runes to sub-images of Mask. The rune ranges must not
// overlap, and must be in increasing rune order.
Ranges []Range
}
func (f *Face) Close() error { return nil }
func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
func (f *Face) Metrics() font.Metrics {
return font.Metrics{
Height: fixed.I(f.Height),
Ascent: fixed.I(f.Ascent),
Descent: fixed.I(f.Descent),
}
}
func (f *Face) Glyph(dot fixed.Point26_6, r rune) (
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
loop:
for _, rr := range [2]rune{r, '\ufffd'} {
for _, rng := range f.Ranges {
if rr < rng.Low || rng.High <= rr {
continue
}
maskp.Y = (int(rr-rng.Low) + rng.Offset) * (f.Ascent + f.Descent)
ok = true
break loop
}
}
if !ok {
return image.Rectangle{}, nil, image.Point{}, 0, false
}
x := int(dot.X+32)>>6 + f.Left
y := int(dot.Y+32) >> 6
dr = image.Rectangle{
Min: image.Point{
X: x,
Y: y - f.Ascent,
},
Max: image.Point{
X: x + f.Width,
Y: y + f.Descent,
},
}
return dr, f.Mask, maskp, fixed.I(f.Advance), true
}
func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
return fixed.R(0, -f.Ascent, f.Width, +f.Descent), fixed.I(f.Advance), true
}
func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
return fixed.I(f.Advance), true
}

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// This program generates data.go.
package main
import (
"bytes"
"fmt"
"go/format"
"image"
"image/draw"
"io/ioutil"
"log"
"path"
"path/filepath"
"golang.org/x/image/font"
"golang.org/x/image/font/plan9font"
"golang.org/x/image/math/fixed"
)
func main() {
// nGlyphs is the number of glyphs to generate: 95 characters in the range
// [0x20, 0x7e], plus the replacement character.
const nGlyphs = 95 + 1
// The particular font (unicode.7x13.font) leaves the right-most column
// empty in its ASCII glyphs. We don't have to include that column in the
// generated glyphs, so we subtract one off the effective width.
const width, height, ascent = 7 - 1, 13, 11
readFile := func(name string) ([]byte, error) {
return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name)))
}
fontData, err := readFile("unicode.7x13.font")
if err != nil {
log.Fatalf("readFile: %v", err)
}
face, err := plan9font.ParseFont(fontData, readFile)
if err != nil {
log.Fatalf("plan9font.ParseFont: %v", err)
}
dst := image.NewRGBA(image.Rect(0, 0, width, nGlyphs*height))
draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src)
d := &font.Drawer{
Dst: dst,
Src: image.White,
Face: face,
}
for i := 0; i < nGlyphs; i++ {
r := '\ufffd'
if i < nGlyphs-1 {
r = 0x20 + rune(i)
}
d.Dot = fixed.P(0, height*i+ascent)
d.DrawString(string(r))
}
w := bytes.NewBuffer(nil)
w.WriteString(preamble)
fmt.Fprintf(w, "// mask7x13 contains %d %d×%d glyphs in %d Pix bytes.\n", nGlyphs, width, height, nGlyphs*width*height)
fmt.Fprintf(w, "var mask7x13 = &image.Alpha{\n")
fmt.Fprintf(w, " Stride: %d,\n", width)
fmt.Fprintf(w, " Rect: image.Rectangle{Max: image.Point{%d, %d*%d}},\n", width, nGlyphs, height)
fmt.Fprintf(w, " Pix: []byte{\n")
b := dst.Bounds()
for y := b.Min.Y; y < b.Max.Y; y++ {
if y%height == 0 {
if y != 0 {
w.WriteByte('\n')
}
i := y / height
if i < nGlyphs-1 {
i += 0x20
fmt.Fprintf(w, "// %#2x %q\n", i, rune(i))
} else {
fmt.Fprintf(w, "// U+FFFD REPLACEMENT CHARACTER\n")
}
}
for x := b.Min.X; x < b.Max.X; x++ {
if dst.RGBAAt(x, y).R > 0 {
w.WriteString("0xff,")
} else {
w.WriteString("0x00,")
}
}
w.WriteByte('\n')
}
w.WriteString("},\n}\n")
fmted, err := format.Source(w.Bytes())
if err != nil {
log.Fatalf("format.Source: %v", err)
}
if err := ioutil.WriteFile("data.go", fmted, 0644); err != nil {
log.Fatalf("ioutil.WriteFile: %v", err)
}
}
const preamble = `// generated by go generate; DO NOT EDIT.
package basicfont
// This data is derived from files in the font/fixed directory of the Plan 9
// Port source code (https://github.com/9fans/plan9port) which were originally
// based on the public domain X11 misc-fixed font files.
import "image"
`

View File

@ -1,359 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package font defines an interface for font faces, for drawing text on an
// image.
//
// Other packages provide font face implementations. For example, a truetype
// package would provide one based on .ttf font files.
package font // import "golang.org/x/image/font"
import (
"image"
"image/draw"
"io"
"unicode/utf8"
"golang.org/x/image/math/fixed"
)
// TODO: who is responsible for caches (glyph images, glyph indices, kerns)?
// The Drawer or the Face?
// Face is a font face. Its glyphs are often derived from a font file, such as
// "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and
// hinting. For example, the 12pt and 18pt versions of Comic Sans are two
// different faces, even if derived from the same font file.
//
// A Face is not safe for concurrent use by multiple goroutines, as its methods
// may re-use implementation-specific caches and mask image buffers.
//
// To create a Face, look to other packages that implement specific font file
// formats.
type Face interface {
io.Closer
// Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's
// glyph at the sub-pixel destination location dot, and that glyph's
// advance width.
//
// It returns !ok if the face does not contain a glyph for r.
//
// The contents of the mask image returned by one Glyph call may change
// after the next Glyph call. Callers that want to cache the mask must make
// a copy.
Glyph(dot fixed.Point26_6, r rune) (
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool)
// GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal
// to the origin, and that glyph's advance width.
//
// It returns !ok if the face does not contain a glyph for r.
//
// The glyph's ascent and descent equal -bounds.Min.Y and +bounds.Max.Y. A
// visual depiction of what these metrics are is at
// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool)
// GlyphAdvance returns the advance width of r's glyph.
//
// It returns !ok if the face does not contain a glyph for r.
GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool)
// Kern returns the horizontal adjustment for the kerning pair (r0, r1). A
// positive kern means to move the glyphs further apart.
Kern(r0, r1 rune) fixed.Int26_6
// Metrics returns the metrics for this Face.
Metrics() Metrics
// TODO: ColoredGlyph for various emoji?
// TODO: Ligatures? Shaping?
}
// Metrics holds the metrics for a Face. A visual depiction is at
// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
type Metrics struct {
// Height is the recommended amount of vertical space between two lines of
// text.
Height fixed.Int26_6
// Ascent is the distance from the top of a line to its baseline.
Ascent fixed.Int26_6
// Descent is the distance from the bottom of a line to its baseline. The
// value is typically positive, even though a descender goes below the
// baseline.
Descent fixed.Int26_6
}
// Drawer draws text on a destination image.
//
// A Drawer is not safe for concurrent use by multiple goroutines, since its
// Face is not.
type Drawer struct {
// Dst is the destination image.
Dst draw.Image
// Src is the source image.
Src image.Image
// Face provides the glyph mask images.
Face Face
// Dot is the baseline location to draw the next glyph. The majority of the
// affected pixels will be above and to the right of the dot, but some may
// be below or to the left. For example, drawing a 'j' in an italic face
// may affect pixels below and to the left of the dot.
Dot fixed.Point26_6
// TODO: Clip image.Image?
// TODO: SrcP image.Point for Src images other than *image.Uniform? How
// does it get updated during DrawString?
}
// TODO: should DrawString return the last rune drawn, so the next DrawString
// call can kern beforehand? Or should that be the responsibility of the caller
// if they really want to do that, since they have to explicitly shift d.Dot
// anyway? What if ligatures span more than two runes? What if grapheme
// clusters span multiple runes?
//
// TODO: do we assume that the input is in any particular Unicode Normalization
// Form?
//
// TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
// io.RuneReader, we can't assume that we can rewind the stream.
//
// TODO: how does this work with line breaking: drawing text up until a
// vertical line? Should DrawString return the number of runes drawn?
// DrawBytes draws s at the dot and advances the dot's location.
//
// It is equivalent to DrawString(string(s)) but may be more efficient.
func (d *Drawer) DrawBytes(s []byte) {
prevC := rune(-1)
for len(s) > 0 {
c, size := utf8.DecodeRune(s)
s = s[size:]
if prevC >= 0 {
d.Dot.X += d.Face.Kern(prevC, c)
}
dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
if !ok {
// TODO: is falling back on the U+FFFD glyph the responsibility of
// the Drawer or the Face?
// TODO: set prevC = '\ufffd'?
continue
}
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
d.Dot.X += advance
prevC = c
}
}
// DrawString draws s at the dot and advances the dot's location.
func (d *Drawer) DrawString(s string) {
prevC := rune(-1)
for _, c := range s {
if prevC >= 0 {
d.Dot.X += d.Face.Kern(prevC, c)
}
dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
if !ok {
// TODO: is falling back on the U+FFFD glyph the responsibility of
// the Drawer or the Face?
// TODO: set prevC = '\ufffd'?
continue
}
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
d.Dot.X += advance
prevC = c
}
}
// BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as
// the advance.
//
// It is equivalent to BoundBytes(string(s)) but may be more efficient.
func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
bounds, advance = BoundBytes(d.Face, s)
bounds.Min = bounds.Min.Add(d.Dot)
bounds.Max = bounds.Max.Add(d.Dot)
return
}
// BoundString returns the bounding box of s, drawn at the drawer dot, as well
// as the advance.
func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
bounds, advance = BoundString(d.Face, s)
bounds.Min = bounds.Min.Add(d.Dot)
bounds.Max = bounds.Max.Add(d.Dot)
return
}
// MeasureBytes returns how far dot would advance by drawing s.
//
// It is equivalent to MeasureString(string(s)) but may be more efficient.
func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
return MeasureBytes(d.Face, s)
}
// MeasureString returns how far dot would advance by drawing s.
func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
return MeasureString(d.Face, s)
}
// BoundBytes returns the bounding box of s with f, drawn at a dot equal to the
// origin, as well as the advance.
//
// It is equivalent to BoundString(string(s)) but may be more efficient.
func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
prevC := rune(-1)
for len(s) > 0 {
c, size := utf8.DecodeRune(s)
s = s[size:]
if prevC >= 0 {
advance += f.Kern(prevC, c)
}
b, a, ok := f.GlyphBounds(c)
if !ok {
// TODO: is falling back on the U+FFFD glyph the responsibility of
// the Drawer or the Face?
// TODO: set prevC = '\ufffd'?
continue
}
b.Min.X += advance
b.Max.X += advance
bounds = bounds.Union(b)
advance += a
prevC = c
}
return
}
// BoundString returns the bounding box of s with f, drawn at a dot equal to the
// origin, as well as the advance.
func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
prevC := rune(-1)
for _, c := range s {
if prevC >= 0 {
advance += f.Kern(prevC, c)
}
b, a, ok := f.GlyphBounds(c)
if !ok {
// TODO: is falling back on the U+FFFD glyph the responsibility of
// the Drawer or the Face?
// TODO: set prevC = '\ufffd'?
continue
}
b.Min.X += advance
b.Max.X += advance
bounds = bounds.Union(b)
advance += a
prevC = c
}
return
}
// MeasureBytes returns how far dot would advance by drawing s with f.
//
// It is equivalent to MeasureString(string(s)) but may be more efficient.
func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
prevC := rune(-1)
for len(s) > 0 {
c, size := utf8.DecodeRune(s)
s = s[size:]
if prevC >= 0 {
advance += f.Kern(prevC, c)
}
a, ok := f.GlyphAdvance(c)
if !ok {
// TODO: is falling back on the U+FFFD glyph the responsibility of
// the Drawer or the Face?
// TODO: set prevC = '\ufffd'?
continue
}
advance += a
prevC = c
}
return advance
}
// MeasureString returns how far dot would advance by drawing s with f.
func MeasureString(f Face, s string) (advance fixed.Int26_6) {
prevC := rune(-1)
for _, c := range s {
if prevC >= 0 {
advance += f.Kern(prevC, c)
}
a, ok := f.GlyphAdvance(c)
if !ok {
// TODO: is falling back on the U+FFFD glyph the responsibility of
// the Drawer or the Face?
// TODO: set prevC = '\ufffd'?
continue
}
advance += a
prevC = c
}
return advance
}
// Hinting selects how to quantize a vector font's glyph nodes.
//
// Not all fonts support hinting.
type Hinting int
const (
HintingNone Hinting = iota
HintingVertical
HintingFull
)
// Stretch selects a normal, condensed, or expanded face.
//
// Not all fonts support stretches.
type Stretch int
const (
StretchUltraCondensed Stretch = -4
StretchExtraCondensed Stretch = -3
StretchCondensed Stretch = -2
StretchSemiCondensed Stretch = -1
StretchNormal Stretch = +0
StretchSemiExpanded Stretch = +1
StretchExpanded Stretch = +2
StretchExtraExpanded Stretch = +3
StretchUltraExpanded Stretch = +4
)
// Style selects a normal, italic, or oblique face.
//
// Not all fonts support styles.
type Style int
const (
StyleNormal Style = iota
StyleItalic
StyleOblique
)
// Weight selects a normal, light or bold face.
//
// Not all fonts support weights.
//
// The named Weight constants (e.g. WeightBold) correspond to CSS' common
// weight names (e.g. "Bold"), but the numerical values differ, so that in Go,
// the zero value means to use a normal weight. For the CSS names and values,
// see https://developer.mozilla.org/en/docs/Web/CSS/font-weight
type Weight int
const (
WeightThin Weight = -3 // CSS font-weight value 100.
WeightExtraLight Weight = -2 // CSS font-weight value 200.
WeightLight Weight = -1 // CSS font-weight value 300.
WeightNormal Weight = +0 // CSS font-weight value 400.
WeightMedium Weight = +1 // CSS font-weight value 500.
WeightSemiBold Weight = +2 // CSS font-weight value 600.
WeightBold Weight = +3 // CSS font-weight value 700.
WeightExtraBold Weight = +4 // CSS font-weight value 800.
WeightBlack Weight = +5 // CSS font-weight value 900.
)

View File

@ -1,65 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package font
import (
"image"
"strings"
"testing"
"golang.org/x/image/math/fixed"
)
const toyAdvance = fixed.Int26_6(10 << 6)
type toyFace struct{}
func (toyFace) Close() error {
return nil
}
func (toyFace) Glyph(dot fixed.Point26_6, r rune) (image.Rectangle, image.Image, image.Point, fixed.Int26_6, bool) {
panic("unimplemented")
}
func (toyFace) GlyphBounds(r rune) (fixed.Rectangle26_6, fixed.Int26_6, bool) {
return fixed.Rectangle26_6{
Min: fixed.P(2, 0),
Max: fixed.P(6, 1),
}, toyAdvance, true
}
func (toyFace) GlyphAdvance(r rune) (fixed.Int26_6, bool) {
return toyAdvance, true
}
func (toyFace) Kern(r0, r1 rune) fixed.Int26_6 {
return 0
}
func (toyFace) Metrics() Metrics {
return Metrics{}
}
func TestBound(t *testing.T) {
wantBounds := []fixed.Rectangle26_6{
{Min: fixed.P(0, 0), Max: fixed.P(0, 0)},
{Min: fixed.P(2, 0), Max: fixed.P(6, 1)},
{Min: fixed.P(2, 0), Max: fixed.P(16, 1)},
{Min: fixed.P(2, 0), Max: fixed.P(26, 1)},
}
for i, wantBound := range wantBounds {
s := strings.Repeat("x", i)
gotBound, gotAdvance := BoundString(toyFace{}, s)
if gotBound != wantBound {
t.Errorf("i=%d: bound: got %v, want %v", i, gotBound, wantBound)
}
wantAdvance := toyAdvance * fixed.Int26_6(i)
if gotAdvance != wantAdvance {
t.Errorf("i=%d: advance: got %v, want %v", i, gotAdvance, wantAdvance)
}
}
}

View File

@ -1,107 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
// This program generates the subdirectories of Go packages that contain []byte
// versions of the TrueType font files under ./ttfs.
//
// Currently, "go run gen.go" needs to be run manually. This isn't done by the
// usual "go generate" mechanism as there isn't any other Go code in this
// directory (excluding sub-directories) to attach a "go:generate" line to.
//
// In any case, code generation should only need to happen when the underlying
// TTF files change, which isn't expected to happen frequently.
import (
"bytes"
"fmt"
"go/format"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)
const suffix = ".ttf"
func main() {
ttfs, err := os.Open("ttfs")
if err != nil {
log.Fatal(err)
}
defer ttfs.Close()
infos, err := ttfs.Readdir(-1)
if err != nil {
log.Fatal(err)
}
for _, info := range infos {
ttfName := info.Name()
if !strings.HasSuffix(ttfName, suffix) {
continue
}
do(ttfName)
}
}
func do(ttfName string) {
fontName := fontName(ttfName)
pkgName := pkgName(ttfName)
if err := os.Mkdir(pkgName, 0777); err != nil && !os.IsExist(err) {
log.Fatal(err)
}
src, err := ioutil.ReadFile(filepath.Join("ttfs", ttfName))
if err != nil {
log.Fatal(err)
}
desc := "a proportional-width, sans-serif"
if strings.Contains(ttfName, "Mono") {
desc = "a fixed-width, slab-serif"
}
b := new(bytes.Buffer)
fmt.Fprintf(b, "// generated by go run gen.go; DO NOT EDIT\n\n")
fmt.Fprintf(b, "// Package %s provides the %q TrueType font\n", pkgName, fontName)
fmt.Fprintf(b, "// from the Go font family. It is %s font.\n", desc)
fmt.Fprintf(b, "//\n")
fmt.Fprintf(b, "// See https://blog.golang.org/go-fonts for details.\n")
fmt.Fprintf(b, "package %s\n\n", pkgName)
fmt.Fprintf(b, "// TTF is the data for the %q TrueType font.\n", fontName)
fmt.Fprintf(b, "var TTF = []byte{")
for i, x := range src {
if i&15 == 0 {
b.WriteByte('\n')
}
fmt.Fprintf(b, "%#02x,", x)
}
fmt.Fprintf(b, "\n}\n")
dst, err := format.Source(b.Bytes())
if err != nil {
log.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(pkgName, "data.go"), dst, 0666); err != nil {
log.Fatal(err)
}
}
// fontName maps "Go-Regular.ttf" to "Go Regular".
func fontName(ttfName string) string {
s := ttfName[:len(ttfName)-len(suffix)]
s = strings.Replace(s, "-", " ", -1)
return s
}
// pkgName maps "Go-Regular.ttf" to "goregular".
func pkgName(ttfName string) string {
s := ttfName[:len(ttfName)-len(suffix)]
s = strings.Replace(s, "-", "", -1)
s = strings.ToLower(s)
return s
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,36 +0,0 @@
These fonts were created by the Bigelow & Holmes foundry specifically for the
Go project. See https://blog.golang.org/go-fonts for details.
They are licensed under the same open source license as the rest of the Go
project's software:
Copyright (c) 2016 Bigelow & Holmes Inc.. All rights reserved.
Distribution of this font is governed by the following license. If you do not
agree to this license, including the disclaimer, do not distribute or modify
this font.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of Google Inc. nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
DISCLAIMER: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate genbasicfont -size=16 -pkg=inconsolata -hinting=full -var=regular8x16 -fontfile=http://www.levien.com/type/myfonts/inconsolata/InconsolataGo-Regular.ttf
//go:generate genbasicfont -size=16 -pkg=inconsolata -hinting=full -var=bold8x16 -fontfile=http://www.levien.com/type/myfonts/inconsolata/InconsolataGo-Bold.ttf
// The genbasicfont program is github.com/golang/freetype/example/genbasicfont
// Package inconsolata provides pre-rendered bitmap versions of the Inconsolata
// font family.
//
// Inconsolata is copyright Raph Levien and Cyreal. This package is licensed
// under Go's BSD-style license (https://golang.org/LICENSE) with their
// permission.
//
// Inconsolata's home page is at
// http://www.levien.com/type/myfonts/inconsolata.html
package inconsolata // import "golang.org/x/image/font/inconsolata"
import (
"golang.org/x/image/font/basicfont"
)
// Regular8x16 is a regular weight, 8x16 font face.
var Regular8x16 *basicfont.Face = &regular8x16
// Bold8x16 is a bold weight, 8x16 font face.
var Bold8x16 *basicfont.Face = &bold8x16

File diff suppressed because it is too large Load Diff

View File

@ -1,103 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package opentype
import (
"image"
"golang.org/x/image/font"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
)
// FaceOptions describes the possible options given to NewFace when
// creating a new font.Face from a sfnt.Font.
type FaceOptions struct {
Size float64 // Size is the font size in points
DPI float64 // DPI is the dots per inch resolution
Hinting font.Hinting // Hinting selects how to quantize a vector font's glyph nodes
}
func defaultFaceOptions() *FaceOptions {
return &FaceOptions{
Size: 12,
DPI: 72,
Hinting: font.HintingNone,
}
}
// Face implements the font.Face interface for sfnt.Font values.
type Face struct {
f *sfnt.Font
hinting font.Hinting
scale fixed.Int26_6
buf sfnt.Buffer
}
// NewFace returns a new font.Face for the given sfnt.Font.
// if opts is nil, sensible defaults will be used.
func NewFace(f *sfnt.Font, opts *FaceOptions) (font.Face, error) {
if opts == nil {
opts = defaultFaceOptions()
}
face := &Face{
f: f,
hinting: opts.Hinting,
scale: fixed.Int26_6(0.5 + (opts.Size * opts.DPI * 64 / 72)),
}
return face, nil
}
// Close satisfies the font.Face interface.
func (f *Face) Close() error {
return nil
}
// Metrics satisfies the font.Face interface.
func (f *Face) Metrics() font.Metrics {
m, err := f.f.Metrics(&f.buf, f.scale, f.hinting)
if err != nil {
return font.Metrics{}
}
return m
}
// Kern satisfies the font.Face interface.
func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 {
x0 := f.index(r0)
x1 := f.index(r1)
k, err := f.f.Kern(&f.buf, x0, x1, fixed.Int26_6(f.f.UnitsPerEm()), f.hinting)
if err != nil {
return 0
}
return k
}
// Glyph satisfies the font.Face interface.
func (f *Face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
panic("not implemented")
}
// GlyphBounds satisfies the font.Face interface.
func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
advance, ok = f.GlyphAdvance(r)
if !ok {
return bounds, advance, ok
}
panic("not implemented")
}
// GlyphAdvance satisfies the font.Face interface.
func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
idx := f.index(r)
advance, err := f.f.GlyphAdvance(&f.buf, idx, f.scale, f.hinting)
return advance, err == nil
}
func (f *Face) index(r rune) sfnt.GlyphIndex {
x, _ := f.f.GlyphIndex(&f.buf, r)
return x
}

View File

@ -1,90 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package opentype
import (
"testing"
"golang.org/x/image/font"
"golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
)
var (
regular font.Face
)
func init() {
font, err := sfnt.Parse(goregular.TTF)
if err != nil {
panic(err)
}
regular, err = NewFace(font, defaultFaceOptions())
if err != nil {
panic(err)
}
}
func TestFaceGlyphAdvance(t *testing.T) {
for _, test := range []struct {
r rune
want fixed.Int26_6
}{
{' ', 213},
{'A', 512},
{'Á', 512},
{'Æ', 768},
{'i', 189},
{'x', 384},
} {
got, ok := regular.GlyphAdvance(test.r)
if !ok {
t.Errorf("could not get glyph advance width for %q", test.r)
continue
}
if got != test.want {
t.Errorf("%q: glyph advance width=%d. want=%d", test.r, got, test.want)
continue
}
}
}
func TestFaceKern(t *testing.T) {
// FIXME(sbinet) there is no kerning with gofont/goregular
for _, test := range []struct {
r1, r2 rune
want fixed.Int26_6
}{
{'A', 'A', 0},
{'A', 'V', 0},
{'V', 'A', 0},
{'A', 'v', 0},
{'W', 'a', 0},
{'W', 'i', 0},
{'Y', 'i', 0},
{'f', '(', 0},
{'f', 'f', 0},
{'f', 'i', 0},
{'T', 'a', 0},
{'T', 'e', 0},
} {
got := regular.Kern(test.r1, test.r2)
if got != test.want {
t.Errorf("(%q, %q): glyph kerning=%d. want=%d", test.r1, test.r2, got, test.want)
continue
}
}
}
func TestFaceMetrics(t *testing.T) {
want := font.Metrics{Height: 768, Ascent: 726, Descent: 162}
got := regular.Metrics()
if got != want {
t.Fatalf("metrics failed. got=%#v. want=%#v", got, want)
}
}

View File

@ -1,7 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package opentype implements the font.Face interface based on SFNT
// font file formats.
package opentype // import "golang.org/x/image/font/opentype"

View File

@ -1,92 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package plan9font_test
import (
"image"
"image/draw"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"golang.org/x/image/font"
"golang.org/x/image/font/plan9font"
"golang.org/x/image/math/fixed"
)
func ExampleParseFont() {
readFile := func(name string) ([]byte, error) {
return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name)))
}
fontData, err := readFile("unicode.7x13.font")
if err != nil {
log.Fatal(err)
}
face, err := plan9font.ParseFont(fontData, readFile)
if err != nil {
log.Fatal(err)
}
ascent := face.Metrics().Ascent.Ceil()
dst := image.NewRGBA(image.Rect(0, 0, 4*7, 13))
draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src)
d := &font.Drawer{
Dst: dst,
Src: image.White,
Face: face,
Dot: fixed.P(0, ascent),
}
// Draw:
// - U+0053 LATIN CAPITAL LETTER S
// - U+03A3 GREEK CAPITAL LETTER SIGMA
// - U+222B INTEGRAL
// - U+3055 HIRAGANA LETTER SA
// The testdata does not contain the CJK subfont files, so U+3055 HIRAGANA
// LETTER SA (さ) should be rendered as U+FFFD REPLACEMENT CHARACTER (<28>).
//
// The missing subfont file will trigger an "open
// ../testdata/shinonome/k12.3000: no such file or directory" log message.
// This is expected and can be ignored.
d.DrawString("SΣ∫さ")
// Convert the dst image to ASCII art.
var out []byte
b := dst.Bounds()
for y := b.Min.Y; y < b.Max.Y; y++ {
out = append(out, '0'+byte(y%10), ' ')
for x := b.Min.X; x < b.Max.X; x++ {
if dst.RGBAAt(x, y).R > 0 {
out = append(out, 'X')
} else {
out = append(out, '.')
}
}
// Highlight the last row before the baseline. Glyphs like 'S' without
// descenders should not affect any pixels whose Y coordinate is >= the
// baseline.
if y == ascent-1 {
out = append(out, '_')
}
out = append(out, '\n')
}
os.Stdout.Write(out)
// Output:
// 0 ..................X.........
// 1 .................X.X........
// 2 .XXXX..XXXXXX....X.....XXX..
// 3 X....X.X.........X....XX.XX.
// 4 X.......X........X....X.X.X.
// 5 X........X.......X....XXX.X.
// 6 .XXXX.....X......X....XX.XX.
// 7 .....X...X.......X....XX.XX.
// 8 .....X..X........X....XXXXX.
// 9 X....X.X.........X....XX.XX.
// 0 .XXXX..XXXXXX....X.....XXX.._
// 1 ...............X.X..........
// 2 ................X...........
}

View File

@ -1,610 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package plan9font implements font faces for the Plan 9 font and subfont file
// formats. These formats are described at
// http://plan9.bell-labs.com/magic/man2html/6/font
package plan9font // import "golang.org/x/image/font/plan9font"
import (
"bytes"
"errors"
"fmt"
"image"
"image/color"
"log"
"strconv"
"strings"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
// fontchar describes one character glyph in a subfont.
//
// For more detail, look for "struct Fontchar" in
// http://plan9.bell-labs.com/magic/man2html/2/cachechars
type fontchar struct {
x uint32 // X position in the image holding the glyphs.
top uint8 // First non-zero scan line.
bottom uint8 // Last non-zero scan line.
left int8 // Offset of baseline.
width uint8 // Width of baseline.
}
func parseFontchars(p []byte) []fontchar {
fc := make([]fontchar, len(p)/6)
for i := range fc {
fc[i] = fontchar{
x: uint32(p[0]) | uint32(p[1])<<8,
top: uint8(p[2]),
bottom: uint8(p[3]),
left: int8(p[4]),
width: uint8(p[5]),
}
p = p[6:]
}
return fc
}
// subface implements font.Face for a Plan 9 subfont.
type subface struct {
firstRune rune // First rune in the subfont.
n int // Number of characters in the subfont.
height int // Inter-line spacing.
ascent int // Height above the baseline.
fontchars []fontchar // Character descriptions.
img *image.Alpha // Image holding the glyphs.
}
func (f *subface) Close() error { return nil }
func (f *subface) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
func (f *subface) Metrics() font.Metrics {
return font.Metrics{
Height: fixed.I(f.height),
Ascent: fixed.I(f.ascent),
Descent: fixed.I(f.height - f.ascent),
}
}
func (f *subface) Glyph(dot fixed.Point26_6, r rune) (
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
r -= f.firstRune
if r < 0 || f.n <= int(r) {
return image.Rectangle{}, nil, image.Point{}, 0, false
}
i := &f.fontchars[r+0]
j := &f.fontchars[r+1]
minX := int(dot.X+32)>>6 + int(i.left)
minY := int(dot.Y+32)>>6 + int(i.top) - f.ascent
dr = image.Rectangle{
Min: image.Point{
X: minX,
Y: minY,
},
Max: image.Point{
X: minX + int(j.x-i.x),
Y: minY + int(i.bottom) - int(i.top),
},
}
return dr, f.img, image.Point{int(i.x), int(i.top)}, fixed.Int26_6(i.width) << 6, true
}
func (f *subface) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
r -= f.firstRune
if r < 0 || f.n <= int(r) {
return fixed.Rectangle26_6{}, 0, false
}
i := &f.fontchars[r+0]
j := &f.fontchars[r+1]
bounds = fixed.R(
int(i.left),
int(i.top)-f.ascent,
int(i.left)+int(j.x-i.x),
int(i.bottom)-f.ascent,
)
return bounds, fixed.Int26_6(i.width) << 6, true
}
func (f *subface) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
r -= f.firstRune
if r < 0 || f.n <= int(r) {
return 0, false
}
return fixed.Int26_6(f.fontchars[r].width) << 6, true
}
// runeRange maps a single rune range [lo, hi] to a lazily loaded subface. Both
// ends of the range are inclusive.
type runeRange struct {
lo, hi rune
offset rune // subfont index that the lo rune maps to.
relFilename string
subface *subface
bad bool
}
// face implements font.Face for a Plan 9 font.
//
// It maps multiple rune ranges to *subface values. Rune ranges may overlap;
// the first match wins.
type face struct {
height int
ascent int
readFile func(relFilename string) ([]byte, error)
runeRanges []runeRange
}
func (f *face) Close() error { return nil }
func (f *face) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
func (f *face) Metrics() font.Metrics {
return font.Metrics{
Height: fixed.I(f.height),
Ascent: fixed.I(f.ascent),
Descent: fixed.I(f.height - f.ascent),
}
}
func (f *face) Glyph(dot fixed.Point26_6, r rune) (
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
if s, rr := f.subface(r); s != nil {
return s.Glyph(dot, rr)
}
return image.Rectangle{}, nil, image.Point{}, 0, false
}
func (f *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
if s, rr := f.subface(r); s != nil {
return s.GlyphBounds(rr)
}
return fixed.Rectangle26_6{}, 0, false
}
func (f *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
if s, rr := f.subface(r); s != nil {
return s.GlyphAdvance(rr)
}
return 0, false
}
// For subfont files, if reading the given file name fails, we try appending
// ".n" where n is the log2 of the grayscale depth in bits (so at most 3) and
// then work down to 0. This was done in Plan 9 when antialiased fonts were
// introduced so that the 1-bit displays could keep using the 1-bit forms but
// higher depth displays could use the antialiased forms.
var subfontSuffixes = [...]string{
"",
".3",
".2",
".1",
".0",
}
func (f *face) readSubfontFile(name string) ([]byte, error) {
var firstErr error
for _, suffix := range subfontSuffixes {
if b, err := f.readFile(name + suffix); err == nil {
return b, nil
} else if firstErr == nil {
firstErr = err
}
}
return nil, firstErr
}
func (f *face) subface(r rune) (*subface, rune) {
// Fall back on U+FFFD if we can't find r.
for _, rr := range [2]rune{r, '\ufffd'} {
// We have to do linear, not binary search. plan9port's
// lucsans/unicode.8.font says:
// 0x2591 0x2593 ../luc/Altshades.7.0
// 0x2500 0x25ee ../luc/FormBlock.7.0
// and the rune ranges overlap.
for i := range f.runeRanges {
x := &f.runeRanges[i]
if rr < x.lo || x.hi < rr || x.bad {
continue
}
if x.subface == nil {
data, err := f.readSubfontFile(x.relFilename)
if err != nil {
log.Printf("plan9font: couldn't read subfont %q: %v", x.relFilename, err)
x.bad = true
continue
}
sub, err := ParseSubfont(data, x.lo-x.offset)
if err != nil {
log.Printf("plan9font: couldn't parse subfont %q: %v", x.relFilename, err)
x.bad = true
continue
}
x.subface = sub.(*subface)
}
return x.subface, rr
}
}
return nil, 0
}
// ParseFont parses a Plan 9 font file. data is the contents of that font file,
// which gives relative filenames for subfont files. readFile returns the
// contents of those subfont files. It is similar to io/ioutil's ReadFile
// function, except that it takes a relative filename instead of an absolute
// one.
func ParseFont(data []byte, readFile func(relFilename string) ([]byte, error)) (font.Face, error) {
f := &face{
readFile: readFile,
}
// TODO: don't use strconv, to avoid the conversions from []byte to string?
for first := true; len(data) > 0; first = false {
i := bytes.IndexByte(data, '\n')
if i < 0 {
return nil, errors.New("plan9font: invalid font: no final newline")
}
row := string(data[:i])
data = data[i+1:]
if first {
height, s, ok := nextInt32(row)
if !ok {
return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
}
ascent, s, ok := nextInt32(s)
if !ok {
return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
}
if height < 0 || 0xffff < height || ascent < 0 || 0xffff < ascent {
return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
}
f.height, f.ascent = int(height), int(ascent)
continue
}
lo, s, ok := nextInt32(row)
if !ok {
return nil, fmt.Errorf("plan9font: invalid font: invalid row %q", row)
}
hi, s, ok := nextInt32(s)
if !ok {
return nil, fmt.Errorf("plan9font: invalid font: invalid row %q", row)
}
offset, s, _ := nextInt32(s)
f.runeRanges = append(f.runeRanges, runeRange{
lo: lo,
hi: hi,
offset: offset,
relFilename: s,
})
}
return f, nil
}
func nextInt32(s string) (ret int32, remaining string, ok bool) {
i := 0
for ; i < len(s) && s[i] <= ' '; i++ {
}
j := i
for ; j < len(s) && s[j] > ' '; j++ {
}
n, err := strconv.ParseInt(s[i:j], 0, 32)
if err != nil {
return 0, s, false
}
for ; j < len(s) && s[j] <= ' '; j++ {
}
return int32(n), s[j:], true
}
// ParseSubfont parses a Plan 9 subfont file.
//
// firstRune is the first rune in the subfont file. For example, the
// Phonetic.6.0 subfont, containing glyphs in the range U+0250 to U+02E9, would
// set firstRune to '\u0250'.
func ParseSubfont(data []byte, firstRune rune) (font.Face, error) {
data, m, err := parseImage(data)
if err != nil {
return nil, err
}
if len(data) < 3*12 {
return nil, errors.New("plan9font: invalid subfont: header too short")
}
n := atoi(data[0*12:])
height := atoi(data[1*12:])
ascent := atoi(data[2*12:])
data = data[3*12:]
if len(data) != 6*(n+1) {
return nil, errors.New("plan9font: invalid subfont: data length mismatch")
}
// Convert from plan9Image to image.Alpha, as the standard library's
// image/draw package works best when glyph masks are of that type.
img := image.NewAlpha(m.Bounds())
for y := img.Rect.Min.Y; y < img.Rect.Max.Y; y++ {
i := img.PixOffset(img.Rect.Min.X, y)
for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
img.Pix[i] = m.at(x, y)
i++
}
}
return &subface{
firstRune: firstRune,
n: n,
height: height,
ascent: ascent,
fontchars: parseFontchars(data),
img: img,
}, nil
}
// plan9Image implements that subset of the Plan 9 image feature set that is
// used by this font file format.
//
// Some features, such as the repl bit and a clip rectangle, are omitted for
// simplicity.
type plan9Image struct {
depth int // Depth of the pixels in bits.
width int // Width in bytes of a single scan line.
rect image.Rectangle // Extent of the image.
pix []byte // Pixel bits.
}
func (m *plan9Image) byteoffset(x, y int) int {
a := y * m.width
if m.depth < 8 {
// We need to always round down, but Go rounds toward zero.
np := 8 / m.depth
if x < 0 {
return a + (x-np+1)/np
}
return a + x/np
}
return a + x*(m.depth/8)
}
func (m *plan9Image) Bounds() image.Rectangle { return m.rect }
func (m *plan9Image) ColorModel() color.Model { return color.AlphaModel }
func (m *plan9Image) At(x, y int) color.Color {
if (image.Point{x, y}).In(m.rect) {
return color.Alpha{m.at(x, y)}
}
return color.Alpha{0x00}
}
func (m *plan9Image) at(x, y int) uint8 {
b := m.pix[m.byteoffset(x, y)]
switch m.depth {
case 1:
// CGrey, 1.
mask := uint8(1 << uint8(7-x&7))
if (b & mask) != 0 {
return 0xff
}
return 0
case 2:
// CGrey, 2.
shift := uint(x&3) << 1
// Place pixel at top of word.
y := b << shift
y &= 0xc0
// Replicate throughout.
y |= y >> 2
y |= y >> 4
return y
}
return 0
}
var compressed = []byte("compressed\n")
func parseImage(data []byte) (remainingData []byte, m *plan9Image, retErr error) {
if !bytes.HasPrefix(data, compressed) {
return nil, nil, errors.New("plan9font: unsupported uncompressed format")
}
data = data[len(compressed):]
const hdrSize = 5 * 12
if len(data) < hdrSize {
return nil, nil, errors.New("plan9font: invalid image: header too short")
}
hdr, data := data[:hdrSize], data[hdrSize:]
// Distinguish new channel descriptor from old ldepth. Channel descriptors
// have letters as well as numbers, while ldepths are a single digit
// formatted as %-11d.
new := false
for m := 0; m < 10; m++ {
if hdr[m] != ' ' {
new = true
break
}
}
if hdr[11] != ' ' {
return nil, nil, errors.New("plan9font: invalid image: bad header")
}
if !new {
return nil, nil, errors.New("plan9font: unsupported ldepth format")
}
depth := 0
switch s := strings.TrimSpace(string(hdr[:1*12])); s {
default:
return nil, nil, fmt.Errorf("plan9font: unsupported pixel format %q", s)
case "k1":
depth = 1
case "k2":
depth = 2
}
r := ator(hdr[1*12:])
if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
return nil, nil, errors.New("plan9font: invalid image: bad rectangle")
}
width := bytesPerLine(r, depth)
m = &plan9Image{
depth: depth,
width: width,
rect: r,
pix: make([]byte, width*r.Dy()),
}
miny := r.Min.Y
for miny != r.Max.Y {
if len(data) < 2*12 {
return nil, nil, errors.New("plan9font: invalid image: data band too short")
}
maxy := atoi(data[0*12:])
nb := atoi(data[1*12:])
data = data[2*12:]
if len(data) < nb {
return nil, nil, errors.New("plan9font: invalid image: data band length mismatch")
}
buf := data[:nb]
data = data[nb:]
if maxy <= miny || r.Max.Y < maxy {
return nil, nil, fmt.Errorf("plan9font: bad maxy %d", maxy)
}
// An old-format image would flip the bits here, but we don't support
// the old format.
rr := r
rr.Min.Y = miny
rr.Max.Y = maxy
if err := decompress(m, rr, buf); err != nil {
return nil, nil, err
}
miny = maxy
}
return data, m, nil
}
// Compressed data are sequences of byte codes. If the first byte b has the
// 0x80 bit set, the next (b^0x80)+1 bytes are data. Otherwise, these two bytes
// specify a previous string to repeat.
const (
compShortestMatch = 3 // shortest match possible.
compWindowSize = 1024 // window size.
)
var (
errDecompressBufferTooSmall = errors.New("plan9font: decompress: buffer too small")
errDecompressPhaseError = errors.New("plan9font: decompress: phase error")
)
func decompress(m *plan9Image, r image.Rectangle, data []byte) error {
if !r.In(m.rect) {
return errors.New("plan9font: decompress: bad rectangle")
}
bpl := bytesPerLine(r, m.depth)
mem := make([]byte, compWindowSize)
memi := 0
omemi := -1
y := r.Min.Y
linei := m.byteoffset(r.Min.X, y)
eline := linei + bpl
datai := 0
for {
if linei == eline {
y++
if y == r.Max.Y {
break
}
linei = m.byteoffset(r.Min.X, y)
eline = linei + bpl
}
if datai == len(data) {
return errDecompressBufferTooSmall
}
c := data[datai]
datai++
if c >= 128 {
for cnt := c - 128 + 1; cnt != 0; cnt-- {
if datai == len(data) {
return errDecompressBufferTooSmall
}
if linei == eline {
return errDecompressPhaseError
}
m.pix[linei] = data[datai]
linei++
mem[memi] = data[datai]
memi++
datai++
if memi == len(mem) {
memi = 0
}
}
} else {
if datai == len(data) {
return errDecompressBufferTooSmall
}
offs := int(data[datai]) + ((int(c) & 3) << 8) + 1
datai++
if memi < offs {
omemi = memi + (compWindowSize - offs)
} else {
omemi = memi - offs
}
for cnt := (c >> 2) + compShortestMatch; cnt != 0; cnt-- {
if linei == eline {
return errDecompressPhaseError
}
m.pix[linei] = mem[omemi]
linei++
mem[memi] = mem[omemi]
memi++
omemi++
if omemi == len(mem) {
omemi = 0
}
if memi == len(mem) {
memi = 0
}
}
}
}
return nil
}
func ator(b []byte) image.Rectangle {
return image.Rectangle{atop(b), atop(b[2*12:])}
}
func atop(b []byte) image.Point {
return image.Pt(atoi(b), atoi(b[12:]))
}
func atoi(b []byte) int {
i := 0
for ; i < len(b) && b[i] == ' '; i++ {
}
n := 0
for ; i < len(b) && '0' <= b[i] && b[i] <= '9'; i++ {
n = n*10 + int(b[i]) - '0'
}
return n
}
func bytesPerLine(r image.Rectangle, depth int) int {
if depth <= 0 || 32 < depth {
panic("invalid depth")
}
var l int
if r.Min.X >= 0 {
l = (r.Max.X*depth + 7) / 8
l -= (r.Min.X * depth) / 8
} else {
// Make positive before divide.
t := (-r.Min.X*depth + 7) / 8
l = t + (r.Max.X*depth+7)/8
}
return l
}

View File

@ -1,24 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package plan9font
import (
"io/ioutil"
"path/filepath"
"testing"
)
func BenchmarkParseSubfont(b *testing.B) {
subfontData, err := ioutil.ReadFile(filepath.FromSlash("../testdata/fixed/7x13.0000"))
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := ParseSubfont(subfontData, 0); err != nil {
b.Fatal(err)
}
}
}

View File

@ -1,259 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sfnt
import (
"golang.org/x/text/encoding/charmap"
)
// Platform IDs and Platform Specific IDs as per
// https://www.microsoft.com/typography/otspec/name.htm
const (
pidUnicode = 0
pidMacintosh = 1
pidWindows = 3
psidUnicode2BMPOnly = 3
psidUnicode2FullRepertoire = 4
// Note that FontForge may generate a bogus Platform Specific ID (value 10)
// for the Unicode Platform ID (value 0). See
// https://github.com/fontforge/fontforge/issues/2728
psidMacintoshRoman = 0
psidWindowsSymbol = 0
psidWindowsUCS2 = 1
psidWindowsUCS4 = 10
)
// platformEncodingWidth returns the number of bytes per character assumed by
// the given Platform ID and Platform Specific ID.
//
// Very old fonts, from before Unicode was widely adopted, assume only 1 byte
// per character: a character map.
//
// Old fonts, from when Unicode meant the Basic Multilingual Plane (BMP),
// assume that 2 bytes per character is sufficient.
//
// Recent fonts naturally support the full range of Unicode code points, which
// can take up to 4 bytes per character. Such fonts might still choose one of
// the legacy encodings if e.g. their repertoire is limited to the BMP, for
// greater compatibility with older software, or because the resultant file
// size can be smaller.
func platformEncodingWidth(pid, psid uint16) int {
switch pid {
case pidUnicode:
switch psid {
case psidUnicode2BMPOnly:
return 2
case psidUnicode2FullRepertoire:
return 4
}
case pidMacintosh:
switch psid {
case psidMacintoshRoman:
return 1
}
case pidWindows:
switch psid {
case psidWindowsSymbol:
return 2
case psidWindowsUCS2:
return 2
case psidWindowsUCS4:
return 4
}
}
return 0
}
// The various cmap formats are described at
// https://www.microsoft.com/typography/otspec/cmap.htm
var supportedCmapFormat = func(format, pid, psid uint16) bool {
switch format {
case 0:
return pid == pidMacintosh && psid == psidMacintoshRoman
case 4:
return true
case 12:
return true
}
return false
}
func (f *Font) makeCachedGlyphIndex(buf []byte, offset, length uint32, format uint16) ([]byte, glyphIndexFunc, error) {
switch format {
case 0:
return f.makeCachedGlyphIndexFormat0(buf, offset, length)
case 4:
return f.makeCachedGlyphIndexFormat4(buf, offset, length)
case 12:
return f.makeCachedGlyphIndexFormat12(buf, offset, length)
}
panic("unreachable")
}
func (f *Font) makeCachedGlyphIndexFormat0(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
if length != 6+256 || offset+length > f.cmap.length {
return nil, nil, errInvalidCmapTable
}
var err error
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(length))
if err != nil {
return nil, nil, err
}
var table [256]byte
copy(table[:], buf[6:])
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
x, ok := charmap.Macintosh.EncodeRune(r)
if !ok {
// The source rune r is not representable in the Macintosh-Roman encoding.
return 0, nil
}
return GlyphIndex(table[x]), nil
}, nil
}
func (f *Font) makeCachedGlyphIndexFormat4(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
const headerSize = 14
if offset+headerSize > f.cmap.length {
return nil, nil, errInvalidCmapTable
}
var err error
buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
if err != nil {
return nil, nil, err
}
offset += headerSize
segCount := u16(buf[6:])
if segCount&1 != 0 {
return nil, nil, errInvalidCmapTable
}
segCount /= 2
if segCount > maxCmapSegments {
return nil, nil, errUnsupportedNumberOfCmapSegments
}
eLength := 8*uint32(segCount) + 2
if offset+eLength > f.cmap.length {
return nil, nil, errInvalidCmapTable
}
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
if err != nil {
return nil, nil, err
}
offset += eLength
entries := make([]cmapEntry16, segCount)
for i := range entries {
entries[i] = cmapEntry16{
end: u16(buf[0*len(entries)+0+2*i:]),
start: u16(buf[2*len(entries)+2+2*i:]),
delta: u16(buf[4*len(entries)+2+2*i:]),
offset: u16(buf[6*len(entries)+2+2*i:]),
}
}
indexesBase := f.cmap.offset + offset
indexesLength := f.cmap.length - offset
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
if uint32(r) > 0xffff {
return 0, nil
}
c := uint16(r)
for i, j := 0, len(entries); i < j; {
h := i + (j-i)/2
entry := &entries[h]
if c < entry.start {
j = h
} else if entry.end < c {
i = h + 1
} else if entry.offset == 0 {
return GlyphIndex(c + entry.delta), nil
} else {
offset := uint32(entry.offset) + 2*uint32(h-len(entries)+int(c-entry.start))
if offset > indexesLength || offset+2 > indexesLength {
return 0, errInvalidCmapTable
}
x, err := b.view(&f.src, int(indexesBase+offset), 2)
if err != nil {
return 0, err
}
return GlyphIndex(u16(x)), nil
}
}
return 0, nil
}, nil
}
func (f *Font) makeCachedGlyphIndexFormat12(buf []byte, offset, _ uint32) ([]byte, glyphIndexFunc, error) {
const headerSize = 16
if offset+headerSize > f.cmap.length {
return nil, nil, errInvalidCmapTable
}
var err error
buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
if err != nil {
return nil, nil, err
}
length := u32(buf[4:])
if f.cmap.length < offset || length > f.cmap.length-offset {
return nil, nil, errInvalidCmapTable
}
offset += headerSize
numGroups := u32(buf[12:])
if numGroups > maxCmapSegments {
return nil, nil, errUnsupportedNumberOfCmapSegments
}
eLength := 12 * numGroups
if headerSize+eLength != length {
return nil, nil, errInvalidCmapTable
}
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
if err != nil {
return nil, nil, err
}
offset += eLength
entries := make([]cmapEntry32, numGroups)
for i := range entries {
entries[i] = cmapEntry32{
start: u32(buf[0+12*i:]),
end: u32(buf[4+12*i:]),
delta: u32(buf[8+12*i:]),
}
}
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
c := uint32(r)
for i, j := 0, len(entries); i < j; {
h := i + (j-i)/2
entry := &entries[h]
if c < entry.start {
j = h
} else if entry.end < c {
i = h + 1
} else {
return GlyphIndex(c - entry.start + entry.delta), nil
}
}
return 0, nil
}, nil
}
type cmapEntry16 struct {
end, start, delta, offset uint16
}
type cmapEntry32 struct {
start, end, delta uint32
}

View File

@ -1,68 +0,0 @@
// generated by go run gen.go; DO NOT EDIT
package sfnt
const numBuiltInPostNames = 258
const builtInPostNamesData = "" +
".notdef.nullnonmarkingreturnspaceexclamquotedblnumbersigndollarp" +
"ercentampersandquotesingleparenleftparenrightasteriskpluscommahy" +
"phenperiodslashzeroonetwothreefourfivesixseveneightninecolonsemi" +
"colonlessequalgreaterquestionatABCDEFGHIJKLMNOPQRSTUVWXYZbracket" +
"leftbackslashbracketrightasciicircumunderscoregraveabcdefghijklm" +
"nopqrstuvwxyzbraceleftbarbracerightasciitildeAdieresisAringCcedi" +
"llaEacuteNtildeOdieresisUdieresisaacuteagraveacircumflexadieresi" +
"satildearingccedillaeacuteegraveecircumflexedieresisiacuteigrave" +
"icircumflexidieresisntildeoacuteograveocircumflexodieresisotilde" +
"uacuteugraveucircumflexudieresisdaggerdegreecentsterlingsectionb" +
"ulletparagraphgermandblsregisteredcopyrighttrademarkacutedieresi" +
"snotequalAEOslashinfinityplusminuslessequalgreaterequalyenmupart" +
"ialdiffsummationproductpiintegralordfeminineordmasculineOmegaaeo" +
"slashquestiondownexclamdownlogicalnotradicalflorinapproxequalDel" +
"taguillemotleftguillemotrightellipsisnonbreakingspaceAgraveAtild" +
"eOtildeOEoeendashemdashquotedblleftquotedblrightquoteleftquoteri" +
"ghtdividelozengeydieresisYdieresisfractioncurrencyguilsinglleftg" +
"uilsinglrightfifldaggerdblperiodcenteredquotesinglbasequotedblba" +
"seperthousandAcircumflexEcircumflexAacuteEdieresisEgraveIacuteIc" +
"ircumflexIdieresisIgraveOacuteOcircumflexappleOgraveUacuteUcircu" +
"mflexUgravedotlessicircumflextildemacronbrevedotaccentringcedill" +
"ahungarumlautogonekcaronLslashlslashScaronscaronZcaronzcaronbrok" +
"enbarEthethYacuteyacuteThornthornminusmultiplyonesuperiortwosupe" +
"riorthreesuperioronehalfonequarterthreequartersfrancGbrevegbreve" +
"IdotaccentScedillascedillaCacutecacuteCcaronccarondcroat"
var builtInPostNamesOffsets = [...]uint16{
0x0000, 0x0007, 0x000c, 0x001c, 0x0021, 0x0027, 0x002f, 0x0039,
0x003f, 0x0046, 0x004f, 0x005a, 0x0063, 0x006d, 0x0075, 0x0079,
0x007e, 0x0084, 0x008a, 0x008f, 0x0093, 0x0096, 0x0099, 0x009e,
0x00a2, 0x00a6, 0x00a9, 0x00ae, 0x00b3, 0x00b7, 0x00bc, 0x00c5,
0x00c9, 0x00ce, 0x00d5, 0x00dd, 0x00df, 0x00e0, 0x00e1, 0x00e2,
0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea,
0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2,
0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x0104,
0x010d, 0x0119, 0x0124, 0x012e, 0x0133, 0x0134, 0x0135, 0x0136,
0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146,
0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d, 0x0156,
0x0159, 0x0163, 0x016d, 0x0176, 0x017b, 0x0183, 0x0189, 0x018f,
0x0198, 0x01a1, 0x01a7, 0x01ad, 0x01b8, 0x01c1, 0x01c7, 0x01cc,
0x01d4, 0x01da, 0x01e0, 0x01eb, 0x01f4, 0x01fa, 0x0200, 0x020b,
0x0214, 0x021a, 0x0220, 0x0226, 0x0231, 0x023a, 0x0240, 0x0246,
0x024c, 0x0257, 0x0260, 0x0266, 0x026c, 0x0270, 0x0278, 0x027f,
0x0285, 0x028e, 0x0298, 0x02a2, 0x02ab, 0x02b4, 0x02b9, 0x02c1,
0x02c9, 0x02cb, 0x02d1, 0x02d9, 0x02e2, 0x02eb, 0x02f7, 0x02fa,
0x02fc, 0x0307, 0x0310, 0x0317, 0x0319, 0x0321, 0x032c, 0x0338,
0x033d, 0x033f, 0x0345, 0x0351, 0x035b, 0x0365, 0x036c, 0x0372,
0x037d, 0x0382, 0x038f, 0x039d, 0x03a5, 0x03b5, 0x03bb, 0x03c1,
0x03c7, 0x03c9, 0x03cb, 0x03d1, 0x03d7, 0x03e3, 0x03f0, 0x03f9,
0x0403, 0x0409, 0x0410, 0x0419, 0x0422, 0x042a, 0x0432, 0x043f,
0x044d, 0x044f, 0x0451, 0x045a, 0x0468, 0x0476, 0x0482, 0x048d,
0x0498, 0x04a3, 0x04a9, 0x04b2, 0x04b8, 0x04be, 0x04c9, 0x04d2,
0x04d8, 0x04de, 0x04e9, 0x04ee, 0x04f4, 0x04fa, 0x0505, 0x050b,
0x0513, 0x051d, 0x0522, 0x0528, 0x052d, 0x0536, 0x053a, 0x0541,
0x054d, 0x0553, 0x0558, 0x055e, 0x0564, 0x056a, 0x0570, 0x0576,
0x057c, 0x0585, 0x0588, 0x058b, 0x0591, 0x0597, 0x059c, 0x05a1,
0x05a6, 0x05ae, 0x05b9, 0x05c4, 0x05d1, 0x05d8, 0x05e2, 0x05ef,
0x05f4, 0x05fa, 0x0600, 0x060a, 0x0612, 0x061a, 0x0620, 0x0626,
0x062c, 0x0632, 0x0638,
}

View File

@ -1,131 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sfnt_test
import (
"image"
"image/draw"
"log"
"os"
"golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/font/sfnt"
"golang.org/x/image/math/fixed"
"golang.org/x/image/vector"
)
func ExampleRasterizeGlyph() {
const (
ppem = 32
width = 24
height = 36
originX = 0
originY = 32
)
f, err := sfnt.Parse(goregular.TTF)
if err != nil {
log.Fatalf("Parse: %v", err)
}
var b sfnt.Buffer
x, err := f.GlyphIndex(&b, 'Ġ')
if err != nil {
log.Fatalf("GlyphIndex: %v", err)
}
if x == 0 {
log.Fatalf("GlyphIndex: no glyph index found for the rune 'Ġ'")
}
segments, err := f.LoadGlyph(&b, x, fixed.I(ppem), nil)
if err != nil {
log.Fatalf("LoadGlyph: %v", err)
}
r := vector.NewRasterizer(width, height)
r.DrawOp = draw.Src
for _, seg := range segments {
// The divisions by 64 below is because the seg.Args values have type
// fixed.Int26_6, a 26.6 fixed point number, and 1<<6 == 64.
switch seg.Op {
case sfnt.SegmentOpMoveTo:
r.MoveTo(
originX+float32(seg.Args[0].X)/64,
originY+float32(seg.Args[0].Y)/64,
)
case sfnt.SegmentOpLineTo:
r.LineTo(
originX+float32(seg.Args[0].X)/64,
originY+float32(seg.Args[0].Y)/64,
)
case sfnt.SegmentOpQuadTo:
r.QuadTo(
originX+float32(seg.Args[0].X)/64,
originY+float32(seg.Args[0].Y)/64,
originX+float32(seg.Args[1].X)/64,
originY+float32(seg.Args[1].Y)/64,
)
case sfnt.SegmentOpCubeTo:
r.CubeTo(
originX+float32(seg.Args[0].X)/64,
originY+float32(seg.Args[0].Y)/64,
originX+float32(seg.Args[1].X)/64,
originY+float32(seg.Args[1].Y)/64,
originX+float32(seg.Args[2].X)/64,
originY+float32(seg.Args[2].Y)/64,
)
}
}
dst := image.NewAlpha(image.Rect(0, 0, width, height))
r.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
const asciiArt = ".++8"
buf := make([]byte, 0, height*(width+1))
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
a := dst.AlphaAt(x, y).A
buf = append(buf, asciiArt[a>>6])
}
buf = append(buf, '\n')
}
os.Stdout.Write(buf)
// Output:
// ........................
// ........................
// ........................
// ............888.........
// ............888.........
// ............888.........
// ............+++.........
// ........................
// ..........+++++++++.....
// .......+8888888888888+..
// ......8888888888888888..
// ....+8888+........++88..
// ....8888................
// ...8888.................
// ..+888+.................
// ..+888..................
// ..888+..................
// .+888+..................
// .+888...................
// .+888...................
// .+888...................
// .+888..........+++++++..
// .+888..........8888888..
// .+888+.........+++8888..
// ..888+............+888..
// ..8888............+888..
// ..+888+...........+888..
// ...8888+..........+888..
// ...+8888+.........+888..
// ....+88888+.......+888..
// .....+8888888888888888..
// .......+888888888888++..
// ..........++++++++......
// ........................
// ........................
// ........................
}

View File

@ -1,321 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
import (
"bytes"
"fmt"
"go/format"
"io/ioutil"
"log"
)
func main() {
data, offsets := []byte(nil), []int{0}
for _, name := range names {
data = append(data, name...)
offsets = append(offsets, len(data))
}
b := new(bytes.Buffer)
fmt.Fprintf(b, "// generated by go run gen.go; DO NOT EDIT\n\n")
fmt.Fprintf(b, "package sfnt\n\n")
fmt.Fprintf(b, "const numBuiltInPostNames = %d\n\n", len(names))
fmt.Fprintf(b, "const builtInPostNamesData = \"\" +\n")
for s := data; ; {
if len(s) <= 64 {
fmt.Fprintf(b, "%q\n", s)
break
}
fmt.Fprintf(b, "%q +\n", s[:64])
s = s[64:]
}
fmt.Fprintf(b, "\n")
fmt.Fprintf(b, "var builtInPostNamesOffsets = [...]uint16{\n")
for i, o := range offsets {
fmt.Fprintf(b, "%#04x,", o)
if i%8 == 7 {
fmt.Fprintf(b, "\n")
}
}
fmt.Fprintf(b, "\n}\n")
dstUnformatted := b.Bytes()
dst, err := format.Source(dstUnformatted)
if err != nil {
log.Fatalf("format.Source: %v\n\n----\n%s\n----", err, dstUnformatted)
}
if err := ioutil.WriteFile("data.go", dst, 0666); err != nil {
log.Fatalf("ioutil.WriteFile: %v", err)
}
}
// names is the built-in post table names listed at
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
var names = [258]string{
".notdef",
".null",
"nonmarkingreturn",
"space",
"exclam",
"quotedbl",
"numbersign",
"dollar",
"percent",
"ampersand",
"quotesingle",
"parenleft",
"parenright",
"asterisk",
"plus",
"comma",
"hyphen",
"period",
"slash",
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"colon",
"semicolon",
"less",
"equal",
"greater",
"question",
"at",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"bracketleft",
"backslash",
"bracketright",
"asciicircum",
"underscore",
"grave",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"braceleft",
"bar",
"braceright",
"asciitilde",
"Adieresis",
"Aring",
"Ccedilla",
"Eacute",
"Ntilde",
"Odieresis",
"Udieresis",
"aacute",
"agrave",
"acircumflex",
"adieresis",
"atilde",
"aring",
"ccedilla",
"eacute",
"egrave",
"ecircumflex",
"edieresis",
"iacute",
"igrave",
"icircumflex",
"idieresis",
"ntilde",
"oacute",
"ograve",
"ocircumflex",
"odieresis",
"otilde",
"uacute",
"ugrave",
"ucircumflex",
"udieresis",
"dagger",
"degree",
"cent",
"sterling",
"section",
"bullet",
"paragraph",
"germandbls",
"registered",
"copyright",
"trademark",
"acute",
"dieresis",
"notequal",
"AE",
"Oslash",
"infinity",
"plusminus",
"lessequal",
"greaterequal",
"yen",
"mu",
"partialdiff",
"summation",
"product",
"pi",
"integral",
"ordfeminine",
"ordmasculine",
"Omega",
"ae",
"oslash",
"questiondown",
"exclamdown",
"logicalnot",
"radical",
"florin",
"approxequal",
"Delta",
"guillemotleft",
"guillemotright",
"ellipsis",
"nonbreakingspace",
"Agrave",
"Atilde",
"Otilde",
"OE",
"oe",
"endash",
"emdash",
"quotedblleft",
"quotedblright",
"quoteleft",
"quoteright",
"divide",
"lozenge",
"ydieresis",
"Ydieresis",
"fraction",
"currency",
"guilsinglleft",
"guilsinglright",
"fi",
"fl",
"daggerdbl",
"periodcentered",
"quotesinglbase",
"quotedblbase",
"perthousand",
"Acircumflex",
"Ecircumflex",
"Aacute",
"Edieresis",
"Egrave",
"Iacute",
"Icircumflex",
"Idieresis",
"Igrave",
"Oacute",
"Ocircumflex",
"apple",
"Ograve",
"Uacute",
"Ucircumflex",
"Ugrave",
"dotlessi",
"circumflex",
"tilde",
"macron",
"breve",
"dotaccent",
"ring",
"cedilla",
"hungarumlaut",
"ogonek",
"caron",
"Lslash",
"lslash",
"Scaron",
"scaron",
"Zcaron",
"zcaron",
"brokenbar",
"Eth",
"eth",
"Yacute",
"yacute",
"Thorn",
"thorn",
"minus",
"multiply",
"onesuperior",
"twosuperior",
"threesuperior",
"onehalf",
"onequarter",
"threequarters",
"franc",
"Gbreve",
"gbreve",
"Idotaccent",
"Scedilla",
"scedilla",
"Cacute",
"cacute",
"Ccaron",
"ccaron",
"dcroat",
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,839 +0,0 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sfnt
import (
"bytes"
"fmt"
"io/ioutil"
"path/filepath"
"testing"
"golang.org/x/image/font"
"golang.org/x/image/font/gofont/gobold"
"golang.org/x/image/font/gofont/gomono"
"golang.org/x/image/font/gofont/goregular"
"golang.org/x/image/math/fixed"
)
func pt(x, y fixed.Int26_6) fixed.Point26_6 {
return fixed.Point26_6{X: x, Y: y}
}
func moveTo(xa, ya fixed.Int26_6) Segment {
return Segment{
Op: SegmentOpMoveTo,
Args: [3]fixed.Point26_6{pt(xa, ya)},
}
}
func lineTo(xa, ya fixed.Int26_6) Segment {
return Segment{
Op: SegmentOpLineTo,
Args: [3]fixed.Point26_6{pt(xa, ya)},
}
}
func quadTo(xa, ya, xb, yb fixed.Int26_6) Segment {
return Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb)},
}
}
func cubeTo(xa, ya, xb, yb, xc, yc fixed.Int26_6) Segment {
return Segment{
Op: SegmentOpCubeTo,
Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb), pt(xc, yc)},
}
}
func translate(dx, dy fixed.Int26_6, s Segment) Segment {
translateArgs(&s.Args, dx, dy)
return s
}
func transform(txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6, s Segment) Segment {
transformArgs(&s.Args, txx, txy, tyx, tyy, dx, dy)
return s
}
func checkSegmentsEqual(got, want []Segment) error {
// Flip got's Y axis. The test cases' coordinates are given with the Y axis
// increasing up, as that is what the ttx tool gives, and is the model for
// the underlying font format. The Go API returns coordinates with the Y
// axis increasing down, the same as the standard graphics libraries.
for i := range got {
for j := range got[i].Args {
got[i].Args[j].Y *= -1
}
}
if len(got) != len(want) {
return fmt.Errorf("got %d elements, want %d\noverall:\ngot %v\nwant %v",
len(got), len(want), got, want)
}
for i, g := range got {
if w := want[i]; g != w {
return fmt.Errorf("element %d:\ngot %v\nwant %v\noverall:\ngot %v\nwant %v",
i, g, w, got, want)
}
}
// Check that every contour is closed.
if len(got) == 0 {
return nil
}
if got[0].Op != SegmentOpMoveTo {
return fmt.Errorf("segments do not start with a moveTo")
}
var (
first, last fixed.Point26_6
firstI int
)
checkClosed := func(lastI int) error {
if first != last {
return fmt.Errorf("segments[%d:%d] not closed:\nfirst %v\nlast %v", firstI, lastI, first, last)
}
return nil
}
for i, g := range got {
switch g.Op {
case SegmentOpMoveTo:
if i != 0 {
if err := checkClosed(i); err != nil {
return err
}
}
firstI, first, last = i, g.Args[0], g.Args[0]
case SegmentOpLineTo:
last = g.Args[0]
case SegmentOpQuadTo:
last = g.Args[1]
case SegmentOpCubeTo:
last = g.Args[2]
}
}
return checkClosed(len(got))
}
func TestTrueTypeParse(t *testing.T) {
f, err := Parse(goregular.TTF)
if err != nil {
t.Fatalf("Parse: %v", err)
}
testTrueType(t, f)
}
func TestTrueTypeParseReaderAt(t *testing.T) {
f, err := ParseReaderAt(bytes.NewReader(goregular.TTF))
if err != nil {
t.Fatalf("ParseReaderAt: %v", err)
}
testTrueType(t, f)
}
func testTrueType(t *testing.T, f *Font) {
if got, want := f.UnitsPerEm(), Units(2048); got != want {
t.Errorf("UnitsPerEm: got %d, want %d", got, want)
}
// The exact number of glyphs in goregular.TTF can vary, and future
// versions may add more glyphs, but https://blog.golang.org/go-fonts says
// that "The WGL4 character set... [has] more than 650 characters in all.
if got, want := f.NumGlyphs(), 650; got <= want {
t.Errorf("NumGlyphs: got %d, want > %d", got, want)
}
}
func fontData(name string) []byte {
switch name {
case "gobold":
return gobold.TTF
case "gomono":
return gomono.TTF
case "goregular":
return goregular.TTF
}
panic("unreachable")
}
func TestBounds(t *testing.T) {
testCases := map[string]fixed.Rectangle26_6{
"gobold": {
Min: fixed.Point26_6{
X: -452,
Y: -2193,
},
Max: fixed.Point26_6{
X: 2190,
Y: 432,
},
},
"gomono": {
Min: fixed.Point26_6{
X: 0,
Y: -2227,
},
Max: fixed.Point26_6{
X: 1229,
Y: 432,
},
},
"goregular": {
Min: fixed.Point26_6{
X: -440,
Y: -2118,
},
Max: fixed.Point26_6{
X: 2160,
Y: 543,
},
},
}
var b Buffer
for name, want := range testCases {
f, err := Parse(fontData(name))
if err != nil {
t.Errorf("Parse(%q): %v", name, err)
continue
}
ppem := fixed.Int26_6(f.UnitsPerEm())
got, err := f.Bounds(&b, ppem, font.HintingNone)
if err != nil {
t.Errorf("name=%q: Bounds: %v", name, err)
continue
}
if got != want {
t.Errorf("name=%q: Bounds: got %v, want %v", name, got, want)
continue
}
}
}
func TestMetrics(t *testing.T) {
cmapFont, err := ioutil.ReadFile(filepath.FromSlash("../testdata/cmapTest.ttf"))
if err != nil {
t.Fatal(err)
}
testCases := map[string]struct {
font []byte
want font.Metrics
}{
"goregular": {goregular.TTF, font.Metrics{Height: 2048, Ascent: 1935, Descent: 432}},
// cmapTest.ttf has a non-zero lineGap.
"cmapTest": {cmapFont, font.Metrics{Height: 2232, Ascent: 1365, Descent: 0}},
}
var b Buffer
for name, tc := range testCases {
f, err := Parse(tc.font)
if err != nil {
t.Errorf("name=%q: Parse: %v", name, err)
continue
}
ppem := fixed.Int26_6(f.UnitsPerEm())
got, err := f.Metrics(&b, ppem, font.HintingNone)
if err != nil {
t.Errorf("name=%q: Metrics: %v", name, err)
continue
}
if got != tc.want {
t.Errorf("name=%q: Metrics: got %v, want %v", name, got, tc.want)
continue
}
}
}
func TestGlyphAdvance(t *testing.T) {
testCases := map[string][]struct {
r rune
want fixed.Int26_6
}{
"gobold": {
{' ', 569},
{'A', 1479},
{'Á', 1479},
{'Æ', 2048},
{'i', 592},
{'x', 1139},
},
"gomono": {
{' ', 1229},
{'A', 1229},
{'Á', 1229},
{'Æ', 1229},
{'i', 1229},
{'x', 1229},
},
"goregular": {
{' ', 569},
{'A', 1366},
{'Á', 1366},
{'Æ', 2048},
{'i', 505},
{'x', 1024},
},
}
var b Buffer
for name, testCases1 := range testCases {
f, err := Parse(fontData(name))
if err != nil {
t.Errorf("Parse(%q): %v", name, err)
continue
}
ppem := fixed.Int26_6(f.UnitsPerEm())
for _, tc := range testCases1 {
x, err := f.GlyphIndex(&b, tc.r)
if err != nil {
t.Errorf("name=%q, r=%q: GlyphIndex: %v", name, tc.r, err)
continue
}
got, err := f.GlyphAdvance(&b, x, ppem, font.HintingNone)
if err != nil {
t.Errorf("name=%q, r=%q: GlyphAdvance: %v", name, tc.r, err)
continue
}
if got != tc.want {
t.Errorf("name=%q, r=%q: GlyphAdvance: got %d, want %d", name, tc.r, got, tc.want)
continue
}
}
}
}
func TestGoRegularGlyphIndex(t *testing.T) {
f, err := Parse(goregular.TTF)
if err != nil {
t.Fatalf("Parse: %v", err)
}
testCases := []struct {
r rune
want GlyphIndex
}{
// Glyphs that aren't present in Go Regular.
{'\u001f', 0}, // U+001F <control>
{'\u0200', 0}, // U+0200 LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
{'\u2000', 0}, // U+2000 EN QUAD
// The want values below can be verified by running the ttx tool on
// Go-Regular.ttf.
//
// The actual values are ad hoc, and result from whatever tools the
// Bigelow & Holmes type foundry used and the order in which they
// crafted the glyphs. They may change over time as newer versions of
// the font are released.
{'\u0020', 3}, // U+0020 SPACE
{'\u0021', 4}, // U+0021 EXCLAMATION MARK
{'\u0022', 5}, // U+0022 QUOTATION MARK
{'\u0023', 6}, // U+0023 NUMBER SIGN
{'\u0024', 7}, // U+0024 DOLLAR SIGN
{'\u0025', 8}, // U+0025 PERCENT SIGN
{'\u0026', 9}, // U+0026 AMPERSAND
{'\u0027', 10}, // U+0027 APOSTROPHE
{'\u03bd', 396}, // U+03BD GREEK SMALL LETTER NU
{'\u03be', 397}, // U+03BE GREEK SMALL LETTER XI
{'\u03bf', 398}, // U+03BF GREEK SMALL LETTER OMICRON
{'\u03c0', 399}, // U+03C0 GREEK SMALL LETTER PI
{'\u03c1', 400}, // U+03C1 GREEK SMALL LETTER RHO
{'\u03c2', 401}, // U+03C2 GREEK SMALL LETTER FINAL SIGMA
}
var b Buffer
for _, tc := range testCases {
got, err := f.GlyphIndex(&b, tc.r)
if err != nil {
t.Errorf("r=%q: %v", tc.r, err)
continue
}
if got != tc.want {
t.Errorf("r=%q: got %d, want %d", tc.r, got, tc.want)
continue
}
}
}
func TestGlyphIndex(t *testing.T) {
data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/cmapTest.ttf"))
if err != nil {
t.Fatal(err)
}
for _, format := range []int{-1, 0, 4, 12} {
testGlyphIndex(t, data, format)
}
}
func testGlyphIndex(t *testing.T, data []byte, cmapFormat int) {
if cmapFormat >= 0 {
originalSupportedCmapFormat := supportedCmapFormat
defer func() {
supportedCmapFormat = originalSupportedCmapFormat
}()
supportedCmapFormat = func(format, pid, psid uint16) bool {
return int(format) == cmapFormat && originalSupportedCmapFormat(format, pid, psid)
}
}
f, err := Parse(data)
if err != nil {
t.Errorf("cmapFormat=%d: %v", cmapFormat, err)
return
}
testCases := []struct {
r rune
want GlyphIndex
}{
// Glyphs that aren't present in cmapTest.ttf.
{'?', 0},
{'\ufffd', 0},
{'\U0001f4a9', 0},
// For a .TTF file, FontForge maps:
// - ".notdef" to glyph index 0.
// - ".null" to glyph index 1.
// - "nonmarkingreturn" to glyph index 2.
{'/', 0},
{'0', 3},
{'1', 4},
{'2', 5},
{'3', 0},
{'@', 0},
{'A', 6},
{'B', 7},
{'C', 0},
{'`', 0},
{'a', 8},
{'b', 0},
// Of the remaining runes, only U+00FF LATIN SMALL LETTER Y WITH
// DIAERESIS is in both the Mac Roman encoding and the cmapTest.ttf
// font file.
{'\u00fe', 0},
{'\u00ff', 9},
{'\u0100', 10},
{'\u0101', 11},
{'\u0102', 0},
{'\u4e2c', 0},
{'\u4e2d', 12},
{'\u4e2e', 0},
{'\U0001f0a0', 0},
{'\U0001f0a1', 13},
{'\U0001f0a2', 0},
{'\U0001f0b0', 0},
{'\U0001f0b1', 14},
{'\U0001f0b2', 15},
{'\U0001f0b3', 0},
}
var b Buffer
for _, tc := range testCases {
want := tc.want
switch {
case cmapFormat == 0 && tc.r > '\u007f' && tc.r != '\u00ff':
// cmap format 0, with the Macintosh Roman encoding, can only
// represent a limited set of non-ASCII runes, e.g. U+00FF.
want = 0
case cmapFormat == 4 && tc.r > '\uffff':
// cmap format 4 only supports the Basic Multilingual Plane (BMP).
want = 0
}
got, err := f.GlyphIndex(&b, tc.r)
if err != nil {
t.Errorf("cmapFormat=%d, r=%q: %v", cmapFormat, tc.r, err)
continue
}
if got != want {
t.Errorf("cmapFormat=%d, r=%q: got %d, want %d", cmapFormat, tc.r, got, want)
continue
}
}
}
func TestPostScriptSegments(t *testing.T) {
// wants' vectors correspond 1-to-1 to what's in the CFFTest.sfd file,
// although OpenType/CFF and FontForge's SFD have reversed orders.
// https://fontforge.github.io/validation.html says that "All paths must be
// drawn in a consistent direction. Clockwise for external paths,
// anti-clockwise for internal paths. (Actually PostScript requires the
// exact opposite, but FontForge reverses PostScript contours when it loads
// them so that everything is consistant internally -- and reverses them
// again when it saves them, of course)."
//
// The .notdef glyph isn't explicitly in the SFD file, but for some unknown
// reason, FontForge generates it in the OpenType/CFF file.
wants := [][]Segment{{
// .notdef
// - contour #0
moveTo(50, 0),
lineTo(450, 0),
lineTo(450, 533),
lineTo(50, 533),
lineTo(50, 0),
// - contour #1
moveTo(100, 50),
lineTo(100, 483),
lineTo(400, 483),
lineTo(400, 50),
lineTo(100, 50),
}, {
// zero
// - contour #0
moveTo(300, 700),
cubeTo(380, 700, 420, 580, 420, 500),
cubeTo(420, 350, 390, 100, 300, 100),
cubeTo(220, 100, 180, 220, 180, 300),
cubeTo(180, 450, 210, 700, 300, 700),
// - contour #1
moveTo(300, 800),
cubeTo(200, 800, 100, 580, 100, 400),
cubeTo(100, 220, 200, 0, 300, 0),
cubeTo(400, 0, 500, 220, 500, 400),
cubeTo(500, 580, 400, 800, 300, 800),
}, {
// one
// - contour #0
moveTo(100, 0),
lineTo(300, 0),
lineTo(300, 800),
lineTo(100, 800),
lineTo(100, 0),
}, {
// Q
// - contour #0
moveTo(657, 237),
lineTo(289, 387),
lineTo(519, 615),
lineTo(657, 237),
// - contour #1
moveTo(792, 169),
cubeTo(867, 263, 926, 502, 791, 665),
cubeTo(645, 840, 380, 831, 228, 673),
cubeTo(71, 509, 110, 231, 242, 93),
cubeTo(369, -39, 641, 18, 722, 93),
lineTo(802, 3),
lineTo(864, 83),
lineTo(792, 169),
}, {
// uni4E2D
// - contour #0
moveTo(141, 520),
lineTo(137, 356),
lineTo(245, 400),
lineTo(331, 26),
lineTo(355, 414),
lineTo(463, 434),
lineTo(453, 620),
lineTo(341, 592),
lineTo(331, 758),
lineTo(243, 752),
lineTo(235, 562),
lineTo(141, 520),
}}
testSegments(t, "CFFTest.otf", wants)
}
func TestTrueTypeSegments(t *testing.T) {
// wants' vectors correspond 1-to-1 to what's in the glyfTest.sfd file,
// although FontForge's SFD format stores quadratic Bézier curves as cubics
// with duplicated off-curve points. quadTo(bx, by, cx, cy) is stored as
// "bx by bx by cx cy".
//
// The .notdef, .null and nonmarkingreturn glyphs aren't explicitly in the
// SFD file, but for some unknown reason, FontForge generates them in the
// TrueType file.
wants := [][]Segment{{
// .notdef
// - contour #0
moveTo(68, 0),
lineTo(68, 1365),
lineTo(612, 1365),
lineTo(612, 0),
lineTo(68, 0),
// - contour #1
moveTo(136, 68),
lineTo(544, 68),
lineTo(544, 1297),
lineTo(136, 1297),
lineTo(136, 68),
}, {
// .null
// Empty glyph.
}, {
// nonmarkingreturn
// Empty glyph.
}, {
// zero
// - contour #0
moveTo(614, 1434),
quadTo(369, 1434, 369, 614),
quadTo(369, 471, 435, 338),
quadTo(502, 205, 614, 205),
quadTo(860, 205, 860, 1024),
quadTo(860, 1167, 793, 1300),
quadTo(727, 1434, 614, 1434),
// - contour #1
moveTo(614, 1638),
quadTo(1024, 1638, 1024, 819),
quadTo(1024, 0, 614, 0),
quadTo(205, 0, 205, 819),
quadTo(205, 1638, 614, 1638),
}, {
// one
// - contour #0
moveTo(205, 0),
lineTo(205, 1638),
lineTo(614, 1638),
lineTo(614, 0),
lineTo(205, 0),
}, {
// five
// - contour #0
moveTo(0, 0),
lineTo(0, 100),
lineTo(400, 100),
lineTo(400, 0),
lineTo(0, 0),
}, {
// six
// - contour #0
moveTo(0, 0),
lineTo(0, 100),
lineTo(400, 100),
lineTo(400, 0),
lineTo(0, 0),
// - contour #1
translate(111, 234, moveTo(205, 0)),
translate(111, 234, lineTo(205, 1638)),
translate(111, 234, lineTo(614, 1638)),
translate(111, 234, lineTo(614, 0)),
translate(111, 234, lineTo(205, 0)),
}, {
// seven
// - contour #0
moveTo(0, 0),
lineTo(0, 100),
lineTo(400, 100),
lineTo(400, 0),
lineTo(0, 0),
// - contour #1
transform(1<<13, 0, 0, 1<<13, 56, 117, moveTo(205, 0)),
transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 1638)),
transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 1638)),
transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 0)),
transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 0)),
}, {
// eight
// - contour #0
moveTo(0, 0),
lineTo(0, 100),
lineTo(400, 100),
lineTo(400, 0),
lineTo(0, 0),
// - contour #1
transform(3<<13, 0, 0, 1<<13, 56, 117, moveTo(205, 0)),
transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 1638)),
transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 1638)),
transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 0)),
transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 0)),
}, {
// nine
// - contour #0
moveTo(0, 0),
lineTo(0, 100),
lineTo(400, 100),
lineTo(400, 0),
lineTo(0, 0),
// - contour #1
transform(22381, 8192, 5996, 14188, 237, 258, moveTo(205, 0)),
transform(22381, 8192, 5996, 14188, 237, 258, lineTo(205, 1638)),
transform(22381, 8192, 5996, 14188, 237, 258, lineTo(614, 1638)),
transform(22381, 8192, 5996, 14188, 237, 258, lineTo(614, 0)),
transform(22381, 8192, 5996, 14188, 237, 258, lineTo(205, 0)),
}}
testSegments(t, "glyfTest.ttf", wants)
}
func testSegments(t *testing.T, filename string, wants [][]Segment) {
data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/" + filename))
if err != nil {
t.Fatalf("ReadFile: %v", err)
}
f, err := Parse(data)
if err != nil {
t.Fatalf("Parse: %v", err)
}
ppem := fixed.Int26_6(f.UnitsPerEm())
if ng := f.NumGlyphs(); ng != len(wants) {
t.Fatalf("NumGlyphs: got %d, want %d", ng, len(wants))
}
var b Buffer
for i, want := range wants {
got, err := f.LoadGlyph(&b, GlyphIndex(i), ppem, nil)
if err != nil {
t.Errorf("i=%d: LoadGlyph: %v", i, err)
continue
}
if err := checkSegmentsEqual(got, want); err != nil {
t.Errorf("i=%d: %v", i, err)
continue
}
}
if _, err := f.LoadGlyph(nil, 0xffff, ppem, nil); err != ErrNotFound {
t.Errorf("LoadGlyph(..., 0xffff, ...):\ngot %v\nwant %v", err, ErrNotFound)
}
name, err := f.Name(nil, NameIDFamily)
if err != nil {
t.Errorf("Name: %v", err)
} else if want := filename[:len(filename)-len(".ttf")]; name != want {
t.Errorf("Name:\ngot %q\nwant %q", name, want)
}
}
func TestPPEM(t *testing.T) {
data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/glyfTest.ttf"))
if err != nil {
t.Fatalf("ReadFile: %v", err)
}
f, err := Parse(data)
if err != nil {
t.Fatalf("Parse: %v", err)
}
var b Buffer
x, err := f.GlyphIndex(&b, '1')
if err != nil {
t.Fatalf("GlyphIndex: %v", err)
}
if x == 0 {
t.Fatalf("GlyphIndex: no glyph index found for the rune '1'")
}
testCases := []struct {
ppem fixed.Int26_6
want []Segment
}{{
ppem: fixed.Int26_6(12 << 6),
want: []Segment{
moveTo(77, 0),
lineTo(77, 614),
lineTo(230, 614),
lineTo(230, 0),
lineTo(77, 0),
},
}, {
ppem: fixed.Int26_6(2048),
want: []Segment{
moveTo(205, 0),
lineTo(205, 1638),
lineTo(614, 1638),
lineTo(614, 0),
lineTo(205, 0),
},
}}
for i, tc := range testCases {
got, err := f.LoadGlyph(&b, x, tc.ppem, nil)
if err != nil {
t.Errorf("i=%d: LoadGlyph: %v", i, err)
continue
}
if err := checkSegmentsEqual(got, tc.want); err != nil {
t.Errorf("i=%d: %v", i, err)
continue
}
}
}
func TestGlyphName(t *testing.T) {
f, err := Parse(goregular.TTF)
if err != nil {
t.Fatalf("Parse: %v", err)
}
testCases := []struct {
r rune
want string
}{
{'\x00', "uni0000"},
{'!', "exclam"},
{'A', "A"},
{'{', "braceleft"},
{'\u00c4', "Adieresis"}, // U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS
{'\u2020', "dagger"}, // U+2020 DAGGER
{'\u2660', "spade"}, // U+2660 BLACK SPADE SUIT
{'\uf800', "gopher"}, // U+F800 <Private Use>
{'\ufffe', ".notdef"}, // Not in the Go Regular font, so GlyphIndex returns (0, nil).
}
var b Buffer
for _, tc := range testCases {
x, err := f.GlyphIndex(&b, tc.r)
if err != nil {
t.Errorf("r=%q: GlyphIndex: %v", tc.r, err)
continue
}
got, err := f.GlyphName(&b, x)
if err != nil {
t.Errorf("r=%q: GlyphName: %v", tc.r, err)
continue
}
if got != tc.want {
t.Errorf("r=%q: got %q, want %q", tc.r, got, tc.want)
continue
}
}
}
func TestBuiltInPostNames(t *testing.T) {
testCases := []struct {
x GlyphIndex
want string
}{
{0, ".notdef"},
{1, ".null"},
{2, "nonmarkingreturn"},
{13, "asterisk"},
{36, "A"},
{93, "z"},
{123, "ocircumflex"},
{202, "Edieresis"},
{255, "Ccaron"},
{256, "ccaron"},
{257, "dcroat"},
{258, ""},
{999, ""},
{0xffff, ""},
}
for _, tc := range testCases {
if tc.x >= numBuiltInPostNames {
continue
}
i := builtInPostNamesOffsets[tc.x+0]
j := builtInPostNamesOffsets[tc.x+1]
got := builtInPostNamesData[i:j]
if got != tc.want {
t.Errorf("x=%d: got %q, want %q", tc.x, got, tc.want)
}
}
}

View File

@ -1,572 +0,0 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sfnt
import (
"golang.org/x/image/math/fixed"
)
// Flags for simple (non-compound) glyphs.
//
// See https://www.microsoft.com/typography/OTSPEC/glyf.htm
const (
flagOnCurve = 1 << 0 // 0x0001
flagXShortVector = 1 << 1 // 0x0002
flagYShortVector = 1 << 2 // 0x0004
flagRepeat = 1 << 3 // 0x0008
// The same flag bits are overloaded to have two meanings, dependent on the
// value of the flag{X,Y}ShortVector bits.
flagPositiveXShortVector = 1 << 4 // 0x0010
flagThisXIsSame = 1 << 4 // 0x0010
flagPositiveYShortVector = 1 << 5 // 0x0020
flagThisYIsSame = 1 << 5 // 0x0020
)
// Flags for compound glyphs.
//
// See https://www.microsoft.com/typography/OTSPEC/glyf.htm
const (
flagArg1And2AreWords = 1 << 0 // 0x0001
flagArgsAreXYValues = 1 << 1 // 0x0002
flagRoundXYToGrid = 1 << 2 // 0x0004
flagWeHaveAScale = 1 << 3 // 0x0008
flagReserved4 = 1 << 4 // 0x0010
flagMoreComponents = 1 << 5 // 0x0020
flagWeHaveAnXAndYScale = 1 << 6 // 0x0040
flagWeHaveATwoByTwo = 1 << 7 // 0x0080
flagWeHaveInstructions = 1 << 8 // 0x0100
flagUseMyMetrics = 1 << 9 // 0x0200
flagOverlapCompound = 1 << 10 // 0x0400
flagScaledComponentOffset = 1 << 11 // 0x0800
flagUnscaledComponentOffset = 1 << 12 // 0x1000
)
func midPoint(p, q fixed.Point26_6) fixed.Point26_6 {
return fixed.Point26_6{
X: (p.X + q.X) / 2,
Y: (p.Y + q.Y) / 2,
}
}
func parseLoca(src *source, loca table, glyfOffset uint32, indexToLocFormat bool, numGlyphs int32) (locations []uint32, err error) {
if indexToLocFormat {
if loca.length != 4*uint32(numGlyphs+1) {
return nil, errInvalidLocaTable
}
} else {
if loca.length != 2*uint32(numGlyphs+1) {
return nil, errInvalidLocaTable
}
}
locations = make([]uint32, numGlyphs+1)
buf, err := src.view(nil, int(loca.offset), int(loca.length))
if err != nil {
return nil, err
}
if indexToLocFormat {
for i := range locations {
locations[i] = 1*uint32(u32(buf[4*i:])) + glyfOffset
}
} else {
for i := range locations {
locations[i] = 2*uint32(u16(buf[2*i:])) + glyfOffset
}
}
return locations, err
}
// https://www.microsoft.com/typography/OTSPEC/glyf.htm says that "Each
// glyph begins with the following [10 byte] header".
const glyfHeaderLen = 10
func loadGlyf(f *Font, b *Buffer, x GlyphIndex, stackBottom, recursionDepth uint32) error {
data, _, _, err := f.viewGlyphData(b, x)
if err != nil {
return err
}
if len(data) == 0 {
return nil
}
if len(data) < glyfHeaderLen {
return errInvalidGlyphData
}
index := glyfHeaderLen
numContours, numPoints := int16(u16(data)), 0
switch {
case numContours == -1:
// We have a compound glyph. No-op.
case numContours == 0:
return nil
case numContours > 0:
// We have a simple (non-compound) glyph.
index += 2 * int(numContours)
if index > len(data) {
return errInvalidGlyphData
}
// The +1 for numPoints is because the value in the file format is
// inclusive, but Go's slice[:index] semantics are exclusive.
numPoints = 1 + int(u16(data[index-2:]))
default:
return errInvalidGlyphData
}
if numContours < 0 {
return loadCompoundGlyf(f, b, data[glyfHeaderLen:], stackBottom, recursionDepth)
}
// Skip the hinting instructions.
index += 2
if index > len(data) {
return errInvalidGlyphData
}
hintsLength := int(u16(data[index-2:]))
index += hintsLength
if index > len(data) {
return errInvalidGlyphData
}
// For simple (non-compound) glyphs, the remainder of the glyf data
// consists of (flags, x, y) points: the Bézier curve segments. These are
// stored in columns (all the flags first, then all the x coordinates, then
// all the y coordinates), not rows, as it compresses better.
//
// Decoding those points in row order involves two passes. The first pass
// determines the indexes (relative to the data slice) of where the flags,
// the x coordinates and the y coordinates each start.
flagIndex := int32(index)
xIndex, yIndex, ok := findXYIndexes(data, index, numPoints)
if !ok {
return errInvalidGlyphData
}
// The second pass decodes each (flags, x, y) tuple in row order.
g := glyfIter{
data: data,
flagIndex: flagIndex,
xIndex: xIndex,
yIndex: yIndex,
endIndex: glyfHeaderLen,
// The -1 is because the contour-end index in the file format is
// inclusive, but Go's slice[:index] semantics are exclusive.
prevEnd: -1,
numContours: int32(numContours),
}
for g.nextContour() {
for g.nextSegment() {
b.segments = append(b.segments, g.seg)
}
}
return g.err
}
func findXYIndexes(data []byte, index, numPoints int) (xIndex, yIndex int32, ok bool) {
xDataLen := 0
yDataLen := 0
for i := 0; ; {
if i > numPoints {
return 0, 0, false
}
if i == numPoints {
break
}
repeatCount := 1
if index >= len(data) {
return 0, 0, false
}
flag := data[index]
index++
if flag&flagRepeat != 0 {
if index >= len(data) {
return 0, 0, false
}
repeatCount += int(data[index])
index++
}
xSize := 0
if flag&flagXShortVector != 0 {
xSize = 1
} else if flag&flagThisXIsSame == 0 {
xSize = 2
}
xDataLen += xSize * repeatCount
ySize := 0
if flag&flagYShortVector != 0 {
ySize = 1
} else if flag&flagThisYIsSame == 0 {
ySize = 2
}
yDataLen += ySize * repeatCount
i += repeatCount
}
if index+xDataLen+yDataLen > len(data) {
return 0, 0, false
}
return int32(index), int32(index + xDataLen), true
}
func loadCompoundGlyf(f *Font, b *Buffer, data []byte, stackBottom, recursionDepth uint32) error {
if recursionDepth++; recursionDepth == maxCompoundRecursionDepth {
return errUnsupportedCompoundGlyph
}
// Read and process the compound glyph's components. They are two separate
// for loops, since reading parses the elements of the data slice, and
// processing can overwrite the backing array.
stackTop := stackBottom
for {
if stackTop >= maxCompoundStackSize {
return errUnsupportedCompoundGlyph
}
elem := &b.compoundStack[stackTop]
stackTop++
if len(data) < 4 {
return errInvalidGlyphData
}
flags := u16(data)
elem.glyphIndex = GlyphIndex(u16(data[2:]))
if flags&flagArg1And2AreWords == 0 {
if len(data) < 6 {
return errInvalidGlyphData
}
elem.dx = int16(int8(data[4]))
elem.dy = int16(int8(data[5]))
data = data[6:]
} else {
if len(data) < 8 {
return errInvalidGlyphData
}
elem.dx = int16(u16(data[4:]))
elem.dy = int16(u16(data[6:]))
data = data[8:]
}
if flags&flagArgsAreXYValues == 0 {
return errUnsupportedCompoundGlyph
}
elem.hasTransform = flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0
if elem.hasTransform {
switch {
case flags&flagWeHaveAScale != 0:
if len(data) < 2 {
return errInvalidGlyphData
}
elem.transformXX = int16(u16(data))
elem.transformXY = 0
elem.transformYX = 0
elem.transformYY = elem.transformXX
data = data[2:]
case flags&flagWeHaveAnXAndYScale != 0:
if len(data) < 4 {
return errInvalidGlyphData
}
elem.transformXX = int16(u16(data[0:]))
elem.transformXY = 0
elem.transformYX = 0
elem.transformYY = int16(u16(data[2:]))
data = data[4:]
case flags&flagWeHaveATwoByTwo != 0:
if len(data) < 8 {
return errInvalidGlyphData
}
elem.transformXX = int16(u16(data[0:]))
elem.transformXY = int16(u16(data[2:]))
elem.transformYX = int16(u16(data[4:]))
elem.transformYY = int16(u16(data[6:]))
data = data[8:]
}
}
if flags&flagMoreComponents == 0 {
break
}
}
// To support hinting, we'd have to save the remaining bytes in data here
// and interpret them after the for loop below, since that for loop's
// loadGlyf calls can overwrite the backing array.
for i := stackBottom; i < stackTop; i++ {
elem := &b.compoundStack[i]
base := len(b.segments)
if err := loadGlyf(f, b, elem.glyphIndex, stackTop, recursionDepth); err != nil {
return err
}
dx, dy := fixed.Int26_6(elem.dx), fixed.Int26_6(elem.dy)
segs := b.segments[base:]
if elem.hasTransform {
txx := elem.transformXX
txy := elem.transformXY
tyx := elem.transformYX
tyy := elem.transformYY
for j := range segs {
transformArgs(&segs[j].Args, txx, txy, tyx, tyy, dx, dy)
}
} else {
for j := range segs {
translateArgs(&segs[j].Args, dx, dy)
}
}
}
return nil
}
type glyfIter struct {
data []byte
err error
// Various indices into the data slice. See the "Decoding those points in
// row order" comment above.
flagIndex int32
xIndex int32
yIndex int32
// endIndex points to the uint16 that is the inclusive point index of the
// current contour's end. prevEnd is the previous contour's end.
endIndex int32
prevEnd int32
// c and p count the current contour and point, up to numContours and
// numPoints.
c, numContours int32
p, nPoints int32
// The next two groups of fields track points and segments. Points are what
// the underlying file format provides. Bézier curve segments are what the
// rasterizer consumes.
//
// Points are either on-curve or off-curve. Two consecutive on-curve points
// define a linear curve segment between them. N off-curve points between
// on-curve points define N quadratic curve segments. The TrueType glyf
// format does not use cubic curves. If N is greater than 1, some of these
// segment end points are implicit, the midpoint of two off-curve points.
// Given the points A, B1, B2, ..., BN, C, where A and C are on-curve and
// all the Bs are off-curve, the segments are:
//
// - A, B1, midpoint(B1, B2)
// - midpoint(B1, B2), B2, midpoint(B2, B3)
// - midpoint(B2, B3), B3, midpoint(B3, B4)
// - ...
// - midpoint(BN-1, BN), BN, C
//
// Note that the sequence of Bs may wrap around from the last point in the
// glyf data to the first. A and C may also be the same point (the only
// explicit on-curve point), or there may be no explicit on-curve points at
// all (but still implicit ones between explicit off-curve points).
// Points.
x, y int16
on bool
flag uint8
repeats uint8
// Segments.
closing bool
closed bool
firstOnCurveValid bool
firstOffCurveValid bool
lastOffCurveValid bool
firstOnCurve fixed.Point26_6
firstOffCurve fixed.Point26_6
lastOffCurve fixed.Point26_6
seg Segment
}
func (g *glyfIter) nextContour() (ok bool) {
if g.c == g.numContours {
return false
}
g.c++
end := int32(u16(g.data[g.endIndex:]))
g.endIndex += 2
if end <= g.prevEnd {
g.err = errInvalidGlyphData
return false
}
g.nPoints = end - g.prevEnd
g.p = 0
g.prevEnd = end
g.closing = false
g.closed = false
g.firstOnCurveValid = false
g.firstOffCurveValid = false
g.lastOffCurveValid = false
return true
}
func (g *glyfIter) close() {
switch {
case !g.firstOffCurveValid && !g.lastOffCurveValid:
g.closed = true
g.seg = Segment{
Op: SegmentOpLineTo,
Args: [3]fixed.Point26_6{g.firstOnCurve},
}
case !g.firstOffCurveValid && g.lastOffCurveValid:
g.closed = true
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{g.lastOffCurve, g.firstOnCurve},
}
case g.firstOffCurveValid && !g.lastOffCurveValid:
g.closed = true
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{g.firstOffCurve, g.firstOnCurve},
}
case g.firstOffCurveValid && g.lastOffCurveValid:
g.lastOffCurveValid = false
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{
g.lastOffCurve,
midPoint(g.lastOffCurve, g.firstOffCurve),
},
}
}
}
func (g *glyfIter) nextSegment() (ok bool) {
for !g.closed {
if g.closing || !g.nextPoint() {
g.closing = true
g.close()
return true
}
// Convert the tuple (g.x, g.y) to a fixed.Point26_6, since the latter
// is what's held in a Segment. The input (g.x, g.y) is a pair of int16
// values, measured in font units, since that is what the underlying
// format provides. The output is a pair of fixed.Int26_6 values. A
// fixed.Int26_6 usually represents a 26.6 fixed number of pixels, but
// this here is just a straight numerical conversion, with no scaling
// factor. A later step scales the Segment.Args values by such a factor
// to convert e.g. 1792 font units to 10.5 pixels at 2048 font units
// per em and 12 ppem (pixels per em).
p := fixed.Point26_6{
X: fixed.Int26_6(g.x),
Y: fixed.Int26_6(g.y),
}
if !g.firstOnCurveValid {
if g.on {
g.firstOnCurve = p
g.firstOnCurveValid = true
g.seg = Segment{
Op: SegmentOpMoveTo,
Args: [3]fixed.Point26_6{p},
}
return true
} else if !g.firstOffCurveValid {
g.firstOffCurve = p
g.firstOffCurveValid = true
continue
} else {
g.firstOnCurve = midPoint(g.firstOffCurve, p)
g.firstOnCurveValid = true
g.lastOffCurve = p
g.lastOffCurveValid = true
g.seg = Segment{
Op: SegmentOpMoveTo,
Args: [3]fixed.Point26_6{g.firstOnCurve},
}
return true
}
} else if !g.lastOffCurveValid {
if !g.on {
g.lastOffCurve = p
g.lastOffCurveValid = true
continue
} else {
g.seg = Segment{
Op: SegmentOpLineTo,
Args: [3]fixed.Point26_6{p},
}
return true
}
} else {
if !g.on {
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{
g.lastOffCurve,
midPoint(g.lastOffCurve, p),
},
}
g.lastOffCurve = p
g.lastOffCurveValid = true
return true
} else {
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{g.lastOffCurve, p},
}
g.lastOffCurveValid = false
return true
}
}
}
return false
}
func (g *glyfIter) nextPoint() (ok bool) {
if g.p == g.nPoints {
return false
}
g.p++
if g.repeats > 0 {
g.repeats--
} else {
g.flag = g.data[g.flagIndex]
g.flagIndex++
if g.flag&flagRepeat != 0 {
g.repeats = g.data[g.flagIndex]
g.flagIndex++
}
}
if g.flag&flagXShortVector != 0 {
if g.flag&flagPositiveXShortVector != 0 {
g.x += int16(g.data[g.xIndex])
} else {
g.x -= int16(g.data[g.xIndex])
}
g.xIndex += 1
} else if g.flag&flagThisXIsSame == 0 {
g.x += int16(u16(g.data[g.xIndex:]))
g.xIndex += 2
}
if g.flag&flagYShortVector != 0 {
if g.flag&flagPositiveYShortVector != 0 {
g.y += int16(g.data[g.yIndex])
} else {
g.y -= int16(g.data[g.yIndex])
}
g.yIndex += 1
} else if g.flag&flagThisYIsSame == 0 {
g.y += int16(u16(g.data[g.yIndex:]))
g.yIndex += 2
}
g.on = g.flag&flagOnCurve != 0
return true
}

Binary file not shown.

View File

@ -1,148 +0,0 @@
SplineFontDB: 3.0
FontName: CFFTest
FullName: CFFTest
FamilyName: CFFTest
Weight: Regular
Copyright: Copyright 2016 The Go Authors. All rights reserved.\nUse of this font is governed by a BSD-style license that can be found at https://golang.org/LICENSE.
Version: 001.000
ItalicAngle: -11.25
UnderlinePosition: -100
UnderlineWidth: 50
Ascent: 800
Descent: 200
LayerCount: 2
Layer: 0 0 "Back" 1
Layer: 1 0 "Fore" 0
XUID: [1021 367 888937226 7862908]
FSType: 8
OS2Version: 0
OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 1
CreationTime: 1479626795
ModificationTime: 1481282599
PfmFamily: 17
TTFWeight: 400
TTFWidth: 5
LineGap: 90
VLineGap: 0
OS2TypoAscent: 0
OS2TypoAOffset: 1
OS2TypoDescent: 0
OS2TypoDOffset: 1
OS2TypoLinegap: 90
OS2WinAscent: 0
OS2WinAOffset: 1
OS2WinDescent: 0
OS2WinDOffset: 1
HheadAscent: 0
HheadAOffset: 1
HheadDescent: 0
HheadDOffset: 1
OS2Vendor: 'PfEd'
MarkAttachClasses: 1
DEI: 91125
LangName: 1033
Encoding: UnicodeBmp
UnicodeInterp: none
NameList: Adobe Glyph List
DisplaySize: -24
AntiAlias: 1
FitToEm: 1
WinInfo: 64 32 11
BeginPrivate: 0
EndPrivate
TeXData: 1 0 0 346030 173015 115343 0 1048576 115343 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144
BeginChars: 65536 4
StartChar: zero
Encoding: 48 48 0
Width: 600
VWidth: 0
HStem: 0 100<248.223 341.575> 700 100<258.425 351.777>
VStem: 100 80<243.925 531.374> 420 80<268.627 556.075>
LayerCount: 2
Fore
SplineSet
300 700 m 0
210 700 180 450 180 300 c 24
180 220 220 100 300 100 c 0
390 100 420 350 420 500 c 24
420 580 380 700 300 700 c 0
300 800 m 0
400 800 500 580 500 400 c 0
500 220 400 0 300 0 c 0
200 0 100 220 100 400 c 0
100 580 200 800 300 800 c 0
EndSplineSet
Validated: 1
EndChar
StartChar: one
Encoding: 49 49 1
Width: 400
VWidth: 0
Flags: W
HStem: 0 21G<100 300>
VStem: 100 200<0 800>
LayerCount: 2
Fore
SplineSet
100 0 m 25
100 800 l 25
300 800 l 29
300 0 l 29
100 0 l 25
EndSplineSet
Validated: 1
EndChar
StartChar: uni4E2D
Encoding: 20013 20013 2
Width: 600
VWidth: 0
Flags: W
VStem: 245 86<641.8 752>
LayerCount: 2
Fore
SplineSet
141 520 m 25
235 562 l 25
243 752 l 25
331 758 l 25
341 592 l 25
453 620 l 25
463 434 l 25
355 414 l 25
331 26 l 25
245 400 l 25
137 356 l 25
141 520 l 25
EndSplineSet
Validated: 1
EndChar
StartChar: Q
Encoding: 81 81 3
Width: 1000
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
657 237 m 0
519 615 l 0
289 387 l 0
657 237 l 0
792 169 m 1
864 83 l 25
802 3 l 21
722 93 l 1
641 18 369 -39 242 93 c 0
110 231 71 509 228 673 c 24
380 831 645 840 791 665 c 0
926 502 867 263 792 169 c 1
EndSplineSet
Validated: 33
EndChar
EndChars
EndSplineFont

View File

@ -1,2 +0,0 @@
CFFTest.sfd is a FontForge file for creating CFFTest.otf, a custom OpenType
font for testing the golang.org/x/image/font/sfnt package's CFF support.

View File

@ -1,265 +0,0 @@
SplineFontDB: 3.0
FontName: cmapTest
FullName: cmapTest
FamilyName: cmapTest
Weight: Regular
Copyright: Copyright 2016 The Go Authors. All rights reserved.\nUse of this font is governed by a BSD-style license that can be found at https://golang.org/LICENSE.
Version: 001.000
ItalicAngle: -11.25
UnderlinePosition: -204
UnderlineWidth: 102
Ascent: 1638
Descent: 410
LayerCount: 2
Layer: 0 1 "Back" 1
Layer: 1 1 "Fore" 0
XUID: [1021 367 888937226 7862908]
FSType: 8
OS2Version: 0
OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 1
CreationTime: 1484386143
ModificationTime: 1486021330
PfmFamily: 17
TTFWeight: 400
TTFWidth: 5
LineGap: 184
VLineGap: 0
OS2TypoAscent: 0
OS2TypoAOffset: 1
OS2TypoDescent: 0
OS2TypoDOffset: 1
OS2TypoLinegap: 184
OS2WinAscent: 0
OS2WinAOffset: 1
OS2WinDescent: 0
OS2WinDOffset: 1
HheadAscent: 0
HheadAOffset: 1
HheadDescent: 0
HheadDOffset: 1
OS2Vendor: 'PfEd'
MarkAttachClasses: 1
DEI: 91125
LangName: 1033
Encoding: UnicodeFull
UnicodeInterp: none
NameList: Adobe Glyph List
DisplaySize: -24
AntiAlias: 1
FitToEm: 1
WinInfo: 126976 32 23
BeginPrivate: 0
EndPrivate
TeXData: 1 0 0 346030 173015 115343 0 -1048576 115343 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144
BeginChars: 1114112 13
StartChar: zero
Encoding: 48 48 0
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: one
Encoding: 49 49 1
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: two
Encoding: 50 50 2
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: A
Encoding: 65 65 3
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: uni4E2D
Encoding: 20013 20013 4
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: u1F0A1
Encoding: 127137 127137 5
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: ydieresis
Encoding: 255 255 6
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: Amacron
Encoding: 256 256 7
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: amacron
Encoding: 257 257 8
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: B
Encoding: 66 66 9
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: a
Encoding: 97 97 10
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: u1F0B1
Encoding: 127153 127153 11
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: u1F0B2
Encoding: 127154 127154 12
Width: 800
VWidth: 0
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 29,0,-1
400 800 l 25,1,-1
800 0 l 25,2,-1
0 0 l 29,0,-1
EndSplineSet
Validated: 1
EndChar
EndChars
EndSplineFont

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +0,0 @@
These font files were copied from the Plan 9 Port's font/fixed directory. The
README in that directory states that: "These fonts are converted from the BDFs
in the XFree86 distribution. They were all marked as public domain."
The Plan 9 Port is at https://github.com/9fans/plan9port and the copy was made
from commit a78b1841 (2015-08-18).
The unicode.7x13.font file also refers to a ../shinonome directory, but this
testdata does not include those subfont files.

View File

@ -1,68 +0,0 @@
13 11
0x0000 0x001F 7x13.2400
0x0000 0x00FF 7x13.0000
0x0100 0x01FF 7x13.0100
0x0200 0x02FF 7x13.0200
0x0300 0x03FF 7x13.0300
0x0400 0x04FF 7x13.0400
0x0500 0x05FF 7x13.0500
0x0E00 0x0EFF 7x13.0E00
0x1000 0x10FF 7x13.1000
0x1600 0x16FF 7x13.1600
0x1E00 0x1EFF 7x13.1E00
0x1F00 0x1FFF 7x13.1F00
0x2000 0x20FF 7x13.2000
0x2100 0x21FF 7x13.2100
0x2200 0x22FF 7x13.2200
0x2300 0x23FF 7x13.2300
0x2400 0x24FF 7x13.2400
0x2500 0x25FF 7x13.2500
0x2600 0x26FF 7x13.2600
0x2700 0x27FF 7x13.2700
0x2800 0x28FF 7x13.2800
0x2A00 0x2AFF 7x13.2A00
0x3000 0x30fe ../shinonome/k12.3000
0x4e00 0x4ffe ../shinonome/k12.4e00
0x5005 0x51fe ../shinonome/k12.5005
0x5200 0x53fa ../shinonome/k12.5200
0x5401 0x55fe ../shinonome/k12.5401
0x5606 0x57fc ../shinonome/k12.5606
0x5800 0x59ff ../shinonome/k12.5800
0x5a01 0x5bff ../shinonome/k12.5a01
0x5c01 0x5dfe ../shinonome/k12.5c01
0x5e02 0x5fff ../shinonome/k12.5e02
0x600e 0x61ff ../shinonome/k12.600e
0x6200 0x63fa ../shinonome/k12.6200
0x6406 0x65fb ../shinonome/k12.6406
0x6602 0x67ff ../shinonome/k12.6602
0x6802 0x69ff ../shinonome/k12.6802
0x6a02 0x6bf3 ../shinonome/k12.6a02
0x6c08 0x6dfb ../shinonome/k12.6c08
0x6e05 0x6ffe ../shinonome/k12.6e05
0x7001 0x71ff ../shinonome/k12.7001
0x7206 0x73fe ../shinonome/k12.7206
0x7403 0x75ff ../shinonome/k12.7403
0x7601 0x77fc ../shinonome/k12.7601
0x7802 0x79fb ../shinonome/k12.7802
0x7a00 0x7bf7 ../shinonome/k12.7a00
0x7c00 0x7dfb ../shinonome/k12.7c00
0x7e01 0x7ffc ../shinonome/k12.7e01
0x8000 0x81fe ../shinonome/k12.8000
0x8201 0x83fd ../shinonome/k12.8201
0x8403 0x85fe ../shinonome/k12.8403
0x8602 0x87fe ../shinonome/k12.8602
0x8805 0x89f8 ../shinonome/k12.8805
0x8a00 0x8b9a ../shinonome/k12.8a00
0x8c37 0x8dff ../shinonome/k12.8c37
0x8e08 0x8ffd ../shinonome/k12.8e08
0x9000 0x91ff ../shinonome/k12.9000
0x920d 0x93e8 ../shinonome/k12.920d
0x9403 0x95e5 ../shinonome/k12.9403
0x961c 0x97ff ../shinonome/k12.961c
0x9801 0x99ff ../shinonome/k12.9801
0x9a01 0x9bf5 ../shinonome/k12.9a01
0x9c04 0x9dfd ../shinonome/k12.9c04
0x9e1a 0x9fa0 ../shinonome/k12.9e1a
0xFB00 0xFBFF 7x13.FB00
0xFE00 0xFEFF 7x13.FE00
0xFF00 0xFFFF 7x13.FF00

View File

@ -1,225 +0,0 @@
SplineFontDB: 3.0
FontName: glyfTest
FullName: glyfTest
FamilyName: glyfTest
Weight: Book
Copyright: Copyright 2016 The Go Authors. All rights reserved.\nUse of this font is governed by a BSD-style license that can be found at https://golang.org/LICENSE.
Version: 001.000
ItalicAngle: -11.25
UnderlinePosition: -204
UnderlineWidth: 102
Ascent: 1638
Descent: 410
sfntRevision: 0x00010000
LayerCount: 2
Layer: 0 1 "Back" 1
Layer: 1 1 "Fore" 0
XUID: [1021 367 888937226 5879518]
FSType: 8
OS2Version: 4
OS2_WeightWidthSlopeOnly: 0
OS2_UseTypoMetrics: 1
CreationTime: 1484386143
ModificationTime: 1489831626
PfmFamily: 17
TTFWeight: 400
TTFWidth: 5
LineGap: 184
VLineGap: 0
Panose: 2 0 5 3 0 0 0 0 0 0
OS2TypoAscent: 1638
OS2TypoAOffset: 0
OS2TypoDescent: -410
OS2TypoDOffset: 0
OS2TypoLinegap: 184
OS2WinAscent: 1984
OS2WinAOffset: 0
OS2WinDescent: 0
OS2WinDOffset: 0
HheadAscent: 1984
HheadAOffset: 0
HheadDescent: 0
HheadDOffset: 0
OS2SubXSize: 1331
OS2SubYSize: 1433
OS2SubXOff: 55
OS2SubYOff: 286
OS2SupXSize: 1331
OS2SupYSize: 1433
OS2SupXOff: -191
OS2SupYOff: 983
OS2StrikeYSize: 102
OS2StrikeYPos: 530
OS2Vendor: 'PfEd'
OS2CodePages: 00000001.00000000
OS2UnicodeRanges: 00000001.00000000.00000000.00000000
MarkAttachClasses: 1
DEI: 91125
ShortTable: cvt 2
68
1297
EndShort
ShortTable: maxp 16
1
0
10
18
2
8
2
2
0
1
1
0
64
46
2
1
EndShort
LangName: 1033 "" "" "Regular" "FontForge : glyfTest : 18-3-2017" "" "Version 001.000"
GaspTable: 1 65535 2 0
Encoding: UnicodeBmp
UnicodeInterp: none
NameList: Adobe Glyph List
DisplaySize: -24
AntiAlias: 1
FitToEm: 1
WinInfo: 0 32 23
BeginChars: 65539 10
StartChar: .notdef
Encoding: 65536 -1 0
Width: 748
Flags: W
LayerCount: 2
Fore
SplineSet
68 0 m 1,0,-1
68 1365 l 1,1,-1
612 1365 l 1,2,-1
612 0 l 1,3,-1
68 0 l 1,0,-1
136 68 m 1,4,-1
544 68 l 1,5,-1
544 1297 l 1,6,-1
136 1297 l 1,7,-1
136 68 l 1,4,-1
EndSplineSet
Validated: 1
EndChar
StartChar: .null
Encoding: 65537 -1 1
Width: 0
Flags: W
LayerCount: 2
EndChar
StartChar: nonmarkingreturn
Encoding: 65538 -1 2
Width: 682
Flags: W
LayerCount: 2
EndChar
StartChar: zero
Encoding: 48 48 3
Width: 1228
Flags: W
LayerCount: 2
Fore
SplineSet
614 1434 m 0,0,1
369 1434 369 1434 369 614 c 0,2,3
369 471 369 471 435 338 c 0,4,5
502 205 502 205 614 205 c 0,6,7
860 205 860 205 860 1024 c 0,8,9
860 1167 860 1167 793 1300 c 1,10,11
727 1434 727 1434 614 1434 c 0,0,1
614 1638 m 0,12,13
1024 1638 1024 1638 1024 819 c 128,-1,14
1024 0 1024 0 614 0 c 0,15,16
205 0 205 0 205 819 c 128,-1,17
205 1638 205 1638 614 1638 c 0,12,13
EndSplineSet
Validated: 1
EndChar
StartChar: one
Encoding: 49 49 4
Width: 819
Flags: W
LayerCount: 2
Fore
SplineSet
205 0 m 1,0,-1
205 1638 l 1,1,-1
614 1638 l 1,2,-1
614 0 l 1,3,-1
205 0 l 1,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: five
Encoding: 53 53 5
Width: 400
Flags: W
LayerCount: 2
Fore
SplineSet
0 0 m 1,0,-1
0 100 l 1,1,-1
400 100 l 1,2,-1
400 0 l 1,3,-1
0 0 l 1,0,-1
EndSplineSet
Validated: 1
EndChar
StartChar: six
Encoding: 54 54 6
Width: 400
Flags: W
LayerCount: 2
Fore
Refer: 5 53 N 1 0 0 1 0 0 2
Refer: 4 49 N 1 0 0 1 111 234 2
Validated: 1
EndChar
StartChar: seven
Encoding: 55 55 7
Width: 400
Flags: W
LayerCount: 2
Fore
Refer: 5 53 N 1 0 0 1 0 0 2
Refer: 4 49 N 0.5 0 0 0.5 56 117 2
Validated: 1
EndChar
StartChar: eight
Encoding: 56 56 8
Width: 400
Flags: W
LayerCount: 2
Fore
Refer: 5 53 N 1 0 0 1 0 0 2
Refer: 4 49 N 1.5 0 0 0.5 56 117 2
Validated: 1
EndChar
StartChar: nine
Encoding: 57 57 9
Width: 400
Flags: W
LayerCount: 2
Fore
Refer: 5 53 N 1 0 0 1 0 0 2
Refer: 4 49 N 1.36603 0.5 0.365967 0.865967 237 258 2
Validated: 1
EndChar
EndChars
EndSplineFont

Binary file not shown.

View File

@ -1,37 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package f32 implements float32 vector and matrix types.
package f32 // import "golang.org/x/image/math/f32"
// Vec2 is a 2-element vector.
type Vec2 [2]float32
// Vec3 is a 3-element vector.
type Vec3 [3]float32
// Vec4 is a 4-element vector.
type Vec4 [4]float32
// Mat3 is a 3x3 matrix in row major order.
//
// m[3*r + c] is the element in the r'th row and c'th column.
type Mat3 [9]float32
// Mat4 is a 4x4 matrix in row major order.
//
// m[4*r + c] is the element in the r'th row and c'th column.
type Mat4 [16]float32
// Aff3 is a 3x3 affine transformation matrix in row major order, where the
// bottom row is implicitly [0 0 1].
//
// m[3*r + c] is the element in the r'th row and c'th column.
type Aff3 [6]float32
// Aff4 is a 4x4 affine transformation matrix in row major order, where the
// bottom row is implicitly [0 0 0 1].
//
// m[4*r + c] is the element in the r'th row and c'th column.
type Aff4 [12]float32

Some files were not shown because too many files have changed in this diff Show More