vendor golang.org/x/image library
This commit is contained in:
parent
dcd3061482
commit
1659609ae1
10
vendor/golang.org/x/image/.gitattributes
generated
vendored
Normal file
10
vendor/golang.org/x/image/.gitattributes
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# 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
|
2
vendor/golang.org/x/image/.gitignore
generated
vendored
Normal file
2
vendor/golang.org/x/image/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Add no patterns to .hgignore except for files generated by the build.
|
||||
last-change
|
3
vendor/golang.org/x/image/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/image/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code refers to The Go Authors for copyright purposes.
|
||||
# The master list of authors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/AUTHORS.
|
26
vendor/golang.org/x/image/CONTRIBUTING.md
generated
vendored
Normal file
26
vendor/golang.org/x/image/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# 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.
|
3
vendor/golang.org/x/image/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/image/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# This source code was written by the Go contributors.
|
||||
# The master list of contributors is in the main Go distribution,
|
||||
# visible at http://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/image/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/image/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
22
vendor/golang.org/x/image/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/image/PATENTS
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
17
vendor/golang.org/x/image/README.md
generated
vendored
Normal file
17
vendor/golang.org/x/image/README.md
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# 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.
|
199
vendor/golang.org/x/image/bmp/reader.go
generated
vendored
Normal file
199
vendor/golang.org/x/image/bmp/reader.go
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
// Copyright 2011 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 implements a BMP image decoder and encoder.
|
||||
//
|
||||
// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
|
||||
package bmp // import "golang.org/x/image/bmp"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ErrUnsupported means that the input BMP image uses a valid but unsupported
|
||||
// feature.
|
||||
var ErrUnsupported = errors.New("bmp: unsupported BMP image")
|
||||
|
||||
func readUint16(b []byte) uint16 {
|
||||
return uint16(b[0]) | uint16(b[1])<<8
|
||||
}
|
||||
|
||||
func readUint32(b []byte) uint32 {
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
// decodePaletted reads an 8 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodePaletted(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
|
||||
paletted := image.NewPaletted(image.Rect(0, 0, c.Width, c.Height), c.ColorModel.(color.Palette))
|
||||
if c.Width == 0 || c.Height == 0 {
|
||||
return paletted, nil
|
||||
}
|
||||
var tmp [4]byte
|
||||
y0, y1, yDelta := c.Height-1, -1, -1
|
||||
if topDown {
|
||||
y0, y1, yDelta = 0, c.Height, +1
|
||||
}
|
||||
for y := y0; y != y1; y += yDelta {
|
||||
p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
|
||||
if _, err := io.ReadFull(r, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Each row is 4-byte aligned.
|
||||
if c.Width%4 != 0 {
|
||||
_, err := io.ReadFull(r, tmp[:4-c.Width%4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return paletted, nil
|
||||
}
|
||||
|
||||
// decodeRGB reads a 24 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodeRGB(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
|
||||
rgba := image.NewRGBA(image.Rect(0, 0, c.Width, c.Height))
|
||||
if c.Width == 0 || c.Height == 0 {
|
||||
return rgba, nil
|
||||
}
|
||||
// There are 3 bytes per pixel, and each row is 4-byte aligned.
|
||||
b := make([]byte, (3*c.Width+3)&^3)
|
||||
y0, y1, yDelta := c.Height-1, -1, -1
|
||||
if topDown {
|
||||
y0, y1, yDelta = 0, c.Height, +1
|
||||
}
|
||||
for y := y0; y != y1; y += yDelta {
|
||||
if _, err := io.ReadFull(r, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
|
||||
for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
|
||||
// BMP images are stored in BGR order rather than RGB order.
|
||||
p[i+0] = b[j+2]
|
||||
p[i+1] = b[j+1]
|
||||
p[i+2] = b[j+0]
|
||||
p[i+3] = 0xFF
|
||||
}
|
||||
}
|
||||
return rgba, nil
|
||||
}
|
||||
|
||||
// decodeNRGBA reads a 32 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodeNRGBA(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
|
||||
rgba := image.NewNRGBA(image.Rect(0, 0, c.Width, c.Height))
|
||||
if c.Width == 0 || c.Height == 0 {
|
||||
return rgba, nil
|
||||
}
|
||||
y0, y1, yDelta := c.Height-1, -1, -1
|
||||
if topDown {
|
||||
y0, y1, yDelta = 0, c.Height, +1
|
||||
}
|
||||
for y := y0; y != y1; y += yDelta {
|
||||
p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
|
||||
if _, err := io.ReadFull(r, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(p); i += 4 {
|
||||
// BMP images are stored in BGRA order rather than RGBA order.
|
||||
p[i+0], p[i+2] = p[i+2], p[i+0]
|
||||
}
|
||||
}
|
||||
return rgba, nil
|
||||
}
|
||||
|
||||
// Decode reads a BMP image from r and returns it as an image.Image.
|
||||
// Limitation: The file must be 8, 24 or 32 bits per pixel.
|
||||
func Decode(r io.Reader) (image.Image, error) {
|
||||
c, bpp, topDown, err := decodeConfig(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch bpp {
|
||||
case 8:
|
||||
return decodePaletted(r, c, topDown)
|
||||
case 24:
|
||||
return decodeRGB(r, c, topDown)
|
||||
case 32:
|
||||
return decodeNRGBA(r, c, topDown)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// DecodeConfig returns the color model and dimensions of a BMP image without
|
||||
// decoding the entire image.
|
||||
// Limitation: The file must be 8, 24 or 32 bits per pixel.
|
||||
func DecodeConfig(r io.Reader) (image.Config, error) {
|
||||
config, _, _, err := decodeConfig(r)
|
||||
return config, err
|
||||
}
|
||||
|
||||
func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown bool, err error) {
|
||||
// We only support those BMP images that are a BITMAPFILEHEADER
|
||||
// immediately followed by a BITMAPINFOHEADER.
|
||||
const (
|
||||
fileHeaderLen = 14
|
||||
infoHeaderLen = 40
|
||||
)
|
||||
var b [1024]byte
|
||||
if _, err := io.ReadFull(r, b[:fileHeaderLen+infoHeaderLen]); err != nil {
|
||||
return image.Config{}, 0, false, err
|
||||
}
|
||||
if string(b[:2]) != "BM" {
|
||||
return image.Config{}, 0, false, errors.New("bmp: invalid format")
|
||||
}
|
||||
offset := readUint32(b[10:14])
|
||||
if readUint32(b[14:18]) != infoHeaderLen {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
width := int(int32(readUint32(b[18:22])))
|
||||
height := int(int32(readUint32(b[22:26])))
|
||||
if height < 0 {
|
||||
height, topDown = -height, true
|
||||
}
|
||||
if width < 0 || height < 0 {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
// We only support 1 plane, 8 or 24 bits per pixel and no compression.
|
||||
planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
|
||||
if planes != 1 || compression != 0 {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
switch bpp {
|
||||
case 8:
|
||||
if offset != fileHeaderLen+infoHeaderLen+256*4 {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
_, err = io.ReadFull(r, b[:256*4])
|
||||
if err != nil {
|
||||
return image.Config{}, 0, false, err
|
||||
}
|
||||
pcm := make(color.Palette, 256)
|
||||
for i := range pcm {
|
||||
// BMP images are stored in BGR order rather than RGB order.
|
||||
// Every 4th byte is padding.
|
||||
pcm[i] = color.RGBA{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF}
|
||||
}
|
||||
return image.Config{ColorModel: pcm, Width: width, Height: height}, 8, topDown, nil
|
||||
case 24:
|
||||
if offset != fileHeaderLen+infoHeaderLen {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, nil
|
||||
case 32:
|
||||
if offset != fileHeaderLen+infoHeaderLen {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, nil
|
||||
}
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
|
||||
func init() {
|
||||
image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig)
|
||||
}
|
75
vendor/golang.org/x/image/bmp/reader_test.go
generated
vendored
Normal file
75
vendor/golang.org/x/image/bmp/reader_test.go
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
166
vendor/golang.org/x/image/bmp/writer.go
generated
vendored
Normal file
166
vendor/golang.org/x/image/bmp/writer.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
// 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 (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
)
|
||||
|
||||
type header struct {
|
||||
sigBM [2]byte
|
||||
fileSize uint32
|
||||
resverved [2]uint16
|
||||
pixOffset uint32
|
||||
dibHeaderSize uint32
|
||||
width uint32
|
||||
height uint32
|
||||
colorPlane uint16
|
||||
bpp uint16
|
||||
compression uint32
|
||||
imageSize uint32
|
||||
xPixelsPerMeter uint32
|
||||
yPixelsPerMeter uint32
|
||||
colorUse uint32
|
||||
colorImportant uint32
|
||||
}
|
||||
|
||||
func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
|
||||
var padding []byte
|
||||
if dx < step {
|
||||
padding = make([]byte, step-dx)
|
||||
}
|
||||
for y := dy - 1; y >= 0; y-- {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx
|
||||
if _, err := w.Write(pix[min:max]); err != nil {
|
||||
return err
|
||||
}
|
||||
if padding != nil {
|
||||
if _, err := w.Write(padding); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
|
||||
buf := make([]byte, step)
|
||||
for y := dy - 1; y >= 0; y-- {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx*4
|
||||
off := 0
|
||||
for i := min; i < max; i += 4 {
|
||||
buf[off+2] = pix[i+0]
|
||||
buf[off+1] = pix[i+1]
|
||||
buf[off+0] = pix[i+2]
|
||||
off += 3
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encode(w io.Writer, m image.Image, step int) error {
|
||||
b := m.Bounds()
|
||||
buf := make([]byte, step)
|
||||
for y := b.Max.Y - 1; y >= b.Min.Y; y-- {
|
||||
off := 0
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
r, g, b, _ := m.At(x, y).RGBA()
|
||||
buf[off+2] = byte(r >> 8)
|
||||
buf[off+1] = byte(g >> 8)
|
||||
buf[off+0] = byte(b >> 8)
|
||||
off += 3
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encode writes the image m to w in BMP format.
|
||||
func Encode(w io.Writer, m image.Image) error {
|
||||
d := m.Bounds().Size()
|
||||
if d.X < 0 || d.Y < 0 {
|
||||
return errors.New("bmp: negative bounds")
|
||||
}
|
||||
h := &header{
|
||||
sigBM: [2]byte{'B', 'M'},
|
||||
fileSize: 14 + 40,
|
||||
pixOffset: 14 + 40,
|
||||
dibHeaderSize: 40,
|
||||
width: uint32(d.X),
|
||||
height: uint32(d.Y),
|
||||
colorPlane: 1,
|
||||
}
|
||||
|
||||
var step int
|
||||
var palette []byte
|
||||
switch m := m.(type) {
|
||||
case *image.Gray:
|
||||
step = (d.X + 3) &^ 3
|
||||
palette = make([]byte, 1024)
|
||||
for i := 0; i < 256; i++ {
|
||||
palette[i*4+0] = uint8(i)
|
||||
palette[i*4+1] = uint8(i)
|
||||
palette[i*4+2] = uint8(i)
|
||||
palette[i*4+3] = 0xFF
|
||||
}
|
||||
h.imageSize = uint32(d.Y * step)
|
||||
h.fileSize += uint32(len(palette)) + h.imageSize
|
||||
h.pixOffset += uint32(len(palette))
|
||||
h.bpp = 8
|
||||
|
||||
case *image.Paletted:
|
||||
step = (d.X + 3) &^ 3
|
||||
palette = make([]byte, 1024)
|
||||
for i := 0; i < len(m.Palette) && i < 256; i++ {
|
||||
r, g, b, _ := m.Palette[i].RGBA()
|
||||
palette[i*4+0] = uint8(b >> 8)
|
||||
palette[i*4+1] = uint8(g >> 8)
|
||||
palette[i*4+2] = uint8(r >> 8)
|
||||
palette[i*4+3] = 0xFF
|
||||
}
|
||||
h.imageSize = uint32(d.Y * step)
|
||||
h.fileSize += uint32(len(palette)) + h.imageSize
|
||||
h.pixOffset += uint32(len(palette))
|
||||
h.bpp = 8
|
||||
default:
|
||||
step = (3*d.X + 3) &^ 3
|
||||
h.imageSize = uint32(d.Y * step)
|
||||
h.fileSize += h.imageSize
|
||||
h.bpp = 24
|
||||
}
|
||||
|
||||
if err := binary.Write(w, binary.LittleEndian, h); err != nil {
|
||||
return err
|
||||
}
|
||||
if palette != nil {
|
||||
if err := binary.Write(w, binary.LittleEndian, palette); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if d.X == 0 || d.Y == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *image.Gray:
|
||||
return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
|
||||
case *image.Paletted:
|
||||
return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
|
||||
case *image.RGBA:
|
||||
return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step)
|
||||
}
|
||||
return encode(w, m, step)
|
||||
}
|
91
vendor/golang.org/x/image/bmp/writer_test.go
generated
vendored
Normal file
91
vendor/golang.org/x/image/bmp/writer_test.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
215
vendor/golang.org/x/image/cmd/webp-manual-test/main.go
generated
vendored
Normal file
215
vendor/golang.org/x/image/cmd/webp-manual-test/main.go
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
// 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()
|
||||
}
|
1
vendor/golang.org/x/image/codereview.cfg
generated
vendored
Normal file
1
vendor/golang.org/x/image/codereview.cfg
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
issuerepo: golang/go
|
10
vendor/golang.org/x/image/colornames/colornames.go
generated
vendored
Normal file
10
vendor/golang.org/x/image/colornames/colornames.go
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
// 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
|
42
vendor/golang.org/x/image/colornames/colornames_test.go
generated
vendored
Normal file
42
vendor/golang.org/x/image/colornames/colornames_test.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
// 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},
|
||||
}
|
197
vendor/golang.org/x/image/colornames/gen.go
generated
vendored
Normal file
197
vendor/golang.org/x/image/colornames/gen.go
generated
vendored
Normal file
@ -0,0 +1,197 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
457
vendor/golang.org/x/image/colornames/table.go
generated
vendored
Normal file
457
vendor/golang.org/x/image/colornames/table.go
generated
vendored
Normal file
@ -0,0 +1,457 @@
|
||||
// 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)
|
||||
)
|
43
vendor/golang.org/x/image/draw/draw.go
generated
vendored
Normal file
43
vendor/golang.org/x/image/draw/draw.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// 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 provides image composition functions.
|
||||
//
|
||||
// See "The Go image/draw package" for an introduction to this package:
|
||||
// http://golang.org/doc/articles/image_draw.html
|
||||
//
|
||||
// This package is a superset of and a drop-in replacement for the image/draw
|
||||
// package in the standard library.
|
||||
package draw
|
||||
|
||||
// This file, and the go1_*.go files, just contains the API exported by the
|
||||
// image/draw package in the standard library. Other files in this package
|
||||
// provide additional features.
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
// Draw calls DrawMask with a nil mask.
|
||||
func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
|
||||
draw.Draw(dst, r, src, sp, draw.Op(op))
|
||||
}
|
||||
|
||||
// DrawMask aligns r.Min in dst with sp in src and mp in mask and then
|
||||
// replaces the rectangle r in dst with the result of a Porter-Duff
|
||||
// composition. A nil mask is treated as opaque.
|
||||
func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
|
||||
draw.DrawMask(dst, r, src, sp, mask, mp, draw.Op(op))
|
||||
}
|
||||
|
||||
// FloydSteinberg is a Drawer that is the Src Op with Floyd-Steinberg error
|
||||
// diffusion.
|
||||
var FloydSteinberg Drawer = floydSteinberg{}
|
||||
|
||||
type floydSteinberg struct{}
|
||||
|
||||
func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||
draw.FloydSteinberg.Draw(dst, r, src, sp)
|
||||
}
|
118
vendor/golang.org/x/image/draw/example_test.go
generated
vendored
Normal file
118
vendor/golang.org/x/image/draw/example_test.go
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
||||
// 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).
|
||||
}
|
1404
vendor/golang.org/x/image/draw/gen.go
generated
vendored
Normal file
1404
vendor/golang.org/x/image/draw/gen.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
49
vendor/golang.org/x/image/draw/go1_8.go
generated
vendored
Normal file
49
vendor/golang.org/x/image/draw/go1_8.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// 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,!go1.8.typealias
|
||||
|
||||
package draw
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
// Drawer contains the Draw method.
|
||||
type Drawer interface {
|
||||
// Draw aligns r.Min in dst with sp in src and then replaces the
|
||||
// rectangle r in dst with the result of drawing src on dst.
|
||||
Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point)
|
||||
}
|
||||
|
||||
// Image is an image.Image with a Set method to change a single pixel.
|
||||
type Image interface {
|
||||
image.Image
|
||||
Set(x, y int, c color.Color)
|
||||
}
|
||||
|
||||
// Op is a Porter-Duff compositing operator.
|
||||
type Op int
|
||||
|
||||
const (
|
||||
// Over specifies ``(src in mask) over dst''.
|
||||
Over Op = Op(draw.Over)
|
||||
// Src specifies ``src in mask''.
|
||||
Src Op = Op(draw.Src)
|
||||
)
|
||||
|
||||
// Draw implements the Drawer interface by calling the Draw function with
|
||||
// this Op.
|
||||
func (op Op) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||
(draw.Op(op)).Draw(dst, r, src, sp)
|
||||
}
|
||||
|
||||
// Quantizer produces a palette for an image.
|
||||
type Quantizer interface {
|
||||
// Quantize appends up to cap(p) - len(p) colors to p and returns the
|
||||
// updated palette suitable for converting m to a paletted image.
|
||||
Quantize(p color.Palette, m image.Image) color.Palette
|
||||
}
|
57
vendor/golang.org/x/image/draw/go1_9.go
generated
vendored
Normal file
57
vendor/golang.org/x/image/draw/go1_9.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
// 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 go1.9 go1.8.typealias
|
||||
|
||||
package draw
|
||||
|
||||
import (
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
// We use type aliases (new in Go 1.9) for the exported names from the standard
|
||||
// library's image/draw package. This is not merely syntactic sugar for
|
||||
//
|
||||
// type Drawer draw.Drawer
|
||||
//
|
||||
// as aliasing means that the types in this package, such as draw.Image and
|
||||
// draw.Op, are identical to the corresponding draw.Image and draw.Op types in
|
||||
// the standard library. In comparison, prior to Go 1.9, the code in go1_8.go
|
||||
// defines new types that mimic the old but are different types.
|
||||
//
|
||||
// The package documentation, in draw.go, explicitly gives the intent of this
|
||||
// package:
|
||||
//
|
||||
// This package is a superset of and a drop-in replacement for the
|
||||
// image/draw package in the standard library.
|
||||
//
|
||||
// Drop-in replacement means that I can replace all of my "image/draw" imports
|
||||
// with "golang.org/x/image/draw", to access additional features in this
|
||||
// package, and no further changes are required. That's mostly true, but not
|
||||
// completely true unless we use type aliases.
|
||||
//
|
||||
// Without type aliases, users might need to import both "image/draw" and
|
||||
// "golang.org/x/image/draw" in order to convert from two conceptually
|
||||
// equivalent but different (from the compiler's point of view) types, such as
|
||||
// from one draw.Op type to another draw.Op type, to satisfy some other
|
||||
// interface or function signature.
|
||||
|
||||
// Drawer contains the Draw method.
|
||||
type Drawer = draw.Drawer
|
||||
|
||||
// Image is an image.Image with a Set method to change a single pixel.
|
||||
type Image = draw.Image
|
||||
|
||||
// Op is a Porter-Duff compositing operator.
|
||||
type Op = draw.Op
|
||||
|
||||
const (
|
||||
// Over specifies ``(src in mask) over dst''.
|
||||
Over Op = draw.Over
|
||||
// Src specifies ``src in mask''.
|
||||
Src Op = draw.Src
|
||||
)
|
||||
|
||||
// Quantizer produces a palette for an image.
|
||||
type Quantizer = draw.Quantizer
|
6670
vendor/golang.org/x/image/draw/impl.go
generated
vendored
Normal file
6670
vendor/golang.org/x/image/draw/impl.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
527
vendor/golang.org/x/image/draw/scale.go
generated
vendored
Normal file
527
vendor/golang.org/x/image/draw/scale.go
generated
vendored
Normal file
@ -0,0 +1,527 @@
|
||||
// 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 draw
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/image/math/f64"
|
||||
)
|
||||
|
||||
// Copy copies the part of the source image defined by src and sr and writes
|
||||
// the result of a Porter-Duff composition to the part of the destination image
|
||||
// defined by dst and the translation of sr so that sr.Min translates to dp.
|
||||
func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, op Op, opts *Options) {
|
||||
var o Options
|
||||
if opts != nil {
|
||||
o = *opts
|
||||
}
|
||||
dr := sr.Add(dp.Sub(sr.Min))
|
||||
if o.DstMask == nil {
|
||||
DrawMask(dst, dr, src, sr.Min, o.SrcMask, o.SrcMaskP.Add(sr.Min), op)
|
||||
} else {
|
||||
NearestNeighbor.Scale(dst, dr, src, sr, op, opts)
|
||||
}
|
||||
}
|
||||
|
||||
// Scaler scales the part of the source image defined by src and sr and writes
|
||||
// the result of a Porter-Duff composition to the part of the destination image
|
||||
// defined by dst and dr.
|
||||
//
|
||||
// A Scaler is safe to use concurrently.
|
||||
type Scaler interface {
|
||||
Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options)
|
||||
}
|
||||
|
||||
// Transformer transforms the part of the source image defined by src and sr
|
||||
// and writes the result of a Porter-Duff composition to the part of the
|
||||
// destination image defined by dst and the affine transform m applied to sr.
|
||||
//
|
||||
// For example, if m is the matrix
|
||||
//
|
||||
// m00 m01 m02
|
||||
// m10 m11 m12
|
||||
//
|
||||
// then the src-space point (sx, sy) maps to the dst-space point
|
||||
// (m00*sx + m01*sy + m02, m10*sx + m11*sy + m12).
|
||||
//
|
||||
// A Transformer is safe to use concurrently.
|
||||
type Transformer interface {
|
||||
Transform(dst Image, m f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options)
|
||||
}
|
||||
|
||||
// Options are optional parameters to Copy, Scale and Transform.
|
||||
//
|
||||
// A nil *Options means to use the default (zero) values of each field.
|
||||
type Options struct {
|
||||
// Masks limit what parts of the dst image are drawn to and what parts of
|
||||
// the src image are drawn from.
|
||||
//
|
||||
// A dst or src mask image having a zero alpha (transparent) pixel value in
|
||||
// the respective coordinate space means that that dst pixel is entirely
|
||||
// unaffected or that src pixel is considered transparent black. A full
|
||||
// alpha (opaque) value means that the dst pixel is maximally affected or
|
||||
// the src pixel contributes maximally. The default values, nil, are
|
||||
// equivalent to fully opaque, infinitely large mask images.
|
||||
//
|
||||
// The DstMask is otherwise known as a clip mask, and its pixels map 1:1 to
|
||||
// the dst image's pixels. DstMaskP in DstMask space corresponds to
|
||||
// image.Point{X:0, Y:0} in dst space. For example, when limiting
|
||||
// repainting to a 'dirty rectangle', use that image.Rectangle and a zero
|
||||
// image.Point as the DstMask and DstMaskP.
|
||||
//
|
||||
// The SrcMask's pixels map 1:1 to the src image's pixels. SrcMaskP in
|
||||
// SrcMask space corresponds to image.Point{X:0, Y:0} in src space. For
|
||||
// example, when drawing font glyphs in a uniform color, use an
|
||||
// *image.Uniform as the src, and use the glyph atlas image and the
|
||||
// per-glyph offset as SrcMask and SrcMaskP:
|
||||
// Copy(dst, dp, image.NewUniform(color), image.Rect(0, 0, glyphWidth, glyphHeight), &Options{
|
||||
// SrcMask: glyphAtlas,
|
||||
// SrcMaskP: glyphOffset,
|
||||
// })
|
||||
DstMask image.Image
|
||||
DstMaskP image.Point
|
||||
SrcMask image.Image
|
||||
SrcMaskP image.Point
|
||||
|
||||
// TODO: a smooth vs sharp edges option, for arbitrary rotations?
|
||||
}
|
||||
|
||||
// Interpolator is an interpolation algorithm, when dst and src pixels don't
|
||||
// have a 1:1 correspondence.
|
||||
//
|
||||
// Of the interpolators provided by this package:
|
||||
// - NearestNeighbor is fast but usually looks worst.
|
||||
// - CatmullRom is slow but usually looks best.
|
||||
// - ApproxBiLinear has reasonable speed and quality.
|
||||
//
|
||||
// The time taken depends on the size of dr. For kernel interpolators, the
|
||||
// speed also depends on the size of sr, and so are often slower than
|
||||
// non-kernel interpolators, especially when scaling down.
|
||||
type Interpolator interface {
|
||||
Scaler
|
||||
Transformer
|
||||
}
|
||||
|
||||
// Kernel is an interpolator that blends source pixels weighted by a symmetric
|
||||
// kernel function.
|
||||
type Kernel struct {
|
||||
// Support is the kernel support and must be >= 0. At(t) is assumed to be
|
||||
// zero when t >= Support.
|
||||
Support float64
|
||||
// At is the kernel function. It will only be called with t in the
|
||||
// range [0, Support).
|
||||
At func(t float64) float64
|
||||
}
|
||||
|
||||
// Scale implements the Scaler interface.
|
||||
func (q *Kernel) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
|
||||
q.newScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy(), false).Scale(dst, dr, src, sr, op, opts)
|
||||
}
|
||||
|
||||
// NewScaler returns a Scaler that is optimized for scaling multiple times with
|
||||
// the same fixed destination and source width and height.
|
||||
func (q *Kernel) NewScaler(dw, dh, sw, sh int) Scaler {
|
||||
return q.newScaler(dw, dh, sw, sh, true)
|
||||
}
|
||||
|
||||
func (q *Kernel) newScaler(dw, dh, sw, sh int, usePool bool) Scaler {
|
||||
z := &kernelScaler{
|
||||
kernel: q,
|
||||
dw: int32(dw),
|
||||
dh: int32(dh),
|
||||
sw: int32(sw),
|
||||
sh: int32(sh),
|
||||
horizontal: newDistrib(q, int32(dw), int32(sw)),
|
||||
vertical: newDistrib(q, int32(dh), int32(sh)),
|
||||
}
|
||||
if usePool {
|
||||
z.pool.New = func() interface{} {
|
||||
tmp := z.makeTmpBuf()
|
||||
return &tmp
|
||||
}
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
var (
|
||||
// NearestNeighbor is the nearest neighbor interpolator. It is very fast,
|
||||
// but usually gives very low quality results. When scaling up, the result
|
||||
// will look 'blocky'.
|
||||
NearestNeighbor = Interpolator(nnInterpolator{})
|
||||
|
||||
// ApproxBiLinear is a mixture of the nearest neighbor and bi-linear
|
||||
// interpolators. It is fast, but usually gives medium quality results.
|
||||
//
|
||||
// It implements bi-linear interpolation when upscaling and a bi-linear
|
||||
// blend of the 4 nearest neighbor pixels when downscaling. This yields
|
||||
// nicer quality than nearest neighbor interpolation when upscaling, but
|
||||
// the time taken is independent of the number of source pixels, unlike the
|
||||
// bi-linear interpolator. When downscaling a large image, the performance
|
||||
// difference can be significant.
|
||||
ApproxBiLinear = Interpolator(ablInterpolator{})
|
||||
|
||||
// BiLinear is the tent kernel. It is slow, but usually gives high quality
|
||||
// results.
|
||||
BiLinear = &Kernel{1, func(t float64) float64 {
|
||||
return 1 - t
|
||||
}}
|
||||
|
||||
// CatmullRom is the Catmull-Rom kernel. It is very slow, but usually gives
|
||||
// very high quality results.
|
||||
//
|
||||
// It is an instance of the more general cubic BC-spline kernel with parameters
|
||||
// B=0 and C=0.5. See Mitchell and Netravali, "Reconstruction Filters in
|
||||
// Computer Graphics", Computer Graphics, Vol. 22, No. 4, pp. 221-228.
|
||||
CatmullRom = &Kernel{2, func(t float64) float64 {
|
||||
if t < 1 {
|
||||
return (1.5*t-2.5)*t*t + 1
|
||||
}
|
||||
return ((-0.5*t+2.5)*t-4)*t + 2
|
||||
}}
|
||||
|
||||
// TODO: a Kaiser-Bessel kernel?
|
||||
)
|
||||
|
||||
type nnInterpolator struct{}
|
||||
|
||||
type ablInterpolator struct{}
|
||||
|
||||
type kernelScaler struct {
|
||||
kernel *Kernel
|
||||
dw, dh, sw, sh int32
|
||||
horizontal, vertical distrib
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
func (z *kernelScaler) makeTmpBuf() [][4]float64 {
|
||||
return make([][4]float64, z.dw*z.sh)
|
||||
}
|
||||
|
||||
// source is a range of contribs, their inverse total weight, and that ITW
|
||||
// divided by 0xffff.
|
||||
type source struct {
|
||||
i, j int32
|
||||
invTotalWeight float64
|
||||
invTotalWeightFFFF float64
|
||||
}
|
||||
|
||||
// contrib is the weight of a column or row.
|
||||
type contrib struct {
|
||||
coord int32
|
||||
weight float64
|
||||
}
|
||||
|
||||
// distrib measures how source pixels are distributed over destination pixels.
|
||||
type distrib struct {
|
||||
// sources are what contribs each column or row in the source image owns,
|
||||
// and the total weight of those contribs.
|
||||
sources []source
|
||||
// contribs are the contributions indexed by sources[s].i and sources[s].j.
|
||||
contribs []contrib
|
||||
}
|
||||
|
||||
// newDistrib returns a distrib that distributes sw source columns (or rows)
|
||||
// over dw destination columns (or rows).
|
||||
func newDistrib(q *Kernel, dw, sw int32) distrib {
|
||||
scale := float64(sw) / float64(dw)
|
||||
halfWidth, kernelArgScale := q.Support, 1.0
|
||||
// When shrinking, broaden the effective kernel support so that we still
|
||||
// visit every source pixel.
|
||||
if scale > 1 {
|
||||
halfWidth *= scale
|
||||
kernelArgScale = 1 / scale
|
||||
}
|
||||
|
||||
// Make the sources slice, one source for each column or row, and temporarily
|
||||
// appropriate its elements' fields so that invTotalWeight is the scaled
|
||||
// coordinate of the source column or row, and i and j are the lower and
|
||||
// upper bounds of the range of destination columns or rows affected by the
|
||||
// source column or row.
|
||||
n, sources := int32(0), make([]source, dw)
|
||||
for x := range sources {
|
||||
center := (float64(x)+0.5)*scale - 0.5
|
||||
i := int32(math.Floor(center - halfWidth))
|
||||
if i < 0 {
|
||||
i = 0
|
||||
}
|
||||
j := int32(math.Ceil(center + halfWidth))
|
||||
if j > sw {
|
||||
j = sw
|
||||
if j < i {
|
||||
j = i
|
||||
}
|
||||
}
|
||||
sources[x] = source{i: i, j: j, invTotalWeight: center}
|
||||
n += j - i
|
||||
}
|
||||
|
||||
contribs := make([]contrib, 0, n)
|
||||
for k, b := range sources {
|
||||
totalWeight := 0.0
|
||||
l := int32(len(contribs))
|
||||
for coord := b.i; coord < b.j; coord++ {
|
||||
t := abs((b.invTotalWeight - float64(coord)) * kernelArgScale)
|
||||
if t >= q.Support {
|
||||
continue
|
||||
}
|
||||
weight := q.At(t)
|
||||
if weight == 0 {
|
||||
continue
|
||||
}
|
||||
totalWeight += weight
|
||||
contribs = append(contribs, contrib{coord, weight})
|
||||
}
|
||||
totalWeight = 1 / totalWeight
|
||||
sources[k] = source{
|
||||
i: l,
|
||||
j: int32(len(contribs)),
|
||||
invTotalWeight: totalWeight,
|
||||
invTotalWeightFFFF: totalWeight / 0xffff,
|
||||
}
|
||||
}
|
||||
|
||||
return distrib{sources, contribs}
|
||||
}
|
||||
|
||||
// abs is like math.Abs, but it doesn't care about negative zero, infinities or
|
||||
// NaNs.
|
||||
func abs(f float64) float64 {
|
||||
if f < 0 {
|
||||
f = -f
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
// ftou converts the range [0.0, 1.0] to [0, 0xffff].
|
||||
func ftou(f float64) uint16 {
|
||||
i := int32(0xffff*f + 0.5)
|
||||
if i > 0xffff {
|
||||
return 0xffff
|
||||
}
|
||||
if i > 0 {
|
||||
return uint16(i)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// fffftou converts the range [0.0, 65535.0] to [0, 0xffff].
|
||||
func fffftou(f float64) uint16 {
|
||||
i := int32(f + 0.5)
|
||||
if i > 0xffff {
|
||||
return 0xffff
|
||||
}
|
||||
if i > 0 {
|
||||
return uint16(i)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// invert returns the inverse of m.
|
||||
//
|
||||
// TODO: move this into the f64 package, once we work out the convention for
|
||||
// matrix methods in that package: do they modify the receiver, take a dst
|
||||
// pointer argument, or return a new value?
|
||||
func invert(m *f64.Aff3) f64.Aff3 {
|
||||
m00 := +m[3*1+1]
|
||||
m01 := -m[3*0+1]
|
||||
m02 := +m[3*1+2]*m[3*0+1] - m[3*1+1]*m[3*0+2]
|
||||
m10 := -m[3*1+0]
|
||||
m11 := +m[3*0+0]
|
||||
m12 := +m[3*1+0]*m[3*0+2] - m[3*1+2]*m[3*0+0]
|
||||
|
||||
det := m00*m11 - m10*m01
|
||||
|
||||
return f64.Aff3{
|
||||
m00 / det,
|
||||
m01 / det,
|
||||
m02 / det,
|
||||
m10 / det,
|
||||
m11 / det,
|
||||
m12 / det,
|
||||
}
|
||||
}
|
||||
|
||||
func matMul(p, q *f64.Aff3) f64.Aff3 {
|
||||
return f64.Aff3{
|
||||
p[3*0+0]*q[3*0+0] + p[3*0+1]*q[3*1+0],
|
||||
p[3*0+0]*q[3*0+1] + p[3*0+1]*q[3*1+1],
|
||||
p[3*0+0]*q[3*0+2] + p[3*0+1]*q[3*1+2] + p[3*0+2],
|
||||
p[3*1+0]*q[3*0+0] + p[3*1+1]*q[3*1+0],
|
||||
p[3*1+0]*q[3*0+1] + p[3*1+1]*q[3*1+1],
|
||||
p[3*1+0]*q[3*0+2] + p[3*1+1]*q[3*1+2] + p[3*1+2],
|
||||
}
|
||||
}
|
||||
|
||||
// transformRect returns a rectangle dr that contains sr transformed by s2d.
|
||||
func transformRect(s2d *f64.Aff3, sr *image.Rectangle) (dr image.Rectangle) {
|
||||
ps := [...]image.Point{
|
||||
{sr.Min.X, sr.Min.Y},
|
||||
{sr.Max.X, sr.Min.Y},
|
||||
{sr.Min.X, sr.Max.Y},
|
||||
{sr.Max.X, sr.Max.Y},
|
||||
}
|
||||
for i, p := range ps {
|
||||
sxf := float64(p.X)
|
||||
syf := float64(p.Y)
|
||||
dx := int(math.Floor(s2d[0]*sxf + s2d[1]*syf + s2d[2]))
|
||||
dy := int(math.Floor(s2d[3]*sxf + s2d[4]*syf + s2d[5]))
|
||||
|
||||
// The +1 adjustments below are because an image.Rectangle is inclusive
|
||||
// on the low end but exclusive on the high end.
|
||||
|
||||
if i == 0 {
|
||||
dr = image.Rectangle{
|
||||
Min: image.Point{dx + 0, dy + 0},
|
||||
Max: image.Point{dx + 1, dy + 1},
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if dr.Min.X > dx {
|
||||
dr.Min.X = dx
|
||||
}
|
||||
dx++
|
||||
if dr.Max.X < dx {
|
||||
dr.Max.X = dx
|
||||
}
|
||||
|
||||
if dr.Min.Y > dy {
|
||||
dr.Min.Y = dy
|
||||
}
|
||||
dy++
|
||||
if dr.Max.Y < dy {
|
||||
dr.Max.Y = dy
|
||||
}
|
||||
}
|
||||
return dr
|
||||
}
|
||||
|
||||
func clipAffectedDestRect(adr image.Rectangle, dstMask image.Image, dstMaskP image.Point) (image.Rectangle, image.Image) {
|
||||
if dstMask == nil {
|
||||
return adr, nil
|
||||
}
|
||||
// TODO: enable this fast path once Go 1.5 is released, where an
|
||||
// image.Rectangle implements image.Image.
|
||||
// if r, ok := dstMask.(image.Rectangle); ok {
|
||||
// return adr.Intersect(r.Sub(dstMaskP)), nil
|
||||
// }
|
||||
// TODO: clip to dstMask.Bounds() if the color model implies that out-of-bounds means 0 alpha?
|
||||
return adr, dstMask
|
||||
}
|
||||
|
||||
func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Uniform, sr image.Rectangle, bias image.Point, op Op) {
|
||||
switch op {
|
||||
case Over:
|
||||
switch dst := dst.(type) {
|
||||
case *image.RGBA:
|
||||
pr, pg, pb, pa := src.C.RGBA()
|
||||
pa1 := (0xffff - pa) * 0x101
|
||||
|
||||
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
|
||||
dyf := float64(dr.Min.Y+int(dy)) + 0.5
|
||||
d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
|
||||
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
|
||||
dxf := float64(dr.Min.X+int(dx)) + 0.5
|
||||
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
|
||||
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
|
||||
if !(image.Point{sx0, sy0}).In(sr) {
|
||||
continue
|
||||
}
|
||||
dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
|
||||
dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
|
||||
dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
|
||||
dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
pr, pg, pb, pa := src.C.RGBA()
|
||||
pa1 := 0xffff - pa
|
||||
dstColorRGBA64 := &color.RGBA64{}
|
||||
dstColor := color.Color(dstColorRGBA64)
|
||||
|
||||
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
|
||||
dyf := float64(dr.Min.Y+int(dy)) + 0.5
|
||||
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
|
||||
dxf := float64(dr.Min.X+int(dx)) + 0.5
|
||||
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
|
||||
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
|
||||
if !(image.Point{sx0, sy0}).In(sr) {
|
||||
continue
|
||||
}
|
||||
qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
|
||||
dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
|
||||
dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
|
||||
dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
|
||||
dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
|
||||
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case Src:
|
||||
switch dst := dst.(type) {
|
||||
case *image.RGBA:
|
||||
pr, pg, pb, pa := src.C.RGBA()
|
||||
pr8 := uint8(pr >> 8)
|
||||
pg8 := uint8(pg >> 8)
|
||||
pb8 := uint8(pb >> 8)
|
||||
pa8 := uint8(pa >> 8)
|
||||
|
||||
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
|
||||
dyf := float64(dr.Min.Y+int(dy)) + 0.5
|
||||
d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
|
||||
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
|
||||
dxf := float64(dr.Min.X+int(dx)) + 0.5
|
||||
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
|
||||
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
|
||||
if !(image.Point{sx0, sy0}).In(sr) {
|
||||
continue
|
||||
}
|
||||
dst.Pix[d+0] = pr8
|
||||
dst.Pix[d+1] = pg8
|
||||
dst.Pix[d+2] = pb8
|
||||
dst.Pix[d+3] = pa8
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
pr, pg, pb, pa := src.C.RGBA()
|
||||
dstColorRGBA64 := &color.RGBA64{
|
||||
uint16(pr),
|
||||
uint16(pg),
|
||||
uint16(pb),
|
||||
uint16(pa),
|
||||
}
|
||||
dstColor := color.Color(dstColorRGBA64)
|
||||
|
||||
for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
|
||||
dyf := float64(dr.Min.Y+int(dy)) + 0.5
|
||||
for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
|
||||
dxf := float64(dr.Min.X+int(dx)) + 0.5
|
||||
sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
|
||||
sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
|
||||
if !(image.Point{sx0, sy0}).In(sr) {
|
||||
continue
|
||||
}
|
||||
dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func opaque(m image.Image) bool {
|
||||
o, ok := m.(interface {
|
||||
Opaque() bool
|
||||
})
|
||||
return ok && o.Opaque()
|
||||
}
|
742
vendor/golang.org/x/image/draw/scale_test.go
generated
vendored
Normal file
742
vendor/golang.org/x/image/draw/scale_test.go
generated
vendored
Normal file
@ -0,0 +1,742 @@
|
||||
// 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) }
|
96
vendor/golang.org/x/image/draw/stdlib_test.go
generated
vendored
Normal file
96
vendor/golang.org/x/image/draw/stdlib_test.go
generated
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
vendor/golang.org/x/image/example/font/main.go
generated
vendored
Normal file
106
vendor/golang.org/x/image/example/font/main.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
126
vendor/golang.org/x/image/font/basicfont/basicfont.go
generated
vendored
Normal file
126
vendor/golang.org/x/image/font/basicfont/basicfont.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
// 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
|
||||
}
|
1456
vendor/golang.org/x/image/font/basicfont/data.go
generated
vendored
Normal file
1456
vendor/golang.org/x/image/font/basicfont/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
115
vendor/golang.org/x/image/font/basicfont/gen.go
generated
vendored
Normal file
115
vendor/golang.org/x/image/font/basicfont/gen.go
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
// 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"
|
||||
|
||||
`
|
359
vendor/golang.org/x/image/font/font.go
generated
vendored
Normal file
359
vendor/golang.org/x/image/font/font.go
generated
vendored
Normal file
@ -0,0 +1,359 @@
|
||||
// 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.
|
||||
)
|
65
vendor/golang.org/x/image/font/font_test.go
generated
vendored
Normal file
65
vendor/golang.org/x/image/font/font_test.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
107
vendor/golang.org/x/image/font/gofont/gen.go
generated
vendored
Normal file
107
vendor/golang.org/x/image/font/gofont/gen.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
// 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
|
||||
}
|
9047
vendor/golang.org/x/image/font/gofont/gobold/data.go
generated
vendored
Normal file
9047
vendor/golang.org/x/image/font/gofont/gobold/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9432
vendor/golang.org/x/image/font/gofont/gobolditalic/data.go
generated
vendored
Normal file
9432
vendor/golang.org/x/image/font/gofont/gobolditalic/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9198
vendor/golang.org/x/image/font/gofont/goitalic/data.go
generated
vendored
Normal file
9198
vendor/golang.org/x/image/font/gofont/goitalic/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9192
vendor/golang.org/x/image/font/gofont/gomedium/data.go
generated
vendored
Normal file
9192
vendor/golang.org/x/image/font/gofont/gomedium/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9726
vendor/golang.org/x/image/font/gofont/gomediumitalic/data.go
generated
vendored
Normal file
9726
vendor/golang.org/x/image/font/gofont/gomediumitalic/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10274
vendor/golang.org/x/image/font/gofont/gomono/data.go
generated
vendored
Normal file
10274
vendor/golang.org/x/image/font/gofont/gomono/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10533
vendor/golang.org/x/image/font/gofont/gomonobold/data.go
generated
vendored
Normal file
10533
vendor/golang.org/x/image/font/gofont/gomonobold/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
11063
vendor/golang.org/x/image/font/gofont/gomonobolditalic/data.go
generated
vendored
Normal file
11063
vendor/golang.org/x/image/font/gofont/gomonobolditalic/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
10858
vendor/golang.org/x/image/font/gofont/gomonoitalic/data.go
generated
vendored
Normal file
10858
vendor/golang.org/x/image/font/gofont/gomonoitalic/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8781
vendor/golang.org/x/image/font/gofont/goregular/data.go
generated
vendored
Normal file
8781
vendor/golang.org/x/image/font/gofont/goregular/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8362
vendor/golang.org/x/image/font/gofont/gosmallcaps/data.go
generated
vendored
Normal file
8362
vendor/golang.org/x/image/font/gofont/gosmallcaps/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8794
vendor/golang.org/x/image/font/gofont/gosmallcapsitalic/data.go
generated
vendored
Normal file
8794
vendor/golang.org/x/image/font/gofont/gosmallcapsitalic/data.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Bold-Italic.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Bold-Italic.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Bold.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Bold.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Italic.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Italic.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Medium-Italic.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Medium-Italic.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Medium.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Medium.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Mono-Bold-Italic.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Mono-Bold-Italic.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Mono-Bold.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Mono-Bold.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Mono-Italic.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Mono-Italic.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Mono.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Mono.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Regular.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Regular.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Smallcaps-Italic.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Smallcaps-Italic.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Smallcaps.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/gofont/ttfs/Go-Smallcaps.ttf
generated
vendored
Normal file
Binary file not shown.
36
vendor/golang.org/x/image/font/gofont/ttfs/README
generated
vendored
Normal file
36
vendor/golang.org/x/image/font/gofont/ttfs/README
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
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.
|
5557
vendor/golang.org/x/image/font/inconsolata/bold8x16.go
generated
vendored
Normal file
5557
vendor/golang.org/x/image/font/inconsolata/bold8x16.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
29
vendor/golang.org/x/image/font/inconsolata/inconsolata.go
generated
vendored
Normal file
29
vendor/golang.org/x/image/font/inconsolata/inconsolata.go
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// 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 = ®ular8x16
|
||||
|
||||
// Bold8x16 is a bold weight, 8x16 font face.
|
||||
var Bold8x16 *basicfont.Face = &bold8x16
|
5557
vendor/golang.org/x/image/font/inconsolata/regular8x16.go
generated
vendored
Normal file
5557
vendor/golang.org/x/image/font/inconsolata/regular8x16.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
103
vendor/golang.org/x/image/font/opentype/face.go
generated
vendored
Normal file
103
vendor/golang.org/x/image/font/opentype/face.go
generated
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
// 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
|
||||
}
|
90
vendor/golang.org/x/image/font/opentype/face_test.go
generated
vendored
Normal file
90
vendor/golang.org/x/image/font/opentype/face_test.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
7
vendor/golang.org/x/image/font/opentype/opentype.go
generated
vendored
Normal file
7
vendor/golang.org/x/image/font/opentype/opentype.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
// 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"
|
92
vendor/golang.org/x/image/font/plan9font/example_test.go
generated
vendored
Normal file
92
vendor/golang.org/x/image/font/plan9font/example_test.go
generated
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
// 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...........
|
||||
}
|
610
vendor/golang.org/x/image/font/plan9font/plan9font.go
generated
vendored
Normal file
610
vendor/golang.org/x/image/font/plan9font/plan9font.go
generated
vendored
Normal file
@ -0,0 +1,610 @@
|
||||
// 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
|
||||
}
|
24
vendor/golang.org/x/image/font/plan9font/plan9font_test.go
generated
vendored
Normal file
24
vendor/golang.org/x/image/font/plan9font/plan9font_test.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
259
vendor/golang.org/x/image/font/sfnt/cmap.go
generated
vendored
Normal file
259
vendor/golang.org/x/image/font/sfnt/cmap.go
generated
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
// 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
|
||||
}
|
68
vendor/golang.org/x/image/font/sfnt/data.go
generated
vendored
Normal file
68
vendor/golang.org/x/image/font/sfnt/data.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
// 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,
|
||||
}
|
131
vendor/golang.org/x/image/font/sfnt/example_test.go
generated
vendored
Normal file
131
vendor/golang.org/x/image/font/sfnt/example_test.go
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
// 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++..
|
||||
// ..........++++++++......
|
||||
// ........................
|
||||
// ........................
|
||||
// ........................
|
||||
}
|
321
vendor/golang.org/x/image/font/sfnt/gen.go
generated
vendored
Normal file
321
vendor/golang.org/x/image/font/sfnt/gen.go
generated
vendored
Normal file
@ -0,0 +1,321 @@
|
||||
// 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",
|
||||
}
|
1414
vendor/golang.org/x/image/font/sfnt/postscript.go
generated
vendored
Normal file
1414
vendor/golang.org/x/image/font/sfnt/postscript.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1390
vendor/golang.org/x/image/font/sfnt/proprietary_test.go
generated
vendored
Normal file
1390
vendor/golang.org/x/image/font/sfnt/proprietary_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1538
vendor/golang.org/x/image/font/sfnt/sfnt.go
generated
vendored
Normal file
1538
vendor/golang.org/x/image/font/sfnt/sfnt.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
839
vendor/golang.org/x/image/font/sfnt/sfnt_test.go
generated
vendored
Normal file
839
vendor/golang.org/x/image/font/sfnt/sfnt_test.go
generated
vendored
Normal file
@ -0,0 +1,839 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
572
vendor/golang.org/x/image/font/sfnt/truetype.go
generated
vendored
Normal file
572
vendor/golang.org/x/image/font/sfnt/truetype.go
generated
vendored
Normal file
@ -0,0 +1,572 @@
|
||||
// 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
|
||||
}
|
BIN
vendor/golang.org/x/image/font/testdata/CFFTest.otf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/CFFTest.otf
generated
vendored
Normal file
Binary file not shown.
148
vendor/golang.org/x/image/font/testdata/CFFTest.sfd
generated
vendored
Normal file
148
vendor/golang.org/x/image/font/testdata/CFFTest.sfd
generated
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
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
|
2
vendor/golang.org/x/image/font/testdata/README
generated
vendored
Normal file
2
vendor/golang.org/x/image/font/testdata/README
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
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.
|
265
vendor/golang.org/x/image/font/testdata/cmapTest.sfd
generated
vendored
Normal file
265
vendor/golang.org/x/image/font/testdata/cmapTest.sfd
generated
vendored
Normal file
@ -0,0 +1,265 @@
|
||||
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
|
BIN
vendor/golang.org/x/image/font/testdata/cmapTest.ttf
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/cmapTest.ttf
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0000
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0000
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0100
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0100
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0200
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0200
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0300
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0300
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0400
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0400
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0500
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0500
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0E00
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.0E00
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.1000
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.1000
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.1600
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.1600
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.1E00
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.1E00
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.1F00
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.1F00
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2000
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2000
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2100
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2100
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2200
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2200
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2300
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2300
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2400
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2400
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2500
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2500
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2600
generated
vendored
Normal file
BIN
vendor/golang.org/x/image/font/testdata/fixed/7x13.2600
generated
vendored
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user