├── .gitattributes ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── PATENTS ├── README.md ├── bmp ├── reader.go ├── reader_test.go ├── writer.go └── writer_test.go ├── ccitt ├── gen.go ├── reader.go ├── reader_test.go ├── table.go ├── table_test.go ├── testdata │ ├── bw-gopher-aligned.ccitt_group3 │ ├── bw-gopher-aligned.ccitt_group4 │ ├── bw-gopher-inverted-aligned.ccitt_group3 │ ├── bw-gopher-inverted-aligned.ccitt_group4 │ ├── bw-gopher-inverted.ccitt_group3 │ ├── bw-gopher-inverted.ccitt_group4 │ ├── bw-gopher-truncated0.ccitt_group3 │ ├── bw-gopher-truncated0.ccitt_group4 │ ├── bw-gopher-truncated1.ccitt_group3 │ ├── bw-gopher-truncated1.ccitt_group4 │ ├── bw-gopher.ccitt_group3 │ ├── bw-gopher.ccitt_group4 │ └── bw-gopher.png ├── writer.go └── writer_test.go ├── cmd └── webp-manual-test │ └── main.go ├── codereview.cfg ├── colornames ├── colornames.go ├── colornames_test.go ├── gen.go └── table.go ├── draw ├── draw.go ├── example_test.go ├── gen.go ├── impl.go ├── scale.go ├── scale_test.go └── stdlib_test.go ├── example └── font │ └── main.go ├── font ├── basicfont │ ├── basicfont.go │ ├── basicfont_test.go │ ├── data.go │ └── gen.go ├── font.go ├── font_test.go ├── gofont │ ├── gen.go │ ├── gobold │ │ └── data.go │ ├── gobolditalic │ │ └── data.go │ ├── goitalic │ │ └── data.go │ ├── gomedium │ │ └── data.go │ ├── gomediumitalic │ │ └── data.go │ ├── gomono │ │ └── data.go │ ├── gomonobold │ │ └── data.go │ ├── gomonobolditalic │ │ └── data.go │ ├── gomonoitalic │ │ └── data.go │ ├── goregular │ │ └── data.go │ ├── gosmallcaps │ │ └── data.go │ ├── gosmallcapsitalic │ │ └── data.go │ └── ttfs │ │ ├── Go-Bold-Italic.ttf │ │ ├── Go-Bold.ttf │ │ ├── Go-Italic.ttf │ │ ├── Go-Medium-Italic.ttf │ │ ├── Go-Medium.ttf │ │ ├── Go-Mono-Bold-Italic.ttf │ │ ├── Go-Mono-Bold.ttf │ │ ├── Go-Mono-Italic.ttf │ │ ├── Go-Mono.ttf │ │ ├── Go-Regular.ttf │ │ ├── Go-Smallcaps-Italic.ttf │ │ ├── Go-Smallcaps.ttf │ │ └── README ├── inconsolata │ ├── bold8x16.go │ ├── inconsolata.go │ └── regular8x16.go ├── opentype │ ├── example_test.go │ ├── opentype.go │ └── opentype_test.go ├── plan9font │ ├── example_test.go │ ├── plan9font.go │ └── plan9font_test.go ├── sfnt │ ├── cmap.go │ ├── data.go │ ├── example_test.go │ ├── gen.go │ ├── gpos.go │ ├── kern_test.go │ ├── postscript.go │ ├── proprietary_test.go │ ├── sfnt.go │ ├── sfnt_test.go │ └── truetype.go └── testdata │ ├── CFFTest.otf │ ├── CFFTest.sfd │ ├── README │ ├── cmapTest.sfd │ ├── cmapTest.ttf │ ├── fixed │ ├── 7x13.0000 │ ├── 7x13.0100 │ ├── 7x13.0200 │ ├── 7x13.0300 │ ├── 7x13.0400 │ ├── 7x13.0500 │ ├── 7x13.0E00 │ ├── 7x13.1000 │ ├── 7x13.1600 │ ├── 7x13.1E00 │ ├── 7x13.1F00 │ ├── 7x13.2000 │ ├── 7x13.2100 │ ├── 7x13.2200 │ ├── 7x13.2300 │ ├── 7x13.2400 │ ├── 7x13.2500 │ ├── 7x13.2600 │ ├── 7x13.2700 │ ├── 7x13.2800 │ ├── 7x13.2A00 │ ├── 7x13.3000 │ ├── 7x13.FB00 │ ├── 7x13.FE00 │ ├── 7x13.FF00 │ ├── README │ └── unicode.7x13.font │ ├── glyfTest.sfd │ └── glyfTest.ttf ├── go.mod ├── go.sum ├── math ├── f32 │ └── f32.go ├── f64 │ └── f64.go └── fixed │ ├── fixed.go │ └── fixed_test.go ├── riff ├── example_test.go ├── riff.go └── riff_test.go ├── testdata ├── blue-purple-pink-large.lossless.webp ├── blue-purple-pink-large.no-filter.lossy.webp ├── blue-purple-pink-large.no-filter.lossy.webp.ycbcr.png ├── blue-purple-pink-large.normal-filter.lossy.webp ├── blue-purple-pink-large.normal-filter.lossy.webp.ycbcr.png ├── blue-purple-pink-large.png ├── blue-purple-pink-large.simple-filter.lossy.webp ├── blue-purple-pink-large.simple-filter.lossy.webp.ycbcr.png ├── blue-purple-pink.lossless.webp ├── blue-purple-pink.lossy.webp ├── blue-purple-pink.lossy.webp.ycbcr.png ├── blue-purple-pink.lzwcompressed.tiff ├── blue-purple-pink.png ├── bw-deflate.tiff ├── bw-gopher.png ├── bw-gopher_ccittGroup3.tiff ├── bw-gopher_ccittGroup4.tiff ├── bw-packbits.tiff ├── bw-uncompressed.tiff ├── colormap-0.bmp ├── colormap-0.png ├── colormap-251.bmp ├── colormap-251.png ├── colormap.bmp ├── colormap.png ├── go-turns-two-14x18.png ├── go-turns-two-280x360.jpeg ├── go-turns-two-down-ab.png ├── go-turns-two-down-bl.png ├── go-turns-two-down-cr.png ├── go-turns-two-down-nn.png ├── go-turns-two-rotate-ab.png ├── go-turns-two-rotate-bl.png ├── go-turns-two-rotate-cr.png ├── go-turns-two-rotate-nn.png ├── go-turns-two-up-ab.png ├── go-turns-two-up-bl.png ├── go-turns-two-up-cr.png ├── go-turns-two-up-nn.png ├── gopher-doc.1bpp.lossless.webp ├── gopher-doc.1bpp.png ├── gopher-doc.2bpp.lossless.webp ├── gopher-doc.2bpp.png ├── gopher-doc.4bpp.lossless.webp ├── gopher-doc.4bpp.png ├── gopher-doc.8bpp.lossless.webp ├── gopher-doc.8bpp.png ├── invalid-palette-ref.tiff ├── no_compress.tiff ├── no_rps.tiff ├── testpattern.png ├── tux-rotate-ab.png ├── tux-rotate-bl.png ├── tux-rotate-cr.png ├── tux-rotate-nn.png ├── tux.lossless.webp ├── tux.png ├── video-001-16bit.tiff ├── video-001-gray-16bit.tiff ├── video-001-gray.tiff ├── video-001-paletted.tiff ├── video-001-strip-64.tiff ├── video-001-tile-64x64.tiff ├── video-001-uncompressed.tiff ├── video-001.bmp ├── video-001.lossy.webp ├── video-001.lossy.webp.ycbcr.png ├── video-001.png ├── video-001.tiff ├── yellow_rose-small-v5.bmp ├── yellow_rose-small-v5.png ├── yellow_rose-small.bmp ├── yellow_rose-small.png ├── yellow_rose.lossless.webp ├── yellow_rose.lossy-with-alpha.webp ├── yellow_rose.lossy-with-alpha.webp.nycbcra.png ├── yellow_rose.lossy.webp ├── yellow_rose.lossy.webp.ycbcr.png └── yellow_rose.png ├── tiff ├── buffer.go ├── buffer_test.go ├── compress.go ├── consts.go ├── fuzz.go ├── lzw │ └── reader.go ├── reader.go ├── reader_test.go ├── writer.go └── writer_test.go ├── vector ├── acc_amd64.go ├── acc_amd64.s ├── acc_other.go ├── acc_test.go ├── example_test.go ├── gen.go ├── gen_acc_amd64.s.tmpl ├── raster_fixed.go ├── raster_floating.go ├── vector.go └── vector_test.go ├── vp8 ├── decode.go ├── filter.go ├── idct.go ├── partition.go ├── pred.go ├── predfunc.go ├── quant.go ├── reconstruct.go └── token.go ├── vp8l ├── decode.go ├── huffman.go └── transform.go └── webp ├── decode.go ├── decode_test.go └── doc.go /.gitattributes: -------------------------------------------------------------------------------- 1 | # Treat all files in this repo as binary, with no git magic updating 2 | # line endings. Windows users contributing to Go will need to use a 3 | # modern version of git and editors capable of LF line endings. 4 | # 5 | # We'll prevent accidental CRLF line endings from entering the repo 6 | # via the git-review gofmt checks. 7 | # 8 | # See golang.org/issue/9281 9 | 10 | * -text 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Add no patterns to .hgignore except for files generated by the build. 2 | last-change 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Go 2 | 3 | Go is an open source project. 4 | 5 | It is the work of hundreds of contributors. We appreciate your help! 6 | 7 | ## Filing issues 8 | 9 | When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions: 10 | 11 | 1. What version of Go are you using (`go version`)? 12 | 2. What operating system and processor architecture are you using? 13 | 3. What did you do? 14 | 4. What did you expect to see? 15 | 5. What did you see instead? 16 | 17 | General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker. 18 | The gophers there will answer or ask you to file an issue if you've tripped over a bug. 19 | 20 | ## Contributing code 21 | 22 | Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html) 23 | before sending patches. 24 | 25 | Unless otherwise noted, the Go source files are distributed under 26 | the BSD-style license found in the LICENSE file. 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go Images 2 | 3 | [![Go Reference](https://pkg.go.dev/badge/golang.org/x/image.svg)](https://pkg.go.dev/golang.org/x/image) 4 | 5 | This repository holds supplementary Go image packages. 6 | 7 | ## Report Issues / Send Patches 8 | 9 | This repository uses Gerrit for code changes. To learn how to submit changes to 10 | this repository, see https://go.dev/doc/contribute. 11 | 12 | The git repository is https://go.googlesource.com/image. 13 | 14 | The main issue tracker for the image repository is located at 15 | https://go.dev/issues. Prefix your issue with "x/image:" in the 16 | subject line, so it is easy to find. 17 | -------------------------------------------------------------------------------- /bmp/reader_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package bmp 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "image" 11 | "io" 12 | "os" 13 | "testing" 14 | 15 | _ "image/png" 16 | ) 17 | 18 | const testdataDir = "../testdata/" 19 | 20 | func compare(img0, img1 image.Image) error { 21 | b := img1.Bounds() 22 | if !b.Eq(img0.Bounds()) { 23 | return fmt.Errorf("wrong image size: want %s, got %s", img0.Bounds(), b) 24 | } 25 | for y := b.Min.Y; y < b.Max.Y; y++ { 26 | for x := b.Min.X; x < b.Max.X; x++ { 27 | c0 := img0.At(x, y) 28 | c1 := img1.At(x, y) 29 | r0, g0, b0, a0 := c0.RGBA() 30 | r1, g1, b1, a1 := c1.RGBA() 31 | if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 { 32 | return fmt.Errorf("pixel at (%d, %d) has wrong color: want %v, got %v", x, y, c0, c1) 33 | } 34 | } 35 | } 36 | return nil 37 | } 38 | 39 | // TestDecode tests that decoding a PNG image and a BMP image result in the 40 | // same pixel data. 41 | func TestDecode(t *testing.T) { 42 | testCases := []string{ 43 | "colormap", 44 | "colormap-0", 45 | "colormap-251", 46 | "video-001", 47 | "yellow_rose-small", 48 | "yellow_rose-small-v5", 49 | } 50 | 51 | for _, tc := range testCases { 52 | f0, err := os.Open(testdataDir + tc + ".png") 53 | if err != nil { 54 | t.Errorf("%s: Open PNG: %v", tc, err) 55 | continue 56 | } 57 | defer f0.Close() 58 | img0, _, err := image.Decode(f0) 59 | if err != nil { 60 | t.Errorf("%s: Decode PNG: %v", tc, err) 61 | continue 62 | } 63 | 64 | f1, err := os.Open(testdataDir + tc + ".bmp") 65 | if err != nil { 66 | t.Errorf("%s: Open BMP: %v", tc, err) 67 | continue 68 | } 69 | defer f1.Close() 70 | img1, _, err := image.Decode(f1) 71 | if err != nil { 72 | t.Errorf("%s: Decode BMP: %v", tc, err) 73 | continue 74 | } 75 | 76 | if err := compare(img0, img1); err != nil { 77 | t.Errorf("%s: %v", tc, err) 78 | continue 79 | } 80 | } 81 | } 82 | 83 | // TestEOF tests that decoding a BMP image returns io.ErrUnexpectedEOF 84 | // when there are no headers or data is empty 85 | func TestEOF(t *testing.T) { 86 | _, err := Decode(bytes.NewReader(nil)) 87 | if err != io.ErrUnexpectedEOF { 88 | t.Errorf("Error should be io.ErrUnexpectedEOF on nil but got %v", err) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /bmp/writer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package bmp 6 | 7 | import ( 8 | "encoding/binary" 9 | "errors" 10 | "image" 11 | "io" 12 | ) 13 | 14 | type header struct { 15 | sigBM [2]byte 16 | fileSize uint32 17 | resverved [2]uint16 18 | pixOffset uint32 19 | dibHeaderSize uint32 20 | width uint32 21 | height uint32 22 | colorPlane uint16 23 | bpp uint16 24 | compression uint32 25 | imageSize uint32 26 | xPixelsPerMeter uint32 27 | yPixelsPerMeter uint32 28 | colorUse uint32 29 | colorImportant uint32 30 | } 31 | 32 | func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error { 33 | var padding []byte 34 | if dx < step { 35 | padding = make([]byte, step-dx) 36 | } 37 | for y := dy - 1; y >= 0; y-- { 38 | min := y*stride + 0 39 | max := y*stride + dx 40 | if _, err := w.Write(pix[min:max]); err != nil { 41 | return err 42 | } 43 | if padding != nil { 44 | if _, err := w.Write(padding); err != nil { 45 | return err 46 | } 47 | } 48 | } 49 | return nil 50 | } 51 | 52 | func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error { 53 | buf := make([]byte, step) 54 | if opaque { 55 | for y := dy - 1; y >= 0; y-- { 56 | min := y*stride + 0 57 | max := y*stride + dx*4 58 | off := 0 59 | for i := min; i < max; i += 4 { 60 | buf[off+2] = pix[i+0] 61 | buf[off+1] = pix[i+1] 62 | buf[off+0] = pix[i+2] 63 | off += 3 64 | } 65 | if _, err := w.Write(buf); err != nil { 66 | return err 67 | } 68 | } 69 | } else { 70 | for y := dy - 1; y >= 0; y-- { 71 | min := y*stride + 0 72 | max := y*stride + dx*4 73 | off := 0 74 | for i := min; i < max; i += 4 { 75 | a := uint32(pix[i+3]) 76 | if a == 0 { 77 | buf[off+2] = 0 78 | buf[off+1] = 0 79 | buf[off+0] = 0 80 | buf[off+3] = 0 81 | off += 4 82 | continue 83 | } else if a == 0xff { 84 | buf[off+2] = pix[i+0] 85 | buf[off+1] = pix[i+1] 86 | buf[off+0] = pix[i+2] 87 | buf[off+3] = 0xff 88 | off += 4 89 | continue 90 | } 91 | buf[off+2] = uint8(((uint32(pix[i+0]) * 0xffff) / a) >> 8) 92 | buf[off+1] = uint8(((uint32(pix[i+1]) * 0xffff) / a) >> 8) 93 | buf[off+0] = uint8(((uint32(pix[i+2]) * 0xffff) / a) >> 8) 94 | buf[off+3] = uint8(a) 95 | off += 4 96 | } 97 | if _, err := w.Write(buf); err != nil { 98 | return err 99 | } 100 | } 101 | } 102 | return nil 103 | } 104 | 105 | func encodeNRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error { 106 | buf := make([]byte, step) 107 | if opaque { 108 | for y := dy - 1; y >= 0; y-- { 109 | min := y*stride + 0 110 | max := y*stride + dx*4 111 | off := 0 112 | for i := min; i < max; i += 4 { 113 | buf[off+2] = pix[i+0] 114 | buf[off+1] = pix[i+1] 115 | buf[off+0] = pix[i+2] 116 | off += 3 117 | } 118 | if _, err := w.Write(buf); err != nil { 119 | return err 120 | } 121 | } 122 | } else { 123 | for y := dy - 1; y >= 0; y-- { 124 | min := y*stride + 0 125 | max := y*stride + dx*4 126 | off := 0 127 | for i := min; i < max; i += 4 { 128 | buf[off+2] = pix[i+0] 129 | buf[off+1] = pix[i+1] 130 | buf[off+0] = pix[i+2] 131 | buf[off+3] = pix[i+3] 132 | off += 4 133 | } 134 | if _, err := w.Write(buf); err != nil { 135 | return err 136 | } 137 | } 138 | } 139 | return nil 140 | } 141 | 142 | func encode(w io.Writer, m image.Image, step int) error { 143 | b := m.Bounds() 144 | buf := make([]byte, step) 145 | for y := b.Max.Y - 1; y >= b.Min.Y; y-- { 146 | off := 0 147 | for x := b.Min.X; x < b.Max.X; x++ { 148 | r, g, b, _ := m.At(x, y).RGBA() 149 | buf[off+2] = byte(r >> 8) 150 | buf[off+1] = byte(g >> 8) 151 | buf[off+0] = byte(b >> 8) 152 | off += 3 153 | } 154 | if _, err := w.Write(buf); err != nil { 155 | return err 156 | } 157 | } 158 | return nil 159 | } 160 | 161 | // Encode writes the image m to w in BMP format. 162 | func Encode(w io.Writer, m image.Image) error { 163 | d := m.Bounds().Size() 164 | if d.X < 0 || d.Y < 0 { 165 | return errors.New("bmp: negative bounds") 166 | } 167 | h := &header{ 168 | sigBM: [2]byte{'B', 'M'}, 169 | fileSize: 14 + 40, 170 | pixOffset: 14 + 40, 171 | dibHeaderSize: 40, 172 | width: uint32(d.X), 173 | height: uint32(d.Y), 174 | colorPlane: 1, 175 | } 176 | 177 | var step int 178 | var palette []byte 179 | var opaque bool 180 | switch m := m.(type) { 181 | case *image.Gray: 182 | step = (d.X + 3) &^ 3 183 | palette = make([]byte, 1024) 184 | for i := 0; i < 256; i++ { 185 | palette[i*4+0] = uint8(i) 186 | palette[i*4+1] = uint8(i) 187 | palette[i*4+2] = uint8(i) 188 | palette[i*4+3] = 0xFF 189 | } 190 | h.imageSize = uint32(d.Y * step) 191 | h.fileSize += uint32(len(palette)) + h.imageSize 192 | h.pixOffset += uint32(len(palette)) 193 | h.bpp = 8 194 | 195 | case *image.Paletted: 196 | step = (d.X + 3) &^ 3 197 | palette = make([]byte, 1024) 198 | for i := 0; i < len(m.Palette) && i < 256; i++ { 199 | r, g, b, _ := m.Palette[i].RGBA() 200 | palette[i*4+0] = uint8(b >> 8) 201 | palette[i*4+1] = uint8(g >> 8) 202 | palette[i*4+2] = uint8(r >> 8) 203 | palette[i*4+3] = 0xFF 204 | } 205 | h.imageSize = uint32(d.Y * step) 206 | h.fileSize += uint32(len(palette)) + h.imageSize 207 | h.pixOffset += uint32(len(palette)) 208 | h.bpp = 8 209 | case *image.RGBA: 210 | opaque = m.Opaque() 211 | if opaque { 212 | step = (3*d.X + 3) &^ 3 213 | h.bpp = 24 214 | } else { 215 | step = 4 * d.X 216 | h.bpp = 32 217 | } 218 | h.imageSize = uint32(d.Y * step) 219 | h.fileSize += h.imageSize 220 | case *image.NRGBA: 221 | opaque = m.Opaque() 222 | if opaque { 223 | step = (3*d.X + 3) &^ 3 224 | h.bpp = 24 225 | } else { 226 | step = 4 * d.X 227 | h.bpp = 32 228 | } 229 | h.imageSize = uint32(d.Y * step) 230 | h.fileSize += h.imageSize 231 | default: 232 | step = (3*d.X + 3) &^ 3 233 | h.imageSize = uint32(d.Y * step) 234 | h.fileSize += h.imageSize 235 | h.bpp = 24 236 | } 237 | 238 | if err := binary.Write(w, binary.LittleEndian, h); err != nil { 239 | return err 240 | } 241 | if palette != nil { 242 | if err := binary.Write(w, binary.LittleEndian, palette); err != nil { 243 | return err 244 | } 245 | } 246 | 247 | if d.X == 0 || d.Y == 0 { 248 | return nil 249 | } 250 | 251 | switch m := m.(type) { 252 | case *image.Gray: 253 | return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step) 254 | case *image.Paletted: 255 | return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step) 256 | case *image.RGBA: 257 | return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque) 258 | case *image.NRGBA: 259 | return encodeNRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque) 260 | } 261 | return encode(w, m, step) 262 | } 263 | -------------------------------------------------------------------------------- /bmp/writer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package bmp 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "image" 11 | "image/draw" 12 | "io/ioutil" 13 | "os" 14 | "testing" 15 | "time" 16 | ) 17 | 18 | func openImage(filename string) (image.Image, error) { 19 | f, err := os.Open(testdataDir + filename) 20 | if err != nil { 21 | return nil, err 22 | } 23 | defer f.Close() 24 | return Decode(f) 25 | } 26 | 27 | func convertToRGBA(in image.Image) image.Image { 28 | b := in.Bounds() 29 | out := image.NewRGBA(b) 30 | draw.Draw(out, b, in, b.Min, draw.Src) 31 | return out 32 | } 33 | 34 | func convertToNRGBA(in image.Image) image.Image { 35 | b := in.Bounds() 36 | out := image.NewNRGBA(b) 37 | draw.Draw(out, b, in, b.Min, draw.Src) 38 | return out 39 | } 40 | 41 | func TestEncode(t *testing.T) { 42 | testCases := []string{ 43 | "video-001.bmp", 44 | "yellow_rose-small.bmp", 45 | } 46 | 47 | for _, tc := range testCases { 48 | img0, err := openImage(tc) 49 | if err != nil { 50 | t.Errorf("%s: Open BMP: %v", tc, err) 51 | continue 52 | } 53 | 54 | buf := new(bytes.Buffer) 55 | err = Encode(buf, img0) 56 | if err != nil { 57 | t.Errorf("%s: Encode BMP: %v", tc, err) 58 | continue 59 | } 60 | 61 | img1, err := Decode(buf) 62 | if err != nil { 63 | t.Errorf("%s: Decode BMP: %v", tc, err) 64 | continue 65 | } 66 | 67 | err = compare(img0, img1) 68 | if err != nil { 69 | t.Errorf("%s: Compare BMP: %v", tc, err) 70 | continue 71 | } 72 | 73 | buf2 := new(bytes.Buffer) 74 | rgba := convertToRGBA(img0) 75 | err = Encode(buf2, rgba) 76 | if err != nil { 77 | t.Errorf("%s: Encode pre-multiplied BMP: %v", tc, err) 78 | continue 79 | } 80 | 81 | img2, err := Decode(buf2) 82 | if err != nil { 83 | t.Errorf("%s: Decode pre-multiplied BMP: %v", tc, err) 84 | continue 85 | } 86 | 87 | // We need to do another round trip to NRGBA to compare to, since 88 | // the conversion process is lossy. 89 | img3 := convertToNRGBA(rgba) 90 | 91 | err = compare(img3, img2) 92 | if err != nil { 93 | t.Errorf("%s: Compare pre-multiplied BMP: %v", tc, err) 94 | } 95 | } 96 | } 97 | 98 | // TestZeroWidthVeryLargeHeight tests that encoding and decoding a degenerate 99 | // image with zero width but over one billion pixels in height is faster than 100 | // naively calling an io.Reader or io.Writer method once per row. 101 | func TestZeroWidthVeryLargeHeight(t *testing.T) { 102 | c := make(chan error, 1) 103 | go func() { 104 | b := image.Rect(0, 0, 0, 0x3fffffff) 105 | var buf bytes.Buffer 106 | if err := Encode(&buf, image.NewRGBA(b)); err != nil { 107 | c <- err 108 | return 109 | } 110 | m, err := Decode(&buf) 111 | if err != nil { 112 | c <- err 113 | return 114 | } 115 | if got := m.Bounds(); got != b { 116 | c <- fmt.Errorf("bounds: got %v, want %v", got, b) 117 | return 118 | } 119 | c <- nil 120 | }() 121 | select { 122 | case err := <-c: 123 | if err != nil { 124 | t.Fatal(err) 125 | } 126 | case <-time.After(3 * time.Second): 127 | t.Fatalf("timed out") 128 | } 129 | } 130 | 131 | // BenchmarkEncode benchmarks the encoding of an image. 132 | func BenchmarkEncode(b *testing.B) { 133 | img, err := openImage("video-001.bmp") 134 | if err != nil { 135 | b.Fatal(err) 136 | } 137 | s := img.Bounds().Size() 138 | b.SetBytes(int64(s.X * s.Y * 4)) 139 | b.ResetTimer() 140 | for i := 0; i < b.N; i++ { 141 | Encode(ioutil.Discard, img) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /ccitt/table_test.go: -------------------------------------------------------------------------------- 1 | // generated by "go run gen.go". DO NOT EDIT. 2 | 3 | package ccitt 4 | 5 | // COPY PASTE table_test.go BEGIN 6 | 7 | type code struct { 8 | val uint32 9 | str string 10 | } 11 | 12 | var modeCodes = []code{ 13 | {modePass, "0001"}, 14 | {modeH, "001"}, 15 | {modeV0, "1"}, 16 | {modeVR1, "011"}, 17 | {modeVR2, "000011"}, 18 | {modeVR3, "0000011"}, 19 | {modeVL1, "010"}, 20 | {modeVL2, "000010"}, 21 | {modeVL3, "0000010"}, 22 | {modeExt, "0000001"}, 23 | } 24 | 25 | var whiteCodes = []code{ 26 | // Terminating codes (0-63). 27 | {0x0000, "00110101"}, 28 | {0x0001, "000111"}, 29 | {0x0002, "0111"}, 30 | {0x0003, "1000"}, 31 | {0x0004, "1011"}, 32 | {0x0005, "1100"}, 33 | {0x0006, "1110"}, 34 | {0x0007, "1111"}, 35 | {0x0008, "10011"}, 36 | {0x0009, "10100"}, 37 | {0x000A, "00111"}, 38 | {0x000B, "01000"}, 39 | {0x000C, "001000"}, 40 | {0x000D, "000011"}, 41 | {0x000E, "110100"}, 42 | {0x000F, "110101"}, 43 | {0x0010, "101010"}, 44 | {0x0011, "101011"}, 45 | {0x0012, "0100111"}, 46 | {0x0013, "0001100"}, 47 | {0x0014, "0001000"}, 48 | {0x0015, "0010111"}, 49 | {0x0016, "0000011"}, 50 | {0x0017, "0000100"}, 51 | {0x0018, "0101000"}, 52 | {0x0019, "0101011"}, 53 | {0x001A, "0010011"}, 54 | {0x001B, "0100100"}, 55 | {0x001C, "0011000"}, 56 | {0x001D, "00000010"}, 57 | {0x001E, "00000011"}, 58 | {0x001F, "00011010"}, 59 | {0x0020, "00011011"}, 60 | {0x0021, "00010010"}, 61 | {0x0022, "00010011"}, 62 | {0x0023, "00010100"}, 63 | {0x0024, "00010101"}, 64 | {0x0025, "00010110"}, 65 | {0x0026, "00010111"}, 66 | {0x0027, "00101000"}, 67 | {0x0028, "00101001"}, 68 | {0x0029, "00101010"}, 69 | {0x002A, "00101011"}, 70 | {0x002B, "00101100"}, 71 | {0x002C, "00101101"}, 72 | {0x002D, "00000100"}, 73 | {0x002E, "00000101"}, 74 | {0x002F, "00001010"}, 75 | {0x0030, "00001011"}, 76 | {0x0031, "01010010"}, 77 | {0x0032, "01010011"}, 78 | {0x0033, "01010100"}, 79 | {0x0034, "01010101"}, 80 | {0x0035, "00100100"}, 81 | {0x0036, "00100101"}, 82 | {0x0037, "01011000"}, 83 | {0x0038, "01011001"}, 84 | {0x0039, "01011010"}, 85 | {0x003A, "01011011"}, 86 | {0x003B, "01001010"}, 87 | {0x003C, "01001011"}, 88 | {0x003D, "00110010"}, 89 | {0x003E, "00110011"}, 90 | {0x003F, "00110100"}, 91 | 92 | // Make-up codes between 64 and 1728. 93 | {0x0040, "11011"}, 94 | {0x0080, "10010"}, 95 | {0x00C0, "010111"}, 96 | {0x0100, "0110111"}, 97 | {0x0140, "00110110"}, 98 | {0x0180, "00110111"}, 99 | {0x01C0, "01100100"}, 100 | {0x0200, "01100101"}, 101 | {0x0240, "01101000"}, 102 | {0x0280, "01100111"}, 103 | {0x02C0, "011001100"}, 104 | {0x0300, "011001101"}, 105 | {0x0340, "011010010"}, 106 | {0x0380, "011010011"}, 107 | {0x03C0, "011010100"}, 108 | {0x0400, "011010101"}, 109 | {0x0440, "011010110"}, 110 | {0x0480, "011010111"}, 111 | {0x04C0, "011011000"}, 112 | {0x0500, "011011001"}, 113 | {0x0540, "011011010"}, 114 | {0x0580, "011011011"}, 115 | {0x05C0, "010011000"}, 116 | {0x0600, "010011001"}, 117 | {0x0640, "010011010"}, 118 | {0x0680, "011000"}, 119 | {0x06C0, "010011011"}, 120 | 121 | // Make-up codes between 1792 and 2560. 122 | {0x0700, "00000001000"}, 123 | {0x0740, "00000001100"}, 124 | {0x0780, "00000001101"}, 125 | {0x07C0, "000000010010"}, 126 | {0x0800, "000000010011"}, 127 | {0x0840, "000000010100"}, 128 | {0x0880, "000000010101"}, 129 | {0x08C0, "000000010110"}, 130 | {0x0900, "000000010111"}, 131 | {0x0940, "000000011100"}, 132 | {0x0980, "000000011101"}, 133 | {0x09C0, "000000011110"}, 134 | {0x0A00, "000000011111"}, 135 | } 136 | 137 | var blackCodes = []code{ 138 | // Terminating codes (0-63). 139 | {0x0000, "0000110111"}, 140 | {0x0001, "010"}, 141 | {0x0002, "11"}, 142 | {0x0003, "10"}, 143 | {0x0004, "011"}, 144 | {0x0005, "0011"}, 145 | {0x0006, "0010"}, 146 | {0x0007, "00011"}, 147 | {0x0008, "000101"}, 148 | {0x0009, "000100"}, 149 | {0x000A, "0000100"}, 150 | {0x000B, "0000101"}, 151 | {0x000C, "0000111"}, 152 | {0x000D, "00000100"}, 153 | {0x000E, "00000111"}, 154 | {0x000F, "000011000"}, 155 | {0x0010, "0000010111"}, 156 | {0x0011, "0000011000"}, 157 | {0x0012, "0000001000"}, 158 | {0x0013, "00001100111"}, 159 | {0x0014, "00001101000"}, 160 | {0x0015, "00001101100"}, 161 | {0x0016, "00000110111"}, 162 | {0x0017, "00000101000"}, 163 | {0x0018, "00000010111"}, 164 | {0x0019, "00000011000"}, 165 | {0x001A, "000011001010"}, 166 | {0x001B, "000011001011"}, 167 | {0x001C, "000011001100"}, 168 | {0x001D, "000011001101"}, 169 | {0x001E, "000001101000"}, 170 | {0x001F, "000001101001"}, 171 | {0x0020, "000001101010"}, 172 | {0x0021, "000001101011"}, 173 | {0x0022, "000011010010"}, 174 | {0x0023, "000011010011"}, 175 | {0x0024, "000011010100"}, 176 | {0x0025, "000011010101"}, 177 | {0x0026, "000011010110"}, 178 | {0x0027, "000011010111"}, 179 | {0x0028, "000001101100"}, 180 | {0x0029, "000001101101"}, 181 | {0x002A, "000011011010"}, 182 | {0x002B, "000011011011"}, 183 | {0x002C, "000001010100"}, 184 | {0x002D, "000001010101"}, 185 | {0x002E, "000001010110"}, 186 | {0x002F, "000001010111"}, 187 | {0x0030, "000001100100"}, 188 | {0x0031, "000001100101"}, 189 | {0x0032, "000001010010"}, 190 | {0x0033, "000001010011"}, 191 | {0x0034, "000000100100"}, 192 | {0x0035, "000000110111"}, 193 | {0x0036, "000000111000"}, 194 | {0x0037, "000000100111"}, 195 | {0x0038, "000000101000"}, 196 | {0x0039, "000001011000"}, 197 | {0x003A, "000001011001"}, 198 | {0x003B, "000000101011"}, 199 | {0x003C, "000000101100"}, 200 | {0x003D, "000001011010"}, 201 | {0x003E, "000001100110"}, 202 | {0x003F, "000001100111"}, 203 | 204 | // Make-up codes between 64 and 1728. 205 | {0x0040, "0000001111"}, 206 | {0x0080, "000011001000"}, 207 | {0x00C0, "000011001001"}, 208 | {0x0100, "000001011011"}, 209 | {0x0140, "000000110011"}, 210 | {0x0180, "000000110100"}, 211 | {0x01C0, "000000110101"}, 212 | {0x0200, "0000001101100"}, 213 | {0x0240, "0000001101101"}, 214 | {0x0280, "0000001001010"}, 215 | {0x02C0, "0000001001011"}, 216 | {0x0300, "0000001001100"}, 217 | {0x0340, "0000001001101"}, 218 | {0x0380, "0000001110010"}, 219 | {0x03C0, "0000001110011"}, 220 | {0x0400, "0000001110100"}, 221 | {0x0440, "0000001110101"}, 222 | {0x0480, "0000001110110"}, 223 | {0x04C0, "0000001110111"}, 224 | {0x0500, "0000001010010"}, 225 | {0x0540, "0000001010011"}, 226 | {0x0580, "0000001010100"}, 227 | {0x05C0, "0000001010101"}, 228 | {0x0600, "0000001011010"}, 229 | {0x0640, "0000001011011"}, 230 | {0x0680, "0000001100100"}, 231 | {0x06C0, "0000001100101"}, 232 | 233 | // Make-up codes between 1792 and 2560. 234 | {0x0700, "00000001000"}, 235 | {0x0740, "00000001100"}, 236 | {0x0780, "00000001101"}, 237 | {0x07C0, "000000010010"}, 238 | {0x0800, "000000010011"}, 239 | {0x0840, "000000010100"}, 240 | {0x0880, "000000010101"}, 241 | {0x08C0, "000000010110"}, 242 | {0x0900, "000000010111"}, 243 | {0x0940, "000000011100"}, 244 | {0x0980, "000000011101"}, 245 | {0x09C0, "000000011110"}, 246 | {0x0A00, "000000011111"}, 247 | } 248 | 249 | // COPY PASTE table_test.go END 250 | -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-aligned.ccitt_group3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-aligned.ccitt_group3 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-aligned.ccitt_group4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-aligned.ccitt_group4 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-inverted-aligned.ccitt_group3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-inverted-aligned.ccitt_group3 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-inverted-aligned.ccitt_group4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-inverted-aligned.ccitt_group4 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-inverted.ccitt_group3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-inverted.ccitt_group3 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-inverted.ccitt_group4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-inverted.ccitt_group4 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-truncated0.ccitt_group3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-truncated0.ccitt_group3 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-truncated0.ccitt_group4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-truncated0.ccitt_group4 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-truncated1.ccitt_group3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-truncated1.ccitt_group3 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher-truncated1.ccitt_group4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher-truncated1.ccitt_group4 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher.ccitt_group3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher.ccitt_group3 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher.ccitt_group4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher.ccitt_group4 -------------------------------------------------------------------------------- /ccitt/testdata/bw-gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/ccitt/testdata/bw-gopher.png -------------------------------------------------------------------------------- /ccitt/writer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ccitt 6 | 7 | import ( 8 | "encoding/binary" 9 | "io" 10 | ) 11 | 12 | type bitWriter struct { 13 | w io.Writer 14 | 15 | // order is whether to process w's bytes LSB first or MSB first. 16 | order Order 17 | 18 | // The high nBits bits of the bits field hold encoded bits to be written to w. 19 | bits uint64 20 | nBits uint32 21 | 22 | // bytes[:bw] holds encoded bytes not yet written to w. 23 | // Overflow protection is ensured by using a multiple of 8 as bytes length. 24 | bw uint32 25 | bytes [1024]uint8 26 | } 27 | 28 | // flushBits copies 64 bits from b.bits to b.bytes. If b.bytes is then full, it 29 | // is written to b.w. 30 | func (b *bitWriter) flushBits() error { 31 | binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits) 32 | b.bits = 0 33 | b.nBits = 0 34 | b.bw += 8 35 | if b.bw < uint32(len(b.bytes)) { 36 | return nil 37 | } 38 | b.bw = 0 39 | if b.order != MSB { 40 | reverseBitsWithinBytes(b.bytes[:]) 41 | } 42 | _, err := b.w.Write(b.bytes[:]) 43 | return err 44 | } 45 | 46 | // close finalizes a bitcode stream by writing any 47 | // pending bits to bitWriter's underlying io.Writer. 48 | func (b *bitWriter) close() error { 49 | // Write any encoded bits to bytes. 50 | if b.nBits > 0 { 51 | binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits) 52 | b.bw += (b.nBits + 7) >> 3 53 | } 54 | 55 | if b.order != MSB { 56 | reverseBitsWithinBytes(b.bytes[:b.bw]) 57 | } 58 | 59 | // Write b.bw bytes to b.w. 60 | _, err := b.w.Write(b.bytes[:b.bw]) 61 | return err 62 | } 63 | 64 | // alignToByteBoundary rounds b.nBits up to a multiple of 8. 65 | // If all 64 bits are used, flush them to bitWriter's bytes. 66 | func (b *bitWriter) alignToByteBoundary() error { 67 | if b.nBits = (b.nBits + 7) &^ 7; b.nBits == 64 { 68 | return b.flushBits() 69 | } 70 | return nil 71 | } 72 | 73 | // writeCode writes a variable length bitcode to b's underlying io.Writer. 74 | func (b *bitWriter) writeCode(bs bitString) error { 75 | bits := bs.bits 76 | nBits := bs.nBits 77 | if 64-b.nBits >= nBits { 78 | // b.bits has sufficient room for storing nBits bits. 79 | b.bits |= uint64(bits) << (64 - nBits - b.nBits) 80 | b.nBits += nBits 81 | if b.nBits == 64 { 82 | return b.flushBits() 83 | } 84 | return nil 85 | } 86 | 87 | // Number of leading bits that fill b.bits. 88 | i := 64 - b.nBits 89 | 90 | // Fill b.bits then flush and write remaining bits. 91 | b.bits |= uint64(bits) >> (nBits - i) 92 | b.nBits = 64 93 | 94 | if err := b.flushBits(); err != nil { 95 | return err 96 | } 97 | 98 | nBits -= i 99 | b.bits = uint64(bits) << (64 - nBits) 100 | b.nBits = nBits 101 | return nil 102 | } 103 | -------------------------------------------------------------------------------- /ccitt/writer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ccitt 6 | 7 | import ( 8 | "bytes" 9 | "reflect" 10 | "testing" 11 | ) 12 | 13 | func testEncode(t *testing.T, o Order) { 14 | t.Helper() 15 | values := []uint32{0, 1, 256, 7, 128, 3, 2560, 2240, 2368, 2048} 16 | 17 | decTable := whiteDecodeTable[:] 18 | encTableSmall := whiteEncodeTable2[:] 19 | encTableBig := whiteEncodeTable3[:] 20 | 21 | // Encode values to bit stream. 22 | var bb bytes.Buffer 23 | w := &bitWriter{w: &bb, order: o} 24 | for _, v := range values { 25 | encTable := encTableSmall 26 | if v < 64 { 27 | // No-op. 28 | } else if v&63 != 0 { 29 | t.Fatalf("writeCode: cannot encode %d: large but not a multiple of 64", v) 30 | } else { 31 | encTable = encTableBig 32 | v = v/64 - 1 33 | } 34 | if err := w.writeCode(encTable[v]); err != nil { 35 | t.Fatalf("writeCode: %v", err) 36 | } 37 | } 38 | if err := w.close(); err != nil { 39 | t.Fatalf("close: %v", err) 40 | } 41 | 42 | // Decode bit stream to values. 43 | got := []uint32(nil) 44 | r := &bitReader{ 45 | r: bytes.NewReader(bb.Bytes()), 46 | order: o, 47 | } 48 | finalValue := values[len(values)-1] 49 | for { 50 | v, err := decode(r, decTable) 51 | if err != nil { 52 | t.Fatalf("after got=%d: %v", got, err) 53 | } 54 | got = append(got, v) 55 | if v == finalValue { 56 | break 57 | } 58 | } 59 | 60 | // Check that the round-tripped values were unchanged. 61 | if !reflect.DeepEqual(got, values) { 62 | t.Fatalf("\ngot: %v\nwant: %v", got, values) 63 | } 64 | } 65 | 66 | func TestEncodeLSB(t *testing.T) { testEncode(t, LSB) } 67 | func TestEncodeMSB(t *testing.T) { testEncode(t, MSB) } 68 | -------------------------------------------------------------------------------- /cmd/webp-manual-test/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build ignore 6 | // +build ignore 7 | 8 | // This build tag means that "go install golang.org/x/image/..." doesn't 9 | // install this manual test. Use "go run main.go" to explicitly run it. 10 | 11 | // Program webp-manual-test checks that the Go WEBP library's decodings match 12 | // the C WEBP library's. 13 | package main // import "golang.org/x/image/cmd/webp-manual-test" 14 | 15 | import ( 16 | "bytes" 17 | "encoding/hex" 18 | "flag" 19 | "fmt" 20 | "image" 21 | "io" 22 | "log" 23 | "os" 24 | "os/exec" 25 | "path/filepath" 26 | "sort" 27 | "strings" 28 | 29 | "golang.org/x/image/webp" 30 | ) 31 | 32 | var ( 33 | dwebp = flag.String("dwebp", "/usr/bin/dwebp", "path to the dwebp program "+ 34 | "installed from https://developers.google.com/speed/webp/download") 35 | testdata = flag.String("testdata", "", "path to the libwebp-test-data directory "+ 36 | "checked out from https://chromium.googlesource.com/webm/libwebp-test-data") 37 | ) 38 | 39 | func main() { 40 | flag.Parse() 41 | if err := checkDwebp(); err != nil { 42 | flag.Usage() 43 | log.Fatal(err) 44 | } 45 | if *testdata == "" { 46 | flag.Usage() 47 | log.Fatal("testdata flag was not specified") 48 | } 49 | 50 | f, err := os.Open(*testdata) 51 | if err != nil { 52 | log.Fatalf("Open: %v", err) 53 | } 54 | defer f.Close() 55 | names, err := f.Readdirnames(-1) 56 | if err != nil { 57 | log.Fatalf("Readdirnames: %v", err) 58 | } 59 | sort.Strings(names) 60 | 61 | nFail, nPass := 0, 0 62 | for _, name := range names { 63 | if !strings.HasSuffix(name, "webp") { 64 | continue 65 | } 66 | if err := test(name); err != nil { 67 | fmt.Printf("FAIL\t%s\t%v\n", name, err) 68 | nFail++ 69 | } else { 70 | fmt.Printf("PASS\t%s\n", name) 71 | nPass++ 72 | } 73 | } 74 | fmt.Printf("%d PASS, %d FAIL, %d TOTAL\n", nPass, nFail, nPass+nFail) 75 | if nFail != 0 { 76 | os.Exit(1) 77 | } 78 | } 79 | 80 | func checkDwebp() error { 81 | if *dwebp == "" { 82 | return fmt.Errorf("dwebp flag was not specified") 83 | } 84 | if _, err := os.Stat(*dwebp); err != nil { 85 | return fmt.Errorf("could not find dwebp program at %q", *dwebp) 86 | } 87 | b, err := exec.Command(*dwebp, "-version").Output() 88 | if err != nil { 89 | return fmt.Errorf("could not determine the dwebp program version for %q: %v", *dwebp, err) 90 | } 91 | switch s := string(bytes.TrimSpace(b)); s { 92 | case "0.4.0", "0.4.1", "0.4.2": 93 | return fmt.Errorf("the dwebp program version %q for %q has a known bug "+ 94 | "(https://bugs.chromium.org/p/webp/issues/detail?id=239). Please use a newer version.", s, *dwebp) 95 | } 96 | return nil 97 | } 98 | 99 | // test tests a single WEBP image. 100 | func test(name string) error { 101 | filename := filepath.Join(*testdata, name) 102 | f, err := os.Open(filename) 103 | if err != nil { 104 | return fmt.Errorf("Open: %v", err) 105 | } 106 | defer f.Close() 107 | 108 | gotImage, err := webp.Decode(f) 109 | if err != nil { 110 | return fmt.Errorf("Decode: %v", err) 111 | } 112 | format, encode := "-pgm", encodePGM 113 | if _, lossless := gotImage.(*image.NRGBA); lossless { 114 | format, encode = "-pam", encodePAM 115 | } 116 | got, err := encode(gotImage) 117 | if err != nil { 118 | return fmt.Errorf("encode: %v", err) 119 | } 120 | 121 | stdout := new(bytes.Buffer) 122 | stderr := new(bytes.Buffer) 123 | c := exec.Command(*dwebp, filename, format, "-o", "/dev/stdout") 124 | c.Stdout = stdout 125 | c.Stderr = stderr 126 | if err := c.Run(); err != nil { 127 | os.Stderr.Write(stderr.Bytes()) 128 | return fmt.Errorf("executing dwebp: %v", err) 129 | } 130 | want := stdout.Bytes() 131 | 132 | if len(got) != len(want) { 133 | return fmt.Errorf("encodings have different length: got %d, want %d", len(got), len(want)) 134 | } 135 | for i, g := range got { 136 | if w := want[i]; g != w { 137 | return fmt.Errorf("encodings differ at position 0x%x: got 0x%02x, want 0x%02x", i, g, w) 138 | } 139 | } 140 | return nil 141 | } 142 | 143 | // encodePAM encodes gotImage in the PAM format. 144 | func encodePAM(gotImage image.Image) ([]byte, error) { 145 | m, ok := gotImage.(*image.NRGBA) 146 | if !ok { 147 | return nil, fmt.Errorf("lossless image did not decode to an *image.NRGBA") 148 | } 149 | b := m.Bounds() 150 | w, h := b.Dx(), b.Dy() 151 | buf := new(bytes.Buffer) 152 | fmt.Fprintf(buf, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n", w, h) 153 | for y := b.Min.Y; y < b.Max.Y; y++ { 154 | o := m.PixOffset(b.Min.X, y) 155 | buf.Write(m.Pix[o : o+4*w]) 156 | } 157 | return buf.Bytes(), nil 158 | } 159 | 160 | // encodePGM encodes gotImage in the PGM format in the IMC4 layout. 161 | func encodePGM(gotImage image.Image) ([]byte, error) { 162 | var ( 163 | m *image.YCbCr 164 | ma *image.NYCbCrA 165 | ) 166 | switch g := gotImage.(type) { 167 | case *image.YCbCr: 168 | m = g 169 | case *image.NYCbCrA: 170 | m = &g.YCbCr 171 | ma = g 172 | default: 173 | return nil, fmt.Errorf("lossy image did not decode to an *image.YCbCr") 174 | } 175 | if m.SubsampleRatio != image.YCbCrSubsampleRatio420 { 176 | return nil, fmt.Errorf("lossy image did not decode to a 4:2:0 YCbCr") 177 | } 178 | b := m.Bounds() 179 | w, h := b.Dx(), b.Dy() 180 | w2, h2 := (w+1)/2, (h+1)/2 181 | outW, outH := 2*w2, h+h2 182 | if ma != nil { 183 | outH += h 184 | } 185 | buf := new(bytes.Buffer) 186 | fmt.Fprintf(buf, "P5\n%d %d\n255\n", outW, outH) 187 | for y := b.Min.Y; y < b.Max.Y; y++ { 188 | o := m.YOffset(b.Min.X, y) 189 | buf.Write(m.Y[o : o+w]) 190 | if w&1 != 0 { 191 | buf.WriteByte(0x00) 192 | } 193 | } 194 | for y := b.Min.Y; y < b.Max.Y; y += 2 { 195 | o := m.COffset(b.Min.X, y) 196 | buf.Write(m.Cb[o : o+w2]) 197 | buf.Write(m.Cr[o : o+w2]) 198 | } 199 | if ma != nil { 200 | for y := b.Min.Y; y < b.Max.Y; y++ { 201 | o := ma.AOffset(b.Min.X, y) 202 | buf.Write(ma.A[o : o+w]) 203 | if w&1 != 0 { 204 | buf.WriteByte(0x00) 205 | } 206 | } 207 | } 208 | return buf.Bytes(), nil 209 | } 210 | 211 | // dump can be useful for debugging. 212 | func dump(w io.Writer, b []byte) { 213 | h := hex.Dumper(w) 214 | h.Write(b) 215 | h.Close() 216 | } 217 | -------------------------------------------------------------------------------- /codereview.cfg: -------------------------------------------------------------------------------- 1 | issuerepo: golang/go 2 | -------------------------------------------------------------------------------- /colornames/colornames.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate go run gen.go 6 | 7 | // Package colornames provides named colors as defined in the SVG 1.1 spec. 8 | // 9 | // See https://www.w3.org/TR/SVG11/types.html#ColorKeywords 10 | package colornames 11 | -------------------------------------------------------------------------------- /colornames/colornames_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package colornames 6 | 7 | import ( 8 | "image/color" 9 | "testing" 10 | ) 11 | 12 | func TestColornames(t *testing.T) { 13 | if len(Map) != len(Names) { 14 | t.Fatalf("Map and Names have different length: %d vs %d", len(Map), len(Names)) 15 | } 16 | 17 | for name, want := range testCases { 18 | got, ok := Map[name] 19 | if !ok { 20 | t.Errorf("Did not find %s", name) 21 | continue 22 | } 23 | if got != want { 24 | t.Errorf("%s:\ngot %v\nwant %v", name, got, want) 25 | } 26 | } 27 | } 28 | 29 | var testCases = map[string]color.RGBA{ 30 | "aliceblue": color.RGBA{240, 248, 255, 255}, 31 | "crimson": color.RGBA{220, 20, 60, 255}, 32 | "darkorange": color.RGBA{255, 140, 0, 255}, 33 | "deepskyblue": color.RGBA{0, 191, 255, 255}, 34 | "greenyellow": color.RGBA{173, 255, 47, 255}, 35 | "lightgrey": color.RGBA{211, 211, 211, 255}, 36 | "lightpink": color.RGBA{255, 182, 193, 255}, 37 | "mediumseagreen": color.RGBA{60, 179, 113, 255}, 38 | "olivedrab": color.RGBA{107, 142, 35, 255}, 39 | "purple": color.RGBA{128, 0, 128, 255}, 40 | "slategrey": color.RGBA{112, 128, 144, 255}, 41 | "yellowgreen": color.RGBA{154, 205, 50, 255}, 42 | } 43 | -------------------------------------------------------------------------------- /colornames/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build ignore 6 | 7 | // This program generates table.go from 8 | // https://www.w3.org/TR/SVG11/types.html#ColorKeywords 9 | package main 10 | 11 | import ( 12 | "bytes" 13 | "fmt" 14 | "go/format" 15 | "image/color" 16 | "io" 17 | "io/ioutil" 18 | "log" 19 | "net/http" 20 | "regexp" 21 | "sort" 22 | "strconv" 23 | "strings" 24 | 25 | "golang.org/x/net/html" 26 | "golang.org/x/net/html/atom" 27 | ) 28 | 29 | // matchFunc matches HTML nodes. 30 | type matchFunc func(*html.Node) bool 31 | 32 | // appendAll recursively traverses the parse tree rooted under the provided 33 | // node and appends all nodes matched by the matchFunc to dst. 34 | func appendAll(dst []*html.Node, n *html.Node, mf matchFunc) []*html.Node { 35 | if mf(n) { 36 | dst = append(dst, n) 37 | } 38 | for c := n.FirstChild; c != nil; c = c.NextSibling { 39 | dst = appendAll(dst, c, mf) 40 | } 41 | return dst 42 | } 43 | 44 | // matchAtom returns a matchFunc that matches a Node with the specified Atom. 45 | func matchAtom(a atom.Atom) matchFunc { 46 | return func(n *html.Node) bool { 47 | return n.DataAtom == a 48 | } 49 | } 50 | 51 | // matchAtomAttr returns a matchFunc that matches a Node with the specified 52 | // Atom and a html.Attribute's namespace, key and value. 53 | func matchAtomAttr(a atom.Atom, namespace, key, value string) matchFunc { 54 | return func(n *html.Node) bool { 55 | return n.DataAtom == a && getAttr(n, namespace, key) == value 56 | } 57 | } 58 | 59 | // getAttr fetches the value of a html.Attribute for a given namespace and key. 60 | func getAttr(n *html.Node, namespace, key string) string { 61 | for _, attr := range n.Attr { 62 | if attr.Namespace == namespace && attr.Key == key { 63 | return attr.Val 64 | } 65 | } 66 | return "" 67 | } 68 | 69 | // re extracts RGB values from strings like "rgb( 0, 223, 128)". 70 | var re = regexp.MustCompile(`rgb\(\s*([0-9]+),\s*([0-9]+),\s*([0-9]+)\)`) 71 | 72 | // parseRGB parses a color from a string like "rgb( 0, 233, 128)". It sets 73 | // the alpha value of the color to full opacity. 74 | func parseRGB(s string) (color.RGBA, error) { 75 | m := re.FindStringSubmatch(s) 76 | if m == nil { 77 | return color.RGBA{}, fmt.Errorf("malformed color: %q", s) 78 | } 79 | var rgb [3]uint8 80 | for i, t := range m[1:] { 81 | num, err := strconv.ParseUint(t, 10, 8) 82 | if err != nil { 83 | return color.RGBA{}, fmt.Errorf("malformed value %q in %q: %s", t, s, err) 84 | } 85 | rgb[i] = uint8(num) 86 | } 87 | return color.RGBA{rgb[0], rgb[1], rgb[2], 0xFF}, nil 88 | } 89 | 90 | // extractSVGColors extracts named colors from the parse tree of the SVG 1.1 91 | // spec HTML document "Chapter 4: Basic data types and interfaces". 92 | func extractSVGColors(tree *html.Node) (map[string]color.RGBA, error) { 93 | ret := make(map[string]color.RGBA) 94 | 95 | // Find the tables which store the color keywords in the parse tree. 96 | colorTables := appendAll(nil, tree, func(n *html.Node) bool { 97 | return n.DataAtom == atom.Table && strings.Contains(getAttr(n, "", "summary"), "color keywords part") 98 | }) 99 | 100 | for _, table := range colorTables { 101 | // Color names and values are stored in TextNodes within spans in each row. 102 | for _, tr := range appendAll(nil, table, matchAtom(atom.Tr)) { 103 | nameSpan := appendAll(nil, tr, matchAtomAttr(atom.Span, "", "class", "prop-value")) 104 | valueSpan := appendAll(nil, tr, matchAtomAttr(atom.Span, "", "class", "color-keyword-value")) 105 | 106 | // Since SVG 1.1 defines an odd number of colors, the last row 107 | // in the second table does not have contents. We skip it. 108 | if len(nameSpan) != 1 || len(valueSpan) != 1 { 109 | continue 110 | } 111 | n, v := nameSpan[0].FirstChild, valueSpan[0].FirstChild 112 | // This sanity checks for the existence of TextNodes under spans. 113 | if n == nil || n.Type != html.TextNode || v == nil || v.Type != html.TextNode { 114 | return nil, fmt.Errorf("extractSVGColors: couldn't find name/value text nodes") 115 | } 116 | val, err := parseRGB(v.Data) 117 | if err != nil { 118 | return nil, fmt.Errorf("extractSVGColors: couldn't parse name/value %q/%q: %s", n.Data, v.Data, err) 119 | } 120 | ret[n.Data] = val 121 | } 122 | } 123 | return ret, nil 124 | } 125 | 126 | const preamble = `// generated by go generate; DO NOT EDIT. 127 | 128 | package colornames 129 | 130 | import "image/color" 131 | 132 | ` 133 | 134 | // WriteColorNames writes table.go. 135 | func writeColorNames(w io.Writer, m map[string]color.RGBA) { 136 | keys := make([]string, 0, len(m)) 137 | for k := range m { 138 | keys = append(keys, k) 139 | } 140 | sort.Strings(keys) 141 | 142 | fmt.Fprintln(w, preamble) 143 | fmt.Fprintln(w, "// Map contains named colors defined in the SVG 1.1 spec.") 144 | fmt.Fprintln(w, "var Map = map[string]color.RGBA{") 145 | for _, k := range keys { 146 | c := m[k] 147 | fmt.Fprintf(w, "%q:color.RGBA{%#02x, %#02x, %#02x, %#02x}, // rgb(%d, %d, %d)\n", 148 | k, c.R, c.G, c.B, c.A, c.R, c.G, c.B) 149 | } 150 | fmt.Fprintln(w, "}\n") 151 | fmt.Fprintln(w, "// Names contains the color names defined in the SVG 1.1 spec.") 152 | fmt.Fprintln(w, "var Names = []string{") 153 | for _, k := range keys { 154 | fmt.Fprintf(w, "%q,\n", k) 155 | } 156 | fmt.Fprintln(w, "}\n") 157 | fmt.Fprintln(w, "var (") 158 | for _, k := range keys { 159 | c := m[k] 160 | // Make the upper case version of k: "Darkred" instead of "darkred". 161 | k = string(k[0]-0x20) + k[1:] 162 | fmt.Fprintf(w, "%s=color.RGBA{%#02x, %#02x, %#02x, %#02x} // rgb(%d, %d, %d)\n", 163 | k, c.R, c.G, c.B, c.A, c.R, c.G, c.B) 164 | } 165 | fmt.Fprintln(w, ")") 166 | } 167 | 168 | const url = "https://www.w3.org/TR/SVG11/types.html" 169 | 170 | func main() { 171 | res, err := http.Get(url) 172 | if err != nil { 173 | log.Fatalf("Couldn't read from %s: %s\n", url, err) 174 | } 175 | defer res.Body.Close() 176 | 177 | tree, err := html.Parse(res.Body) 178 | if err != nil { 179 | log.Fatalf("Couldn't parse %s: %s\n", url, err) 180 | } 181 | 182 | colors, err := extractSVGColors(tree) 183 | if err != nil { 184 | log.Fatalf("Couldn't extract colors: %s\n", err) 185 | } 186 | 187 | buf := &bytes.Buffer{} 188 | writeColorNames(buf, colors) 189 | fmted, err := format.Source(buf.Bytes()) 190 | if err != nil { 191 | log.Fatalf("Error while formatting code: %s\n", err) 192 | } 193 | 194 | if err := ioutil.WriteFile("table.go", fmted, 0644); err != nil { 195 | log.Fatalf("Error writing table.go: %s\n", err) 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /draw/draw.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package draw provides image composition functions. 6 | // 7 | // See "The Go image/draw package" for an introduction to this package: 8 | // http://golang.org/doc/articles/image_draw.html 9 | // 10 | // This package is a superset of and a drop-in replacement for the image/draw 11 | // package in the standard library. 12 | package draw 13 | 14 | // This file just contains the API exported by the image/draw package in the 15 | // standard library. Other files in this package provide additional features. 16 | 17 | import ( 18 | "image" 19 | "image/draw" 20 | ) 21 | 22 | // Draw calls DrawMask with a nil mask. 23 | func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) { 24 | draw.Draw(dst, r, src, sp, draw.Op(op)) 25 | } 26 | 27 | // DrawMask aligns r.Min in dst with sp in src and mp in mask and then 28 | // replaces the rectangle r in dst with the result of a Porter-Duff 29 | // composition. A nil mask is treated as opaque. 30 | func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) { 31 | draw.DrawMask(dst, r, src, sp, mask, mp, draw.Op(op)) 32 | } 33 | 34 | // Drawer contains the Draw method. 35 | type Drawer = draw.Drawer 36 | 37 | // FloydSteinberg is a Drawer that is the Src Op with Floyd-Steinberg error 38 | // diffusion. 39 | var FloydSteinberg Drawer = floydSteinberg{} 40 | 41 | type floydSteinberg struct{} 42 | 43 | func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) { 44 | draw.FloydSteinberg.Draw(dst, r, src, sp) 45 | } 46 | 47 | // Image is an image.Image with a Set method to change a single pixel. 48 | type Image = draw.Image 49 | 50 | // RGBA64Image extends both the Image and image.RGBA64Image interfaces with a 51 | // SetRGBA64 method to change a single pixel. SetRGBA64 is equivalent to 52 | // calling Set, but it can avoid allocations from converting concrete color 53 | // types to the color.Color interface type. 54 | type RGBA64Image = draw.RGBA64Image 55 | 56 | // Op is a Porter-Duff compositing operator. 57 | type Op = draw.Op 58 | 59 | const ( 60 | // Over specifies ``(src in mask) over dst''. 61 | Over Op = draw.Over 62 | // Src specifies ``src in mask''. 63 | Src Op = draw.Src 64 | ) 65 | 66 | // Quantizer produces a palette for an image. 67 | type Quantizer = draw.Quantizer 68 | -------------------------------------------------------------------------------- /draw/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package draw_test 6 | 7 | import ( 8 | "fmt" 9 | "image" 10 | "image/color" 11 | "image/png" 12 | "log" 13 | "math" 14 | "os" 15 | 16 | "golang.org/x/image/draw" 17 | "golang.org/x/image/math/f64" 18 | ) 19 | 20 | func ExampleDraw() { 21 | fSrc, err := os.Open("../testdata/blue-purple-pink.png") 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | defer fSrc.Close() 26 | src, err := png.Decode(fSrc) 27 | if err != nil { 28 | log.Fatal(err) 29 | } 30 | 31 | dst := image.NewRGBA(image.Rect(0, 0, 400, 300)) 32 | green := image.NewUniform(color.RGBA{0x00, 0x1f, 0x00, 0xff}) 33 | draw.Copy(dst, image.Point{}, green, dst.Bounds(), draw.Src, nil) 34 | qs := []draw.Interpolator{ 35 | draw.NearestNeighbor, 36 | draw.ApproxBiLinear, 37 | draw.CatmullRom, 38 | } 39 | const cos60, sin60 = 0.5, 0.866025404 40 | t := f64.Aff3{ 41 | +2 * cos60, -2 * sin60, 100, 42 | +2 * sin60, +2 * cos60, 100, 43 | } 44 | 45 | draw.Copy(dst, image.Point{20, 30}, src, src.Bounds(), draw.Over, nil) 46 | for i, q := range qs { 47 | q.Scale(dst, image.Rect(200+10*i, 100*i, 600+10*i, 150+100*i), src, src.Bounds(), draw.Over, nil) 48 | } 49 | draw.NearestNeighbor.Transform(dst, t, src, src.Bounds(), draw.Over, nil) 50 | 51 | red := image.NewNRGBA(image.Rect(0, 0, 16, 16)) 52 | for y := 0; y < 16; y++ { 53 | for x := 0; x < 16; x++ { 54 | red.SetNRGBA(x, y, color.NRGBA{ 55 | R: uint8(x * 0x11), 56 | A: uint8(y * 0x11), 57 | }) 58 | } 59 | } 60 | red.SetNRGBA(0, 0, color.NRGBA{0xff, 0xff, 0x00, 0xff}) 61 | red.SetNRGBA(15, 15, color.NRGBA{0xff, 0xff, 0x00, 0xff}) 62 | 63 | ops := []draw.Op{ 64 | draw.Over, 65 | draw.Src, 66 | } 67 | for i, op := range ops { 68 | dr := image.Rect(120+10*i, 150+60*i, 170+10*i, 200+60*i) 69 | draw.NearestNeighbor.Scale(dst, dr, red, red.Bounds(), op, nil) 70 | t := f64.Aff3{ 71 | +cos60, -sin60, float64(190 + 10*i), 72 | +sin60, +cos60, float64(140 + 50*i), 73 | } 74 | draw.NearestNeighbor.Transform(dst, t, red, red.Bounds(), op, nil) 75 | } 76 | 77 | dr := image.Rect(0, 0, 128, 128) 78 | checkerboard := image.NewAlpha(dr) 79 | for y := dr.Min.Y; y < dr.Max.Y; y++ { 80 | for x := dr.Min.X; x < dr.Max.X; x++ { 81 | if (x/20)%2 == (y/20)%2 { 82 | checkerboard.SetAlpha(x, y, color.Alpha{0xff}) 83 | } 84 | } 85 | } 86 | sr := image.Rect(0, 0, 16, 16) 87 | circle := image.NewAlpha(sr) 88 | for y := sr.Min.Y; y < sr.Max.Y; y++ { 89 | for x := sr.Min.X; x < sr.Max.X; x++ { 90 | dx, dy := x-10, y-8 91 | if d := 32 * math.Sqrt(float64(dx*dx)+float64(dy*dy)); d < 0xff { 92 | circle.SetAlpha(x, y, color.Alpha{0xff - uint8(d)}) 93 | } 94 | } 95 | } 96 | cyan := image.NewUniform(color.RGBA{0x00, 0xff, 0xff, 0xff}) 97 | draw.NearestNeighbor.Scale(dst, dr, cyan, sr, draw.Over, &draw.Options{ 98 | DstMask: checkerboard, 99 | SrcMask: circle, 100 | }) 101 | 102 | // Change false to true to write the resultant image to disk. 103 | if false { 104 | fDst, err := os.Create("out.png") 105 | if err != nil { 106 | log.Fatal(err) 107 | } 108 | defer fDst.Close() 109 | err = png.Encode(fDst, dst) 110 | if err != nil { 111 | log.Fatal(err) 112 | } 113 | } 114 | 115 | fmt.Printf("dst has bounds %v.\n", dst.Bounds()) 116 | // Output: 117 | // dst has bounds (0,0)-(400,300). 118 | } 119 | -------------------------------------------------------------------------------- /draw/stdlib_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package draw 6 | 7 | import ( 8 | "bytes" 9 | "image" 10 | "image/color" 11 | "testing" 12 | ) 13 | 14 | // TestFastPaths tests that the fast path implementations produce identical 15 | // results to the generic implementation. 16 | func TestFastPaths(t *testing.T) { 17 | drs := []image.Rectangle{ 18 | image.Rect(0, 0, 10, 10), // The dst bounds. 19 | image.Rect(3, 4, 8, 6), // A strict subset of the dst bounds. 20 | image.Rect(-3, -5, 2, 4), // Partial out-of-bounds #0. 21 | image.Rect(4, -2, 6, 12), // Partial out-of-bounds #1. 22 | image.Rect(12, 14, 23, 45), // Complete out-of-bounds. 23 | image.Rect(5, 5, 5, 5), // Empty. 24 | } 25 | srs := []image.Rectangle{ 26 | image.Rect(0, 0, 12, 9), // The src bounds. 27 | image.Rect(2, 2, 10, 8), // A strict subset of the src bounds. 28 | image.Rect(10, 5, 20, 20), // Partial out-of-bounds #0. 29 | image.Rect(-40, 0, 40, 8), // Partial out-of-bounds #1. 30 | image.Rect(-8, -8, -4, -4), // Complete out-of-bounds. 31 | image.Rect(5, 5, 5, 5), // Empty. 32 | } 33 | srcfs := []func(image.Rectangle) (image.Image, error){ 34 | srcGray, 35 | srcNRGBA, 36 | srcRGBA, 37 | srcUnif, 38 | srcYCbCr, 39 | } 40 | var srcs []image.Image 41 | for _, srcf := range srcfs { 42 | src, err := srcf(srs[0]) 43 | if err != nil { 44 | t.Fatal(err) 45 | } 46 | srcs = append(srcs, src) 47 | } 48 | qs := []Interpolator{ 49 | NearestNeighbor, 50 | ApproxBiLinear, 51 | CatmullRom, 52 | } 53 | ops := []Op{ 54 | Over, 55 | Src, 56 | } 57 | blue := image.NewUniform(color.RGBA{0x11, 0x22, 0x44, 0x7f}) 58 | 59 | for _, dr := range drs { 60 | for _, src := range srcs { 61 | for _, sr := range srs { 62 | for _, transform := range []bool{false, true} { 63 | for _, q := range qs { 64 | for _, op := range ops { 65 | dst0 := image.NewRGBA(drs[0]) 66 | dst1 := image.NewRGBA(drs[0]) 67 | Draw(dst0, dst0.Bounds(), blue, image.Point{}, Src) 68 | Draw(dstWrapper{dst1}, dst1.Bounds(), srcWrapper{blue}, image.Point{}, Src) 69 | 70 | if transform { 71 | m := transformMatrix(3.75, 2, 1) 72 | q.Transform(dst0, m, src, sr, op, nil) 73 | q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, op, nil) 74 | } else { 75 | q.Scale(dst0, dr, src, sr, op, nil) 76 | q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, op, nil) 77 | } 78 | 79 | if !bytes.Equal(dst0.Pix, dst1.Pix) { 80 | t.Errorf("pix differ for dr=%v, src=%T, sr=%v, transform=%t, q=%T", 81 | dr, src, sr, transform, q) 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /example/font/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build example 6 | // +build example 7 | 8 | // This build tag means that "go install golang.org/x/image/..." doesn't 9 | // install this example program. Use "go run main.go" to run it or "go install 10 | // -tags=example" to install it. 11 | 12 | // Font is a basic example of using fonts. 13 | package main 14 | 15 | import ( 16 | "flag" 17 | "image" 18 | "image/color" 19 | "image/draw" 20 | "image/png" 21 | "io/ioutil" 22 | "log" 23 | "os" 24 | "path/filepath" 25 | "strings" 26 | 27 | "golang.org/x/image/font" 28 | "golang.org/x/image/font/plan9font" 29 | "golang.org/x/image/math/fixed" 30 | ) 31 | 32 | var ( 33 | fontFlag = flag.String("font", "", 34 | `filename of the Plan 9 font or subfont file, such as "lucsans/unicode.8.font" or "lucsans/lsr.14"`) 35 | firstRuneFlag = flag.Int("firstrune", 0, "the Unicode code point of the first rune in the subfont file") 36 | ) 37 | 38 | func pt(p fixed.Point26_6) image.Point { 39 | return image.Point{ 40 | X: int(p.X+32) >> 6, 41 | Y: int(p.Y+32) >> 6, 42 | } 43 | } 44 | 45 | func main() { 46 | flag.Parse() 47 | 48 | // TODO: mmap the files. 49 | if *fontFlag == "" { 50 | flag.Usage() 51 | log.Fatal("no font specified") 52 | } 53 | var face font.Face 54 | if strings.HasSuffix(*fontFlag, ".font") { 55 | fontData, err := ioutil.ReadFile(*fontFlag) 56 | if err != nil { 57 | log.Fatal(err) 58 | } 59 | dir := filepath.Dir(*fontFlag) 60 | face, err = plan9font.ParseFont(fontData, func(name string) ([]byte, error) { 61 | return ioutil.ReadFile(filepath.Join(dir, filepath.FromSlash(name))) 62 | }) 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | } else { 67 | fontData, err := ioutil.ReadFile(*fontFlag) 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | face, err = plan9font.ParseSubfont(fontData, rune(*firstRuneFlag)) 72 | if err != nil { 73 | log.Fatal(err) 74 | } 75 | } 76 | 77 | dst := image.NewRGBA(image.Rect(0, 0, 800, 300)) 78 | draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src) 79 | 80 | d := &font.Drawer{ 81 | Dst: dst, 82 | Src: image.White, 83 | Face: face, 84 | } 85 | ss := []string{ 86 | "The quick brown fox jumps over the lazy dog.", 87 | "Hello, 世界.", 88 | "U+FFFD is \ufffd.", 89 | } 90 | for i, s := range ss { 91 | d.Dot = fixed.P(20, 100*i+80) 92 | dot0 := pt(d.Dot) 93 | d.DrawString(s) 94 | dot1 := pt(d.Dot) 95 | dst.SetRGBA(dot0.X, dot0.Y, color.RGBA{0xff, 0x00, 0x00, 0xff}) 96 | dst.SetRGBA(dot1.X, dot1.Y, color.RGBA{0x00, 0x00, 0xff, 0xff}) 97 | } 98 | 99 | out, err := os.Create("out.png") 100 | if err != nil { 101 | log.Fatal(err) 102 | } 103 | defer out.Close() 104 | if err := png.Encode(out, dst); err != nil { 105 | log.Fatal(err) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /font/basicfont/basicfont.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate go run gen.go 6 | 7 | // Package basicfont provides fixed-size font faces. 8 | package basicfont // import "golang.org/x/image/font/basicfont" 9 | 10 | import ( 11 | "image" 12 | 13 | "golang.org/x/image/font" 14 | "golang.org/x/image/math/fixed" 15 | ) 16 | 17 | // Range maps a contiguous range of runes to vertically adjacent sub-images of 18 | // a Face's Mask image. The rune range is inclusive on the low end and 19 | // exclusive on the high end. 20 | // 21 | // If Low <= r && r < High, then the rune r is mapped to the sub-image of 22 | // Face.Mask whose bounds are image.Rect(0, y*h, Face.Width, (y+1)*h), 23 | // where y = (int(r-Low) + Offset) and h = (Face.Ascent + Face.Descent). 24 | type Range struct { 25 | Low, High rune 26 | Offset int 27 | } 28 | 29 | // Face7x13 is a Face derived from the public domain X11 misc-fixed font files. 30 | // 31 | // At the moment, it holds the printable characters in ASCII starting with 32 | // space, and the Unicode replacement character U+FFFD. 33 | // 34 | // Its data is entirely self-contained and does not require loading from 35 | // separate files. 36 | var Face7x13 = &Face{ 37 | Advance: 7, 38 | Width: 6, 39 | Height: 13, 40 | Ascent: 11, 41 | Descent: 2, 42 | Mask: mask7x13, 43 | Ranges: []Range{ 44 | {'\u0020', '\u007f', 0}, 45 | {'\ufffd', '\ufffe', 95}, 46 | }, 47 | } 48 | 49 | // Face is a basic font face whose glyphs all have the same metrics. 50 | // 51 | // It is safe to use concurrently. 52 | type Face struct { 53 | // Advance is the glyph advance, in pixels. 54 | Advance int 55 | // Width is the glyph width, in pixels. 56 | Width int 57 | // Height is the inter-line height, in pixels. 58 | Height int 59 | // Ascent is the glyph ascent, in pixels. 60 | Ascent int 61 | // Descent is the glyph descent, in pixels. 62 | Descent int 63 | // Left is the left side bearing, in pixels. A positive value means that 64 | // all of a glyph is to the right of the dot. 65 | Left int 66 | 67 | // Mask contains all of the glyph masks. Its width is typically the Face's 68 | // Width, and its height a multiple of the Face's Height. 69 | Mask image.Image 70 | // Ranges map runes to sub-images of Mask. The rune ranges must not 71 | // overlap, and must be in increasing rune order. 72 | Ranges []Range 73 | } 74 | 75 | func (f *Face) Close() error { return nil } 76 | func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 { return 0 } 77 | 78 | func (f *Face) Metrics() font.Metrics { 79 | return font.Metrics{ 80 | Height: fixed.I(f.Height), 81 | Ascent: fixed.I(f.Ascent), 82 | Descent: fixed.I(f.Descent), 83 | XHeight: fixed.I(f.Ascent), 84 | CapHeight: fixed.I(f.Ascent), 85 | CaretSlope: image.Point{X: 0, Y: 1}, 86 | } 87 | } 88 | 89 | func (f *Face) Glyph(dot fixed.Point26_6, r rune) ( 90 | dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { 91 | 92 | if found, rng := f.find(r); rng != nil { 93 | maskp.Y = (int(found-rng.Low) + rng.Offset) * (f.Ascent + f.Descent) 94 | x := int(dot.X+32)>>6 + f.Left 95 | y := int(dot.Y+32) >> 6 96 | dr = image.Rectangle{ 97 | Min: image.Point{ 98 | X: x, 99 | Y: y - f.Ascent, 100 | }, 101 | Max: image.Point{ 102 | X: x + f.Width, 103 | Y: y + f.Descent, 104 | }, 105 | } 106 | 107 | return dr, f.Mask, maskp, fixed.I(f.Advance), r == found 108 | } 109 | return image.Rectangle{}, nil, image.Point{}, 0, false 110 | } 111 | 112 | func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { 113 | if found, rng := f.find(r); rng != nil { 114 | return fixed.R(0, -f.Ascent, f.Width, +f.Descent), fixed.I(f.Advance), r == found 115 | } 116 | return fixed.Rectangle26_6{}, 0, false 117 | } 118 | 119 | func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { 120 | if found, rng := f.find(r); rng != nil { 121 | return fixed.I(f.Advance), r == found 122 | } 123 | return 0, false 124 | } 125 | 126 | func (f *Face) find(r rune) (rune, *Range) { 127 | for { 128 | for i, rng := range f.Ranges { 129 | if (rng.Low <= r) && (r < rng.High) { 130 | return r, &f.Ranges[i] 131 | } 132 | } 133 | if r == '\ufffd' { 134 | return 0, nil 135 | } 136 | r = '\ufffd' 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /font/basicfont/basicfont_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package basicfont 6 | 7 | import ( 8 | "image" 9 | "testing" 10 | 11 | "golang.org/x/image/font" 12 | ) 13 | 14 | func TestMetrics(t *testing.T) { 15 | want := font.Metrics{Height: 832, Ascent: 704, Descent: 128, XHeight: 704, CapHeight: 704, CaretSlope: image.Point{X: 0, Y: 1}} 16 | if got := Face7x13.Metrics(); got != want { 17 | t.Errorf("Face7x13: Metrics: got %v want %v", got, want) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /font/basicfont/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build ignore 6 | 7 | // This program generates data.go. 8 | package main 9 | 10 | import ( 11 | "bytes" 12 | "fmt" 13 | "go/format" 14 | "image" 15 | "image/draw" 16 | "io/ioutil" 17 | "log" 18 | "path" 19 | "path/filepath" 20 | 21 | "golang.org/x/image/font" 22 | "golang.org/x/image/font/plan9font" 23 | "golang.org/x/image/math/fixed" 24 | ) 25 | 26 | func main() { 27 | // nGlyphs is the number of glyphs to generate: 95 characters in the range 28 | // [0x20, 0x7e], plus the replacement character. 29 | const nGlyphs = 95 + 1 30 | // The particular font (unicode.7x13.font) leaves the right-most column 31 | // empty in its ASCII glyphs. We don't have to include that column in the 32 | // generated glyphs, so we subtract one off the effective width. 33 | const width, height, ascent = 7 - 1, 13, 11 34 | 35 | readFile := func(name string) ([]byte, error) { 36 | return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name))) 37 | } 38 | fontData, err := readFile("unicode.7x13.font") 39 | if err != nil { 40 | log.Fatalf("readFile: %v", err) 41 | } 42 | face, err := plan9font.ParseFont(fontData, readFile) 43 | if err != nil { 44 | log.Fatalf("plan9font.ParseFont: %v", err) 45 | } 46 | 47 | dst := image.NewRGBA(image.Rect(0, 0, width, nGlyphs*height)) 48 | draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src) 49 | d := &font.Drawer{ 50 | Dst: dst, 51 | Src: image.White, 52 | Face: face, 53 | } 54 | for i := 0; i < nGlyphs; i++ { 55 | r := '\ufffd' 56 | if i < nGlyphs-1 { 57 | r = 0x20 + rune(i) 58 | } 59 | d.Dot = fixed.P(0, height*i+ascent) 60 | d.DrawString(string(r)) 61 | } 62 | 63 | w := bytes.NewBuffer(nil) 64 | w.WriteString(preamble) 65 | fmt.Fprintf(w, "// mask7x13 contains %d %d×%d glyphs in %d Pix bytes.\n", nGlyphs, width, height, nGlyphs*width*height) 66 | fmt.Fprintf(w, "var mask7x13 = &image.Alpha{\n") 67 | fmt.Fprintf(w, " Stride: %d,\n", width) 68 | fmt.Fprintf(w, " Rect: image.Rectangle{Max: image.Point{%d, %d*%d}},\n", width, nGlyphs, height) 69 | fmt.Fprintf(w, " Pix: []byte{\n") 70 | b := dst.Bounds() 71 | for y := b.Min.Y; y < b.Max.Y; y++ { 72 | if y%height == 0 { 73 | if y != 0 { 74 | w.WriteByte('\n') 75 | } 76 | i := y / height 77 | if i < nGlyphs-1 { 78 | i += 0x20 79 | fmt.Fprintf(w, "// %#2x %q\n", i, rune(i)) 80 | } else { 81 | fmt.Fprintf(w, "// U+FFFD REPLACEMENT CHARACTER\n") 82 | } 83 | } 84 | 85 | for x := b.Min.X; x < b.Max.X; x++ { 86 | if dst.RGBAAt(x, y).R > 0 { 87 | w.WriteString("0xff,") 88 | } else { 89 | w.WriteString("0x00,") 90 | } 91 | } 92 | w.WriteByte('\n') 93 | } 94 | w.WriteString("},\n}\n") 95 | 96 | fmted, err := format.Source(w.Bytes()) 97 | if err != nil { 98 | log.Fatalf("format.Source: %v", err) 99 | } 100 | if err := ioutil.WriteFile("data.go", fmted, 0644); err != nil { 101 | log.Fatalf("ioutil.WriteFile: %v", err) 102 | } 103 | } 104 | 105 | const preamble = `// generated by go generate; DO NOT EDIT. 106 | 107 | package basicfont 108 | 109 | // This data is derived from files in the font/fixed directory of the Plan 9 110 | // Port source code (https://github.com/9fans/plan9port) which were originally 111 | // based on the public domain X11 misc-fixed font files. 112 | 113 | import "image" 114 | 115 | ` 116 | -------------------------------------------------------------------------------- /font/font_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package font 6 | 7 | import ( 8 | "image" 9 | "strings" 10 | "testing" 11 | 12 | "golang.org/x/image/math/fixed" 13 | ) 14 | 15 | const toyAdvance = fixed.Int26_6(10 << 6) 16 | 17 | type toyFace struct{} 18 | 19 | func (toyFace) Close() error { 20 | return nil 21 | } 22 | 23 | func (toyFace) Glyph(dot fixed.Point26_6, r rune) (image.Rectangle, image.Image, image.Point, fixed.Int26_6, bool) { 24 | panic("unimplemented") 25 | } 26 | 27 | func (toyFace) GlyphBounds(r rune) (fixed.Rectangle26_6, fixed.Int26_6, bool) { 28 | return fixed.Rectangle26_6{ 29 | Min: fixed.P(2, 0), 30 | Max: fixed.P(6, 1), 31 | }, toyAdvance, true 32 | } 33 | 34 | func (toyFace) GlyphAdvance(r rune) (fixed.Int26_6, bool) { 35 | return toyAdvance, true 36 | } 37 | 38 | func (toyFace) Kern(r0, r1 rune) fixed.Int26_6 { 39 | return 0 40 | } 41 | 42 | func (toyFace) Metrics() Metrics { 43 | return Metrics{} 44 | } 45 | 46 | func TestBound(t *testing.T) { 47 | wantBounds := []fixed.Rectangle26_6{ 48 | {Min: fixed.P(0, 0), Max: fixed.P(0, 0)}, 49 | {Min: fixed.P(2, 0), Max: fixed.P(6, 1)}, 50 | {Min: fixed.P(2, 0), Max: fixed.P(16, 1)}, 51 | {Min: fixed.P(2, 0), Max: fixed.P(26, 1)}, 52 | } 53 | 54 | for i, wantBound := range wantBounds { 55 | s := strings.Repeat("x", i) 56 | gotBound, gotAdvance := BoundString(toyFace{}, s) 57 | if gotBound != wantBound { 58 | t.Errorf("i=%d: bound: got %v, want %v", i, gotBound, wantBound) 59 | } 60 | wantAdvance := toyAdvance * fixed.Int26_6(i) 61 | if gotAdvance != wantAdvance { 62 | t.Errorf("i=%d: advance: got %v, want %v", i, gotAdvance, wantAdvance) 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /font/gofont/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build ignore 6 | // +build ignore 7 | 8 | package main 9 | 10 | // This program generates the subdirectories of Go packages that contain []byte 11 | // versions of the TrueType font files under ./ttfs. 12 | // 13 | // Currently, "go run gen.go" needs to be run manually. This isn't done by the 14 | // usual "go generate" mechanism as there isn't any other Go code in this 15 | // directory (excluding sub-directories) to attach a "go:generate" line to. 16 | // 17 | // In any case, code generation should only need to happen when the underlying 18 | // TTF files change, which isn't expected to happen frequently. 19 | 20 | import ( 21 | "bytes" 22 | "fmt" 23 | "go/format" 24 | "io/ioutil" 25 | "log" 26 | "os" 27 | "path/filepath" 28 | "strings" 29 | ) 30 | 31 | const suffix = ".ttf" 32 | 33 | func main() { 34 | ttfs, err := os.Open("ttfs") 35 | if err != nil { 36 | log.Fatal(err) 37 | } 38 | defer ttfs.Close() 39 | 40 | infos, err := ttfs.Readdir(-1) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | for _, info := range infos { 45 | ttfName := info.Name() 46 | if !strings.HasSuffix(ttfName, suffix) { 47 | continue 48 | } 49 | do(ttfName) 50 | } 51 | } 52 | 53 | func do(ttfName string) { 54 | fontName := fontName(ttfName) 55 | pkgName := pkgName(ttfName) 56 | if err := os.Mkdir(pkgName, 0777); err != nil && !os.IsExist(err) { 57 | log.Fatal(err) 58 | } 59 | src, err := ioutil.ReadFile(filepath.Join("ttfs", ttfName)) 60 | if err != nil { 61 | log.Fatal(err) 62 | } 63 | 64 | desc := "a proportional-width, sans-serif" 65 | if strings.Contains(ttfName, "Mono") { 66 | desc = "a fixed-width, slab-serif" 67 | } 68 | 69 | b := new(bytes.Buffer) 70 | fmt.Fprintf(b, "// generated by go run gen.go; DO NOT EDIT\n\n") 71 | fmt.Fprintf(b, "// Package %s provides the %q TrueType font\n", pkgName, fontName) 72 | fmt.Fprintf(b, "// from the Go font family. It is %s font.\n", desc) 73 | fmt.Fprintf(b, "//\n") 74 | fmt.Fprintf(b, "// See https://blog.golang.org/go-fonts for details.\n") 75 | fmt.Fprintf(b, "package %s\n\n", pkgName) 76 | fmt.Fprintf(b, "// TTF is the data for the %q TrueType font.\n", fontName) 77 | fmt.Fprintf(b, "var TTF = []byte{") 78 | for i, x := range src { 79 | if i&15 == 0 { 80 | b.WriteByte('\n') 81 | } 82 | fmt.Fprintf(b, "%#02x,", x) 83 | } 84 | fmt.Fprintf(b, "\n}\n") 85 | 86 | dst, err := format.Source(b.Bytes()) 87 | if err != nil { 88 | log.Fatal(err) 89 | } 90 | if err := ioutil.WriteFile(filepath.Join(pkgName, "data.go"), dst, 0666); err != nil { 91 | log.Fatal(err) 92 | } 93 | } 94 | 95 | // fontName maps "Go-Regular.ttf" to "Go Regular". 96 | func fontName(ttfName string) string { 97 | s := ttfName[:len(ttfName)-len(suffix)] 98 | s = strings.Replace(s, "-", " ", -1) 99 | return s 100 | } 101 | 102 | // pkgName maps "Go-Regular.ttf" to "goregular". 103 | func pkgName(ttfName string) string { 104 | s := ttfName[:len(ttfName)-len(suffix)] 105 | s = strings.Replace(s, "-", "", -1) 106 | s = strings.ToLower(s) 107 | return s 108 | } 109 | -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Bold-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Bold-Italic.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Bold.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Italic.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Medium-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Medium-Italic.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Medium.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Mono-Bold-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Mono-Bold-Italic.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Mono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Mono-Bold.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Mono-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Mono-Italic.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Mono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Mono.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Regular.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Smallcaps-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Smallcaps-Italic.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/Go-Smallcaps.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/gofont/ttfs/Go-Smallcaps.ttf -------------------------------------------------------------------------------- /font/gofont/ttfs/README: -------------------------------------------------------------------------------- 1 | These fonts were created by the Bigelow & Holmes foundry specifically for the 2 | Go project. See https://blog.golang.org/go-fonts for details. 3 | 4 | They are licensed under the same open source license as the rest of the Go 5 | project's software: 6 | 7 | Copyright (c) 2016 Bigelow & Holmes Inc.. All rights reserved. 8 | 9 | Distribution of this font is governed by the following license. If you do not 10 | agree to this license, including the disclaimer, do not distribute or modify 11 | this font. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | * Redistributions of source code must retain the above copyright notice, 17 | this list of conditions and the following disclaimer. 18 | 19 | * Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | * Neither the name of Google Inc. nor the names of its contributors may be 24 | used to endorse or promote products derived from this software without 25 | specific prior written permission. 26 | 27 | DISCLAIMER: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 29 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | -------------------------------------------------------------------------------- /font/inconsolata/inconsolata.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:generate genbasicfont -size=16 -pkg=inconsolata -hinting=full -var=regular8x16 -fontfile=http://www.levien.com/type/myfonts/inconsolata/InconsolataGo-Regular.ttf 6 | //go:generate genbasicfont -size=16 -pkg=inconsolata -hinting=full -var=bold8x16 -fontfile=http://www.levien.com/type/myfonts/inconsolata/InconsolataGo-Bold.ttf 7 | 8 | // The genbasicfont program is github.com/golang/freetype/example/genbasicfont 9 | 10 | // Package inconsolata provides pre-rendered bitmap versions of the Inconsolata 11 | // font family. 12 | // 13 | // Inconsolata is copyright Raph Levien and Cyreal. This package is licensed 14 | // under Go's BSD-style license (https://golang.org/LICENSE) with their 15 | // permission. 16 | // 17 | // Inconsolata's home page is at 18 | // http://www.levien.com/type/myfonts/inconsolata.html 19 | package inconsolata // import "golang.org/x/image/font/inconsolata" 20 | 21 | import ( 22 | "golang.org/x/image/font/basicfont" 23 | ) 24 | 25 | // Regular8x16 is a regular weight, 8x16 font face. 26 | var Regular8x16 *basicfont.Face = ®ular8x16 27 | 28 | // Bold8x16 is a bold weight, 8x16 font face. 29 | var Bold8x16 *basicfont.Face = &bold8x16 30 | -------------------------------------------------------------------------------- /font/opentype/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package opentype_test 6 | 7 | import ( 8 | "fmt" 9 | "image" 10 | "image/color" 11 | "log" 12 | "os" 13 | 14 | "golang.org/x/image/font" 15 | "golang.org/x/image/font/gofont/goitalic" 16 | "golang.org/x/image/font/opentype" 17 | "golang.org/x/image/math/fixed" 18 | ) 19 | 20 | func ExampleNewFace() { 21 | const ( 22 | width = 72 23 | height = 36 24 | startingDotX = 6 25 | startingDotY = 28 26 | ) 27 | 28 | f, err := opentype.Parse(goitalic.TTF) 29 | if err != nil { 30 | log.Fatalf("Parse: %v", err) 31 | } 32 | face, err := opentype.NewFace(f, &opentype.FaceOptions{ 33 | Size: 32, 34 | DPI: 72, 35 | Hinting: font.HintingNone, 36 | }) 37 | if err != nil { 38 | log.Fatalf("NewFace: %v", err) 39 | } 40 | 41 | dst := image.NewGray(image.Rect(0, 0, width, height)) 42 | d := font.Drawer{ 43 | Dst: dst, 44 | Src: image.White, 45 | Face: face, 46 | Dot: fixed.P(startingDotX, startingDotY), 47 | } 48 | fmt.Printf("The dot is at %v\n", d.Dot) 49 | d.DrawString("jel") 50 | fmt.Printf("The dot is at %v\n", d.Dot) 51 | d.Src = image.NewUniform(color.Gray{0x7F}) 52 | d.DrawString("ly") 53 | fmt.Printf("The dot is at %v\n", d.Dot) 54 | 55 | const asciiArt = ".++8" 56 | buf := make([]byte, 0, height*(width+1)) 57 | for y := 0; y < height; y++ { 58 | for x := 0; x < width; x++ { 59 | c := asciiArt[dst.GrayAt(x, y).Y>>6] 60 | if c != '.' { 61 | // No-op. 62 | } else if x == startingDotX-1 { 63 | c = ']' 64 | } else if y == startingDotY-1 { 65 | c = '_' 66 | } 67 | buf = append(buf, c) 68 | } 69 | buf = append(buf, '\n') 70 | } 71 | os.Stdout.Write(buf) 72 | 73 | // Output: 74 | // The dot is at {6:00 28:00} 75 | // The dot is at {41:32 28:00} 76 | // The dot is at {66:48 28:00} 77 | // .....].................................................................. 78 | // .....].................................................................. 79 | // .....].................................................................. 80 | // .....]..................................+++......+++.................... 81 | // .....]........+++.......................888......+++.................... 82 | // .....].......+88+......................+88+......+++.................... 83 | // .....].......888+......................+88+.....+++..................... 84 | // .....].......888+......................+88+.....+++..................... 85 | // .....].................................888......+++..................... 86 | // .....].................................888......+++..................... 87 | // .....]....................++..........+88+......+++..................... 88 | // .....]......+88+.......+888888+.......+88+.....+++....+++..........++... 89 | // .....]......888......+888888888+......+88+.....+++....++++........+++... 90 | // .....]......888.....+888+...+888......888......+++.....+++........++.... 91 | // .....].....+888....+888......+88+.....888......+++.....+++.......+++.... 92 | // .....].....+88+....888.......+88+....+88+......+++.....+++......+++..... 93 | // .....].....+88+...+888.......+88+....+88+.....+++......+++......+++..... 94 | // .....].....888....888+++++++++88+....+88+.....+++......+++.....+++...... 95 | // .....].....888....88888888888888+....888......+++......++++....++....... 96 | // .....]....+888...+88888888888888.....888......+++.......+++...+++....... 97 | // .....]....+88+...+888...............+888......+++.......+++..+++........ 98 | // .....]....+88+...+888...............+88+.....+++........+++..+++........ 99 | // .....]....888....+888...............+88+.....+++........+++.+++......... 100 | // .....]....888....+888...............888......+++........++++++.......... 101 | // .....]...+888.....888+..............888......+++........++++++.......... 102 | // .....]...+88+.....+8888+....++8.....888+.....++++........++++........... 103 | // .....]...+88+......+8888888888+.....+8888....+++++.......++++........... 104 | // _____]___888________+88888888++______+888_____++++_______+++____________ 105 | // .....]...888...........+++.............++................+++............ 106 | // .....]..+88+............................................+++............. 107 | // .....]..+88+...........................................+++.............. 108 | // .....].+888............................................+++.............. 109 | // ....888888............................................+++............... 110 | // ....88888............................................++++............... 111 | // ....+++................................................................. 112 | // .....].................................................................. 113 | } 114 | -------------------------------------------------------------------------------- /font/opentype/opentype_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package opentype 6 | 7 | import ( 8 | "image" 9 | "testing" 10 | 11 | "golang.org/x/image/font" 12 | "golang.org/x/image/font/gofont/goregular" 13 | "golang.org/x/image/font/sfnt" 14 | "golang.org/x/image/math/fixed" 15 | ) 16 | 17 | var ( 18 | regular font.Face 19 | ) 20 | 21 | func init() { 22 | font, err := sfnt.Parse(goregular.TTF) 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | regular, err = NewFace(font, defaultFaceOptions()) 28 | if err != nil { 29 | panic(err) 30 | } 31 | } 32 | 33 | var runeTests = []struct { 34 | r rune 35 | advance fixed.Int26_6 36 | dr image.Rectangle 37 | }{ 38 | {' ', 213, image.Rect(0, 0, 0, 0)}, 39 | {'A', 512, image.Rect(0, -9, 8, 0)}, 40 | {'Á', 512, image.Rect(0, -12, 8, 0)}, 41 | {'Æ', 768, image.Rect(0, -9, 12, 0)}, 42 | {'i', 189, image.Rect(0, -9, 3, 0)}, 43 | {'x', 384, image.Rect(0, -7, 6, 0)}, 44 | } 45 | 46 | func TestFaceGlyphAdvance(t *testing.T) { 47 | for _, test := range runeTests { 48 | got, ok := regular.GlyphAdvance(test.r) 49 | if !ok { 50 | t.Errorf("could not get glyph advance width for %q", test.r) 51 | continue 52 | } 53 | 54 | if got != test.advance { 55 | t.Errorf("%q: glyph advance width=%d. want=%d", test.r, got, test.advance) 56 | continue 57 | } 58 | } 59 | } 60 | 61 | func TestFaceGlyphBounds(t *testing.T) { 62 | for _, test := range runeTests { 63 | bounds, advance, ok := regular.GlyphBounds(test.r) 64 | if !ok { 65 | t.Errorf("could not get glyph bounds for %q", test.r) 66 | continue 67 | } 68 | 69 | // bounds must fit inside the draw rect. 70 | testFixedBounds := fixed.R(test.dr.Min.X, test.dr.Min.Y, 71 | test.dr.Max.X, test.dr.Max.Y) 72 | if !bounds.In(testFixedBounds) { 73 | t.Errorf("%q: glyph bounds %v must be inside %v", test.r, bounds, testFixedBounds) 74 | continue 75 | } 76 | if advance != test.advance { 77 | t.Errorf("%q: glyph advance width=%d. want=%d", test.r, advance, test.advance) 78 | continue 79 | } 80 | } 81 | } 82 | 83 | func TestFaceGlyph(t *testing.T) { 84 | dot := image.Pt(200, 500) 85 | fixedDot := fixed.P(dot.X, dot.Y) 86 | 87 | for _, test := range runeTests { 88 | dr, mask, maskp, advance, ok := regular.Glyph(fixedDot, test.r) 89 | if !ok { 90 | t.Errorf("could not get glyph for %q", test.r) 91 | continue 92 | } 93 | if got, want := dr, test.dr.Add(dot); got != want { 94 | t.Errorf("%q: glyph draw rectangle=%d. want=%d", test.r, got, want) 95 | continue 96 | } 97 | if got, want := mask.Bounds(), image.Rect(0, 0, dr.Dx(), dr.Dy()); got != want { 98 | t.Errorf("%q: glyph mask rectangle=%d. want=%d", test.r, got, want) 99 | continue 100 | } 101 | if maskp != (image.Point{}) { 102 | t.Errorf("%q: glyph maskp=%d. want=%d", test.r, maskp, image.Point{}) 103 | continue 104 | } 105 | if advance != test.advance { 106 | t.Errorf("%q: glyph advance width=%d. want=%d", test.r, advance, test.advance) 107 | continue 108 | } 109 | } 110 | } 111 | 112 | func BenchmarkFaceGlyph(b *testing.B) { 113 | fixedDot := fixed.P(200, 500) 114 | r := 'A' 115 | 116 | b.ReportAllocs() 117 | b.ResetTimer() 118 | for i := 0; i < b.N; i++ { 119 | _, _, _, _, ok := regular.Glyph(fixedDot, r) 120 | if !ok { 121 | b.Fatalf("could not get glyph for %q", r) 122 | } 123 | } 124 | } 125 | 126 | func TestFaceKern(t *testing.T) { 127 | // FIXME(sbinet) there is no kerning with gofont/goregular 128 | for _, test := range []struct { 129 | r1, r2 rune 130 | want fixed.Int26_6 131 | }{ 132 | {'A', 'A', 0}, 133 | {'A', 'V', 0}, 134 | {'V', 'A', 0}, 135 | {'A', 'v', 0}, 136 | {'W', 'a', 0}, 137 | {'W', 'i', 0}, 138 | {'Y', 'i', 0}, 139 | {'f', '(', 0}, 140 | {'f', 'f', 0}, 141 | {'f', 'i', 0}, 142 | {'T', 'a', 0}, 143 | {'T', 'e', 0}, 144 | } { 145 | got := regular.Kern(test.r1, test.r2) 146 | if got != test.want { 147 | t.Errorf("(%q, %q): glyph kerning=%d. want=%d", test.r1, test.r2, got, test.want) 148 | continue 149 | } 150 | } 151 | } 152 | 153 | func TestFaceMetrics(t *testing.T) { 154 | want := font.Metrics{Height: 888, Ascent: 726, Descent: 162, XHeight: 407, CapHeight: 555, 155 | CaretSlope: image.Point{X: 0, Y: 1}} 156 | got := regular.Metrics() 157 | if got != want { 158 | t.Fatalf("metrics failed. got=%#v. want=%#v", got, want) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /font/plan9font/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package plan9font_test 6 | 7 | import ( 8 | "image" 9 | "image/draw" 10 | "io/ioutil" 11 | "log" 12 | "os" 13 | "path" 14 | "path/filepath" 15 | 16 | "golang.org/x/image/font" 17 | "golang.org/x/image/font/plan9font" 18 | "golang.org/x/image/math/fixed" 19 | ) 20 | 21 | func ExampleParseFont() { 22 | readFile := func(name string) ([]byte, error) { 23 | return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name))) 24 | } 25 | fontData, err := readFile("unicode.7x13.font") 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | face, err := plan9font.ParseFont(fontData, readFile) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | ascent := face.Metrics().Ascent.Ceil() 34 | 35 | dst := image.NewRGBA(image.Rect(0, 0, 4*7, 13)) 36 | draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src) 37 | d := &font.Drawer{ 38 | Dst: dst, 39 | Src: image.White, 40 | Face: face, 41 | Dot: fixed.P(0, ascent), 42 | } 43 | // Draw: 44 | // - U+0053 LATIN CAPITAL LETTER S 45 | // - U+03A3 GREEK CAPITAL LETTER SIGMA 46 | // - U+222B INTEGRAL 47 | // - U+3055 HIRAGANA LETTER SA 48 | // The testdata does not contain the CJK subfont files, so U+3055 HIRAGANA 49 | // LETTER SA (さ) should be rendered as U+FFFD REPLACEMENT CHARACTER (�). 50 | // 51 | // The missing subfont file will trigger an "open 52 | // ../testdata/shinonome/k12.3000: no such file or directory" log message. 53 | // This is expected and can be ignored. 54 | d.DrawString("SΣ∫さ") 55 | 56 | // Convert the dst image to ASCII art. 57 | var out []byte 58 | b := dst.Bounds() 59 | for y := b.Min.Y; y < b.Max.Y; y++ { 60 | out = append(out, '0'+byte(y%10), ' ') 61 | for x := b.Min.X; x < b.Max.X; x++ { 62 | if dst.RGBAAt(x, y).R > 0 { 63 | out = append(out, 'X') 64 | } else { 65 | out = append(out, '.') 66 | } 67 | } 68 | // Highlight the last row before the baseline. Glyphs like 'S' without 69 | // descenders should not affect any pixels whose Y coordinate is >= the 70 | // baseline. 71 | if y == ascent-1 { 72 | out = append(out, '_') 73 | } 74 | out = append(out, '\n') 75 | } 76 | os.Stdout.Write(out) 77 | 78 | // Output: 79 | // 0 ..................X......... 80 | // 1 .................X.X........ 81 | // 2 .XXXX..XXXXXX....X.....XXX.. 82 | // 3 X....X.X.........X....XX.XX. 83 | // 4 X.......X........X....X.X.X. 84 | // 5 X........X.......X....XXX.X. 85 | // 6 .XXXX.....X......X....XX.XX. 86 | // 7 .....X...X.......X....XX.XX. 87 | // 8 .....X..X........X....XXXXX. 88 | // 9 X....X.X.........X....XX.XX. 89 | // 0 .XXXX..XXXXXX....X.....XXX.._ 90 | // 1 ...............X.X.......... 91 | // 2 ................X........... 92 | } 93 | -------------------------------------------------------------------------------- /font/plan9font/plan9font_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package plan9font 6 | 7 | import ( 8 | "image" 9 | "io/ioutil" 10 | "path" 11 | "path/filepath" 12 | "testing" 13 | 14 | "golang.org/x/image/font" 15 | ) 16 | 17 | func TestMetrics(t *testing.T) { 18 | readFile := func(name string) ([]byte, error) { 19 | return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name))) 20 | } 21 | data, err := readFile("unicode.7x13.font") 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | face, err := ParseFont(data, readFile) 26 | if err != nil { 27 | t.Fatal(err) 28 | } 29 | want := font.Metrics{Height: 832, Ascent: 704, Descent: 128, XHeight: 704, CapHeight: 704, 30 | CaretSlope: image.Point{X: 0, Y: 1}} 31 | if got := face.Metrics(); got != want { 32 | t.Errorf("unicode.7x13.font: Metrics: got %v, want %v", got, want) 33 | } 34 | subData, err := readFile("7x13.0000") 35 | if err != nil { 36 | t.Fatal(err) 37 | } 38 | subFace, err := ParseSubfont(subData, 0) 39 | if err != nil { 40 | t.Fatal(err) 41 | } 42 | if got := subFace.Metrics(); got != want { 43 | t.Errorf("7x13.0000: Metrics: got %v, want %v", got, want) 44 | } 45 | } 46 | 47 | func BenchmarkParseSubfont(b *testing.B) { 48 | subfontData, err := ioutil.ReadFile(filepath.FromSlash("../testdata/fixed/7x13.0000")) 49 | if err != nil { 50 | b.Fatal(err) 51 | } 52 | b.ResetTimer() 53 | for i := 0; i < b.N; i++ { 54 | if _, err := ParseSubfont(subfontData, 0); err != nil { 55 | b.Fatal(err) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /font/sfnt/data.go: -------------------------------------------------------------------------------- 1 | // generated by go run gen.go; DO NOT EDIT 2 | 3 | package sfnt 4 | 5 | const numBuiltInPostNames = 258 6 | 7 | const builtInPostNamesData = "" + 8 | ".notdef.nullnonmarkingreturnspaceexclamquotedblnumbersigndollarp" + 9 | "ercentampersandquotesingleparenleftparenrightasteriskpluscommahy" + 10 | "phenperiodslashzeroonetwothreefourfivesixseveneightninecolonsemi" + 11 | "colonlessequalgreaterquestionatABCDEFGHIJKLMNOPQRSTUVWXYZbracket" + 12 | "leftbackslashbracketrightasciicircumunderscoregraveabcdefghijklm" + 13 | "nopqrstuvwxyzbraceleftbarbracerightasciitildeAdieresisAringCcedi" + 14 | "llaEacuteNtildeOdieresisUdieresisaacuteagraveacircumflexadieresi" + 15 | "satildearingccedillaeacuteegraveecircumflexedieresisiacuteigrave" + 16 | "icircumflexidieresisntildeoacuteograveocircumflexodieresisotilde" + 17 | "uacuteugraveucircumflexudieresisdaggerdegreecentsterlingsectionb" + 18 | "ulletparagraphgermandblsregisteredcopyrighttrademarkacutedieresi" + 19 | "snotequalAEOslashinfinityplusminuslessequalgreaterequalyenmupart" + 20 | "ialdiffsummationproductpiintegralordfeminineordmasculineOmegaaeo" + 21 | "slashquestiondownexclamdownlogicalnotradicalflorinapproxequalDel" + 22 | "taguillemotleftguillemotrightellipsisnonbreakingspaceAgraveAtild" + 23 | "eOtildeOEoeendashemdashquotedblleftquotedblrightquoteleftquoteri" + 24 | "ghtdividelozengeydieresisYdieresisfractioncurrencyguilsinglleftg" + 25 | "uilsinglrightfifldaggerdblperiodcenteredquotesinglbasequotedblba" + 26 | "seperthousandAcircumflexEcircumflexAacuteEdieresisEgraveIacuteIc" + 27 | "ircumflexIdieresisIgraveOacuteOcircumflexappleOgraveUacuteUcircu" + 28 | "mflexUgravedotlessicircumflextildemacronbrevedotaccentringcedill" + 29 | "ahungarumlautogonekcaronLslashlslashScaronscaronZcaronzcaronbrok" + 30 | "enbarEthethYacuteyacuteThornthornminusmultiplyonesuperiortwosupe" + 31 | "riorthreesuperioronehalfonequarterthreequartersfrancGbrevegbreve" + 32 | "IdotaccentScedillascedillaCacutecacuteCcaronccarondcroat" 33 | 34 | var builtInPostNamesOffsets = [...]uint16{ 35 | 0x0000, 0x0007, 0x000c, 0x001c, 0x0021, 0x0027, 0x002f, 0x0039, 36 | 0x003f, 0x0046, 0x004f, 0x005a, 0x0063, 0x006d, 0x0075, 0x0079, 37 | 0x007e, 0x0084, 0x008a, 0x008f, 0x0093, 0x0096, 0x0099, 0x009e, 38 | 0x00a2, 0x00a6, 0x00a9, 0x00ae, 0x00b3, 0x00b7, 0x00bc, 0x00c5, 39 | 0x00c9, 0x00ce, 0x00d5, 0x00dd, 0x00df, 0x00e0, 0x00e1, 0x00e2, 40 | 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 41 | 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 42 | 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x0104, 43 | 0x010d, 0x0119, 0x0124, 0x012e, 0x0133, 0x0134, 0x0135, 0x0136, 44 | 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e, 45 | 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 46 | 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d, 0x0156, 47 | 0x0159, 0x0163, 0x016d, 0x0176, 0x017b, 0x0183, 0x0189, 0x018f, 48 | 0x0198, 0x01a1, 0x01a7, 0x01ad, 0x01b8, 0x01c1, 0x01c7, 0x01cc, 49 | 0x01d4, 0x01da, 0x01e0, 0x01eb, 0x01f4, 0x01fa, 0x0200, 0x020b, 50 | 0x0214, 0x021a, 0x0220, 0x0226, 0x0231, 0x023a, 0x0240, 0x0246, 51 | 0x024c, 0x0257, 0x0260, 0x0266, 0x026c, 0x0270, 0x0278, 0x027f, 52 | 0x0285, 0x028e, 0x0298, 0x02a2, 0x02ab, 0x02b4, 0x02b9, 0x02c1, 53 | 0x02c9, 0x02cb, 0x02d1, 0x02d9, 0x02e2, 0x02eb, 0x02f7, 0x02fa, 54 | 0x02fc, 0x0307, 0x0310, 0x0317, 0x0319, 0x0321, 0x032c, 0x0338, 55 | 0x033d, 0x033f, 0x0345, 0x0351, 0x035b, 0x0365, 0x036c, 0x0372, 56 | 0x037d, 0x0382, 0x038f, 0x039d, 0x03a5, 0x03b5, 0x03bb, 0x03c1, 57 | 0x03c7, 0x03c9, 0x03cb, 0x03d1, 0x03d7, 0x03e3, 0x03f0, 0x03f9, 58 | 0x0403, 0x0409, 0x0410, 0x0419, 0x0422, 0x042a, 0x0432, 0x043f, 59 | 0x044d, 0x044f, 0x0451, 0x045a, 0x0468, 0x0476, 0x0482, 0x048d, 60 | 0x0498, 0x04a3, 0x04a9, 0x04b2, 0x04b8, 0x04be, 0x04c9, 0x04d2, 61 | 0x04d8, 0x04de, 0x04e9, 0x04ee, 0x04f4, 0x04fa, 0x0505, 0x050b, 62 | 0x0513, 0x051d, 0x0522, 0x0528, 0x052d, 0x0536, 0x053a, 0x0541, 63 | 0x054d, 0x0553, 0x0558, 0x055e, 0x0564, 0x056a, 0x0570, 0x0576, 64 | 0x057c, 0x0585, 0x0588, 0x058b, 0x0591, 0x0597, 0x059c, 0x05a1, 65 | 0x05a6, 0x05ae, 0x05b9, 0x05c4, 0x05d1, 0x05d8, 0x05e2, 0x05ef, 66 | 0x05f4, 0x05fa, 0x0600, 0x060a, 0x0612, 0x061a, 0x0620, 0x0626, 67 | 0x062c, 0x0632, 0x0638, 68 | } 69 | -------------------------------------------------------------------------------- /font/sfnt/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sfnt_test 6 | 7 | import ( 8 | "image" 9 | "image/draw" 10 | "log" 11 | "os" 12 | 13 | "golang.org/x/image/font/gofont/goregular" 14 | "golang.org/x/image/font/sfnt" 15 | "golang.org/x/image/math/fixed" 16 | "golang.org/x/image/vector" 17 | ) 18 | 19 | func Example_rasterizeGlyph() { 20 | const ( 21 | ppem = 32 22 | width = 24 23 | height = 36 24 | originX = 0 25 | originY = 32 26 | ) 27 | 28 | // Load the 'G' glyph from the Go Regular font. 29 | f, err := sfnt.Parse(goregular.TTF) 30 | if err != nil { 31 | log.Fatalf("Parse: %v", err) 32 | } 33 | var b sfnt.Buffer 34 | x, err := f.GlyphIndex(&b, 'Ġ') 35 | if err != nil { 36 | log.Fatalf("GlyphIndex: %v", err) 37 | } 38 | if x == 0 { 39 | log.Fatalf("GlyphIndex: no glyph index found for the rune 'Ġ'") 40 | } 41 | segments, err := f.LoadGlyph(&b, x, fixed.I(ppem), nil) 42 | if err != nil { 43 | log.Fatalf("LoadGlyph: %v", err) 44 | } 45 | 46 | // Translate and scale that glyph as we pass it to a vector.Rasterizer. 47 | r := vector.NewRasterizer(width, height) 48 | r.DrawOp = draw.Src 49 | for _, seg := range segments { 50 | // The divisions by 64 below is because the seg.Args values have type 51 | // fixed.Int26_6, a 26.6 fixed point number, and 1<<6 == 64. 52 | switch seg.Op { 53 | case sfnt.SegmentOpMoveTo: 54 | r.MoveTo( 55 | originX+float32(seg.Args[0].X)/64, 56 | originY+float32(seg.Args[0].Y)/64, 57 | ) 58 | case sfnt.SegmentOpLineTo: 59 | r.LineTo( 60 | originX+float32(seg.Args[0].X)/64, 61 | originY+float32(seg.Args[0].Y)/64, 62 | ) 63 | case sfnt.SegmentOpQuadTo: 64 | r.QuadTo( 65 | originX+float32(seg.Args[0].X)/64, 66 | originY+float32(seg.Args[0].Y)/64, 67 | originX+float32(seg.Args[1].X)/64, 68 | originY+float32(seg.Args[1].Y)/64, 69 | ) 70 | case sfnt.SegmentOpCubeTo: 71 | r.CubeTo( 72 | originX+float32(seg.Args[0].X)/64, 73 | originY+float32(seg.Args[0].Y)/64, 74 | originX+float32(seg.Args[1].X)/64, 75 | originY+float32(seg.Args[1].Y)/64, 76 | originX+float32(seg.Args[2].X)/64, 77 | originY+float32(seg.Args[2].Y)/64, 78 | ) 79 | } 80 | } 81 | 82 | // Finish the rasterization: the conversion from vector graphics (shapes) 83 | // to raster graphics (pixels). 84 | dst := image.NewAlpha(image.Rect(0, 0, width, height)) 85 | r.Draw(dst, dst.Bounds(), image.Opaque, image.Point{}) 86 | 87 | // Visualize the pixels. 88 | const asciiArt = ".++8" 89 | buf := make([]byte, 0, height*(width+1)) 90 | for y := 0; y < height; y++ { 91 | for x := 0; x < width; x++ { 92 | a := dst.AlphaAt(x, y).A 93 | buf = append(buf, asciiArt[a>>6]) 94 | } 95 | buf = append(buf, '\n') 96 | } 97 | os.Stdout.Write(buf) 98 | 99 | // Output: 100 | // ........................ 101 | // ........................ 102 | // ........................ 103 | // ............888......... 104 | // ............888......... 105 | // ............888......... 106 | // ............+++......... 107 | // ........................ 108 | // ..........+++++++++..... 109 | // .......+8888888888888+.. 110 | // ......8888888888888888.. 111 | // ....+8888+........++88.. 112 | // ....8888................ 113 | // ...8888................. 114 | // ..+888+................. 115 | // ..+888.................. 116 | // ..888+.................. 117 | // .+888+.................. 118 | // .+888................... 119 | // .+888................... 120 | // .+888................... 121 | // .+888..........+++++++.. 122 | // .+888..........8888888.. 123 | // .+888+.........+++8888.. 124 | // ..888+............+888.. 125 | // ..8888............+888.. 126 | // ..+888+...........+888.. 127 | // ...8888+..........+888.. 128 | // ...+8888+.........+888.. 129 | // ....+88888+.......+888.. 130 | // .....+8888888888888888.. 131 | // .......+888888888888++.. 132 | // ..........++++++++...... 133 | // ........................ 134 | // ........................ 135 | // ........................ 136 | } 137 | -------------------------------------------------------------------------------- /font/sfnt/gen.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build ignore 6 | 7 | package main 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "go/format" 13 | "io/ioutil" 14 | "log" 15 | ) 16 | 17 | func main() { 18 | data, offsets := []byte(nil), []int{0} 19 | for _, name := range names { 20 | data = append(data, name...) 21 | offsets = append(offsets, len(data)) 22 | } 23 | 24 | b := new(bytes.Buffer) 25 | fmt.Fprintf(b, "// generated by go run gen.go; DO NOT EDIT\n\n") 26 | fmt.Fprintf(b, "package sfnt\n\n") 27 | 28 | fmt.Fprintf(b, "const numBuiltInPostNames = %d\n\n", len(names)) 29 | 30 | fmt.Fprintf(b, "const builtInPostNamesData = \"\" +\n") 31 | for s := data; ; { 32 | if len(s) <= 64 { 33 | fmt.Fprintf(b, "%q\n", s) 34 | break 35 | } 36 | fmt.Fprintf(b, "%q +\n", s[:64]) 37 | s = s[64:] 38 | } 39 | fmt.Fprintf(b, "\n") 40 | 41 | fmt.Fprintf(b, "var builtInPostNamesOffsets = [...]uint16{\n") 42 | for i, o := range offsets { 43 | fmt.Fprintf(b, "%#04x,", o) 44 | if i%8 == 7 { 45 | fmt.Fprintf(b, "\n") 46 | } 47 | } 48 | fmt.Fprintf(b, "\n}\n") 49 | 50 | dstUnformatted := b.Bytes() 51 | dst, err := format.Source(dstUnformatted) 52 | if err != nil { 53 | log.Fatalf("format.Source: %v\n\n----\n%s\n----", err, dstUnformatted) 54 | } 55 | if err := ioutil.WriteFile("data.go", dst, 0666); err != nil { 56 | log.Fatalf("ioutil.WriteFile: %v", err) 57 | } 58 | } 59 | 60 | // names is the built-in post table names listed at 61 | // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html 62 | var names = [258]string{ 63 | ".notdef", 64 | ".null", 65 | "nonmarkingreturn", 66 | "space", 67 | "exclam", 68 | "quotedbl", 69 | "numbersign", 70 | "dollar", 71 | "percent", 72 | "ampersand", 73 | "quotesingle", 74 | "parenleft", 75 | "parenright", 76 | "asterisk", 77 | "plus", 78 | "comma", 79 | "hyphen", 80 | "period", 81 | "slash", 82 | "zero", 83 | "one", 84 | "two", 85 | "three", 86 | "four", 87 | "five", 88 | "six", 89 | "seven", 90 | "eight", 91 | "nine", 92 | "colon", 93 | "semicolon", 94 | "less", 95 | "equal", 96 | "greater", 97 | "question", 98 | "at", 99 | "A", 100 | "B", 101 | "C", 102 | "D", 103 | "E", 104 | "F", 105 | "G", 106 | "H", 107 | "I", 108 | "J", 109 | "K", 110 | "L", 111 | "M", 112 | "N", 113 | "O", 114 | "P", 115 | "Q", 116 | "R", 117 | "S", 118 | "T", 119 | "U", 120 | "V", 121 | "W", 122 | "X", 123 | "Y", 124 | "Z", 125 | "bracketleft", 126 | "backslash", 127 | "bracketright", 128 | "asciicircum", 129 | "underscore", 130 | "grave", 131 | "a", 132 | "b", 133 | "c", 134 | "d", 135 | "e", 136 | "f", 137 | "g", 138 | "h", 139 | "i", 140 | "j", 141 | "k", 142 | "l", 143 | "m", 144 | "n", 145 | "o", 146 | "p", 147 | "q", 148 | "r", 149 | "s", 150 | "t", 151 | "u", 152 | "v", 153 | "w", 154 | "x", 155 | "y", 156 | "z", 157 | "braceleft", 158 | "bar", 159 | "braceright", 160 | "asciitilde", 161 | "Adieresis", 162 | "Aring", 163 | "Ccedilla", 164 | "Eacute", 165 | "Ntilde", 166 | "Odieresis", 167 | "Udieresis", 168 | "aacute", 169 | "agrave", 170 | "acircumflex", 171 | "adieresis", 172 | "atilde", 173 | "aring", 174 | "ccedilla", 175 | "eacute", 176 | "egrave", 177 | "ecircumflex", 178 | "edieresis", 179 | "iacute", 180 | "igrave", 181 | "icircumflex", 182 | "idieresis", 183 | "ntilde", 184 | "oacute", 185 | "ograve", 186 | "ocircumflex", 187 | "odieresis", 188 | "otilde", 189 | "uacute", 190 | "ugrave", 191 | "ucircumflex", 192 | "udieresis", 193 | "dagger", 194 | "degree", 195 | "cent", 196 | "sterling", 197 | "section", 198 | "bullet", 199 | "paragraph", 200 | "germandbls", 201 | "registered", 202 | "copyright", 203 | "trademark", 204 | "acute", 205 | "dieresis", 206 | "notequal", 207 | "AE", 208 | "Oslash", 209 | "infinity", 210 | "plusminus", 211 | "lessequal", 212 | "greaterequal", 213 | "yen", 214 | "mu", 215 | "partialdiff", 216 | "summation", 217 | "product", 218 | "pi", 219 | "integral", 220 | "ordfeminine", 221 | "ordmasculine", 222 | "Omega", 223 | "ae", 224 | "oslash", 225 | "questiondown", 226 | "exclamdown", 227 | "logicalnot", 228 | "radical", 229 | "florin", 230 | "approxequal", 231 | "Delta", 232 | "guillemotleft", 233 | "guillemotright", 234 | "ellipsis", 235 | "nonbreakingspace", 236 | "Agrave", 237 | "Atilde", 238 | "Otilde", 239 | "OE", 240 | "oe", 241 | "endash", 242 | "emdash", 243 | "quotedblleft", 244 | "quotedblright", 245 | "quoteleft", 246 | "quoteright", 247 | "divide", 248 | "lozenge", 249 | "ydieresis", 250 | "Ydieresis", 251 | "fraction", 252 | "currency", 253 | "guilsinglleft", 254 | "guilsinglright", 255 | "fi", 256 | "fl", 257 | "daggerdbl", 258 | "periodcentered", 259 | "quotesinglbase", 260 | "quotedblbase", 261 | "perthousand", 262 | "Acircumflex", 263 | "Ecircumflex", 264 | "Aacute", 265 | "Edieresis", 266 | "Egrave", 267 | "Iacute", 268 | "Icircumflex", 269 | "Idieresis", 270 | "Igrave", 271 | "Oacute", 272 | "Ocircumflex", 273 | "apple", 274 | "Ograve", 275 | "Uacute", 276 | "Ucircumflex", 277 | "Ugrave", 278 | "dotlessi", 279 | "circumflex", 280 | "tilde", 281 | "macron", 282 | "breve", 283 | "dotaccent", 284 | "ring", 285 | "cedilla", 286 | "hungarumlaut", 287 | "ogonek", 288 | "caron", 289 | "Lslash", 290 | "lslash", 291 | "Scaron", 292 | "scaron", 293 | "Zcaron", 294 | "zcaron", 295 | "brokenbar", 296 | "Eth", 297 | "eth", 298 | "Yacute", 299 | "yacute", 300 | "Thorn", 301 | "thorn", 302 | "minus", 303 | "multiply", 304 | "onesuperior", 305 | "twosuperior", 306 | "threesuperior", 307 | "onehalf", 308 | "onequarter", 309 | "threequarters", 310 | "franc", 311 | "Gbreve", 312 | "gbreve", 313 | "Idotaccent", 314 | "Scedilla", 315 | "scedilla", 316 | "Cacute", 317 | "cacute", 318 | "Ccaron", 319 | "ccaron", 320 | "dcroat", 321 | } 322 | -------------------------------------------------------------------------------- /font/sfnt/kern_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package sfnt 6 | 7 | /* 8 | This file contains opt-in tests for kerning in user provided fonts. 9 | 10 | Kerning information in kern and GPOS tables can be quite complex. These tests 11 | recursively load all fonts from -bulkFontDirs and try to kern all possible 12 | glyph pairs. 13 | 14 | These tests only check if there are no errors during kerning. Tests of actual 15 | kerning values are in proprietary_test.go. 16 | 17 | Note: CJK fonts can contain billions of posible kerning pairs. Testing for 18 | these fonts stops after -bulkMaxKernPairs. 19 | 20 | To opt-in: 21 | 22 | go test golang.org/x/image/font/sfnt -test.run=BulkKern -args -bulk -bulkFontDirs /Library/Fonts:./myfonts 23 | */ 24 | 25 | import ( 26 | "flag" 27 | "io/ioutil" 28 | "log" 29 | "os" 30 | "path/filepath" 31 | "strings" 32 | "testing" 33 | 34 | "golang.org/x/image/font" 35 | "golang.org/x/image/math/fixed" 36 | ) 37 | 38 | var ( 39 | bulk = flag.Bool("bulk", false, "") 40 | 41 | fontDirs = flag.String( 42 | "bulkFontDirs", 43 | "./", 44 | "separated directories to search for fonts", 45 | ) 46 | maxKernPairs = flag.Int( 47 | "bulkMaxKernPairs", 48 | 20000000, 49 | "skip testing of kerning after this many tested pairs", 50 | ) 51 | ) 52 | 53 | func TestBulkKern(t *testing.T) { 54 | if !*bulk { 55 | t.Skip("skipping bulk font test") 56 | } 57 | 58 | for _, fontDir := range filepath.SplitList(*fontDirs) { 59 | err := filepath.Walk(fontDir, func(path string, info os.FileInfo, err error) error { 60 | if err != nil { 61 | return err 62 | } 63 | if info.IsDir() { 64 | return nil 65 | } 66 | if strings.HasSuffix(path, ".ttf") || strings.HasSuffix(path, ".otf") { 67 | t.Run(info.Name(), testFontKerning(filepath.Join(path))) 68 | } 69 | return nil 70 | }) 71 | if err != nil { 72 | t.Fatal("error finding fonts", err) 73 | } 74 | } 75 | 76 | } 77 | 78 | func testFontKerning(fname string) func(*testing.T) { 79 | return func(t *testing.T) { 80 | t.Parallel() 81 | b, err := ioutil.ReadFile(fname) 82 | if err != nil { 83 | t.Fatal(err) 84 | } 85 | fnt, err := Parse(b) 86 | if err != nil { 87 | t.Fatal(err) 88 | } 89 | 90 | buf := &Buffer{} 91 | 92 | // collect all GlyphIndex 93 | glyphs := make([]GlyphIndex, 1, fnt.NumGlyphs()) 94 | glyphs[0] = GlyphIndex(0) 95 | r := rune(0) 96 | for r < 0xffff { 97 | g, err := fnt.GlyphIndex(buf, r) 98 | r++ 99 | if g == 0 || err == ErrNotFound { 100 | continue 101 | } 102 | if err != nil { 103 | t.Fatal(err) 104 | } 105 | glyphs = append(glyphs, g) 106 | if len(glyphs) == fnt.NumGlyphs() { 107 | break 108 | } 109 | } 110 | 111 | var kerned, tested int 112 | for _, g1 := range glyphs { 113 | for _, g2 := range glyphs { 114 | if tested >= *maxKernPairs { 115 | log.Printf("stop testing after %d or %d kerning pairs (found %d pairs)", 116 | tested, len(glyphs)*len(glyphs), kerned) 117 | return 118 | } 119 | 120 | tested++ 121 | adv, err := fnt.Kern(buf, g1, g2, fixed.I(20), font.HintingNone) 122 | if err == ErrNotFound { 123 | continue 124 | } 125 | if err != nil { 126 | t.Fatal(err) 127 | } 128 | if adv != 0 { 129 | kerned++ 130 | } 131 | } 132 | } 133 | 134 | log.Printf("found %d kerning pairs for %d glyphs (%.1f%%) in %q", 135 | kerned, 136 | len(glyphs), 137 | 100*float64(kerned)/float64(len(glyphs)*len(glyphs)), 138 | fname, 139 | ) 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /font/testdata/CFFTest.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/CFFTest.otf -------------------------------------------------------------------------------- /font/testdata/CFFTest.sfd: -------------------------------------------------------------------------------- 1 | SplineFontDB: 3.0 2 | FontName: CFFTest 3 | FullName: CFFTest 4 | FamilyName: CFFTest 5 | Weight: Regular 6 | 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. 7 | Version: 001.000 8 | ItalicAngle: -11.25 9 | UnderlinePosition: -100 10 | UnderlineWidth: 50 11 | Ascent: 800 12 | Descent: 200 13 | LayerCount: 2 14 | Layer: 0 0 "Back" 1 15 | Layer: 1 0 "Fore" 0 16 | XUID: [1021 367 888937226 7862908] 17 | FSType: 8 18 | OS2Version: 0 19 | OS2_WeightWidthSlopeOnly: 0 20 | OS2_UseTypoMetrics: 1 21 | CreationTime: 1479626795 22 | ModificationTime: 1481282599 23 | PfmFamily: 17 24 | TTFWeight: 400 25 | TTFWidth: 5 26 | LineGap: 90 27 | VLineGap: 0 28 | OS2TypoAscent: 0 29 | OS2TypoAOffset: 1 30 | OS2TypoDescent: 0 31 | OS2TypoDOffset: 1 32 | OS2TypoLinegap: 90 33 | OS2WinAscent: 0 34 | OS2WinAOffset: 1 35 | OS2WinDescent: 0 36 | OS2WinDOffset: 1 37 | HheadAscent: 0 38 | HheadAOffset: 1 39 | HheadDescent: 0 40 | HheadDOffset: 1 41 | OS2Vendor: 'PfEd' 42 | MarkAttachClasses: 1 43 | DEI: 91125 44 | LangName: 1033 45 | Encoding: UnicodeBmp 46 | UnicodeInterp: none 47 | NameList: Adobe Glyph List 48 | DisplaySize: -24 49 | AntiAlias: 1 50 | FitToEm: 1 51 | WinInfo: 64 32 11 52 | BeginPrivate: 0 53 | EndPrivate 54 | 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 55 | BeginChars: 65536 4 56 | 57 | StartChar: zero 58 | Encoding: 48 48 0 59 | Width: 600 60 | VWidth: 0 61 | HStem: 0 100<248.223 341.575> 700 100<258.425 351.777> 62 | VStem: 100 80<243.925 531.374> 420 80<268.627 556.075> 63 | LayerCount: 2 64 | Fore 65 | SplineSet 66 | 300 700 m 0 67 | 210 700 180 450 180 300 c 24 68 | 180 220 220 100 300 100 c 0 69 | 390 100 420 350 420 500 c 24 70 | 420 580 380 700 300 700 c 0 71 | 300 800 m 0 72 | 400 800 500 580 500 400 c 0 73 | 500 220 400 0 300 0 c 0 74 | 200 0 100 220 100 400 c 0 75 | 100 580 200 800 300 800 c 0 76 | EndSplineSet 77 | Validated: 1 78 | EndChar 79 | 80 | StartChar: one 81 | Encoding: 49 49 1 82 | Width: 400 83 | VWidth: 0 84 | Flags: W 85 | HStem: 0 21G<100 300> 86 | VStem: 100 200<0 800> 87 | LayerCount: 2 88 | Fore 89 | SplineSet 90 | 100 0 m 25 91 | 100 800 l 25 92 | 300 800 l 29 93 | 300 0 l 29 94 | 100 0 l 25 95 | EndSplineSet 96 | Validated: 1 97 | EndChar 98 | 99 | StartChar: uni4E2D 100 | Encoding: 20013 20013 2 101 | Width: 600 102 | VWidth: 0 103 | Flags: W 104 | VStem: 245 86<641.8 752> 105 | LayerCount: 2 106 | Fore 107 | SplineSet 108 | 141 520 m 25 109 | 235 562 l 25 110 | 243 752 l 25 111 | 331 758 l 25 112 | 341 592 l 25 113 | 453 620 l 25 114 | 463 434 l 25 115 | 355 414 l 25 116 | 331 26 l 25 117 | 245 400 l 25 118 | 137 356 l 25 119 | 141 520 l 25 120 | EndSplineSet 121 | Validated: 1 122 | EndChar 123 | 124 | StartChar: Q 125 | Encoding: 81 81 3 126 | Width: 1000 127 | VWidth: 0 128 | Flags: W 129 | LayerCount: 2 130 | Fore 131 | SplineSet 132 | 657 237 m 0 133 | 519 615 l 0 134 | 289 387 l 0 135 | 657 237 l 0 136 | 792 169 m 1 137 | 864 83 l 25 138 | 802 3 l 21 139 | 722 93 l 1 140 | 641 18 369 -39 242 93 c 0 141 | 110 231 71 509 228 673 c 24 142 | 380 831 645 840 791 665 c 0 143 | 926 502 867 263 792 169 c 1 144 | EndSplineSet 145 | Validated: 33 146 | EndChar 147 | EndChars 148 | EndSplineFont 149 | -------------------------------------------------------------------------------- /font/testdata/README: -------------------------------------------------------------------------------- 1 | CFFTest.sfd is a FontForge file for creating CFFTest.otf, a custom OpenType 2 | font for testing the golang.org/x/image/font/sfnt package's CFF support. 3 | -------------------------------------------------------------------------------- /font/testdata/cmapTest.sfd: -------------------------------------------------------------------------------- 1 | SplineFontDB: 3.0 2 | FontName: cmapTest 3 | FullName: cmapTest 4 | FamilyName: cmapTest 5 | Weight: Regular 6 | 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. 7 | Version: 001.000 8 | ItalicAngle: -11.25 9 | UnderlinePosition: -204 10 | UnderlineWidth: 102 11 | Ascent: 1638 12 | Descent: 410 13 | LayerCount: 2 14 | Layer: 0 1 "Back" 1 15 | Layer: 1 1 "Fore" 0 16 | XUID: [1021 367 888937226 7862908] 17 | FSType: 8 18 | OS2Version: 0 19 | OS2_WeightWidthSlopeOnly: 0 20 | OS2_UseTypoMetrics: 1 21 | CreationTime: 1484386143 22 | ModificationTime: 1486021330 23 | PfmFamily: 17 24 | TTFWeight: 400 25 | TTFWidth: 5 26 | LineGap: 184 27 | VLineGap: 0 28 | OS2TypoAscent: 0 29 | OS2TypoAOffset: 1 30 | OS2TypoDescent: 0 31 | OS2TypoDOffset: 1 32 | OS2TypoLinegap: 184 33 | OS2WinAscent: 0 34 | OS2WinAOffset: 1 35 | OS2WinDescent: 0 36 | OS2WinDOffset: 1 37 | HheadAscent: 0 38 | HheadAOffset: 1 39 | HheadDescent: 0 40 | HheadDOffset: 1 41 | OS2Vendor: 'PfEd' 42 | MarkAttachClasses: 1 43 | DEI: 91125 44 | LangName: 1033 45 | Encoding: UnicodeFull 46 | UnicodeInterp: none 47 | NameList: Adobe Glyph List 48 | DisplaySize: -24 49 | AntiAlias: 1 50 | FitToEm: 1 51 | WinInfo: 126976 32 23 52 | BeginPrivate: 0 53 | EndPrivate 54 | 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 55 | BeginChars: 1114112 13 56 | 57 | StartChar: zero 58 | Encoding: 48 48 0 59 | Width: 800 60 | VWidth: 0 61 | Flags: W 62 | LayerCount: 2 63 | Fore 64 | SplineSet 65 | 0 0 m 29,0,-1 66 | 400 800 l 25,1,-1 67 | 800 0 l 25,2,-1 68 | 0 0 l 29,0,-1 69 | EndSplineSet 70 | Validated: 1 71 | EndChar 72 | 73 | StartChar: one 74 | Encoding: 49 49 1 75 | Width: 800 76 | VWidth: 0 77 | Flags: W 78 | LayerCount: 2 79 | Fore 80 | SplineSet 81 | 0 0 m 29,0,-1 82 | 400 800 l 25,1,-1 83 | 800 0 l 25,2,-1 84 | 0 0 l 29,0,-1 85 | EndSplineSet 86 | Validated: 1 87 | EndChar 88 | 89 | StartChar: two 90 | Encoding: 50 50 2 91 | Width: 800 92 | VWidth: 0 93 | Flags: W 94 | LayerCount: 2 95 | Fore 96 | SplineSet 97 | 0 0 m 29,0,-1 98 | 400 800 l 25,1,-1 99 | 800 0 l 25,2,-1 100 | 0 0 l 29,0,-1 101 | EndSplineSet 102 | Validated: 1 103 | EndChar 104 | 105 | StartChar: A 106 | Encoding: 65 65 3 107 | Width: 800 108 | VWidth: 0 109 | Flags: W 110 | LayerCount: 2 111 | Fore 112 | SplineSet 113 | 0 0 m 29,0,-1 114 | 400 800 l 25,1,-1 115 | 800 0 l 25,2,-1 116 | 0 0 l 29,0,-1 117 | EndSplineSet 118 | Validated: 1 119 | EndChar 120 | 121 | StartChar: uni4E2D 122 | Encoding: 20013 20013 4 123 | Width: 800 124 | VWidth: 0 125 | Flags: W 126 | LayerCount: 2 127 | Fore 128 | SplineSet 129 | 0 0 m 29,0,-1 130 | 400 800 l 25,1,-1 131 | 800 0 l 25,2,-1 132 | 0 0 l 29,0,-1 133 | EndSplineSet 134 | Validated: 1 135 | EndChar 136 | 137 | StartChar: u1F0A1 138 | Encoding: 127137 127137 5 139 | Width: 800 140 | VWidth: 0 141 | Flags: W 142 | LayerCount: 2 143 | Fore 144 | SplineSet 145 | 0 0 m 29,0,-1 146 | 400 800 l 25,1,-1 147 | 800 0 l 25,2,-1 148 | 0 0 l 29,0,-1 149 | EndSplineSet 150 | Validated: 1 151 | EndChar 152 | 153 | StartChar: ydieresis 154 | Encoding: 255 255 6 155 | Width: 800 156 | VWidth: 0 157 | Flags: W 158 | LayerCount: 2 159 | Fore 160 | SplineSet 161 | 0 0 m 29,0,-1 162 | 400 800 l 25,1,-1 163 | 800 0 l 25,2,-1 164 | 0 0 l 29,0,-1 165 | EndSplineSet 166 | Validated: 1 167 | EndChar 168 | 169 | StartChar: Amacron 170 | Encoding: 256 256 7 171 | Width: 800 172 | VWidth: 0 173 | Flags: W 174 | LayerCount: 2 175 | Fore 176 | SplineSet 177 | 0 0 m 29,0,-1 178 | 400 800 l 25,1,-1 179 | 800 0 l 25,2,-1 180 | 0 0 l 29,0,-1 181 | EndSplineSet 182 | Validated: 1 183 | EndChar 184 | 185 | StartChar: amacron 186 | Encoding: 257 257 8 187 | Width: 800 188 | VWidth: 0 189 | Flags: W 190 | LayerCount: 2 191 | Fore 192 | SplineSet 193 | 0 0 m 29,0,-1 194 | 400 800 l 25,1,-1 195 | 800 0 l 25,2,-1 196 | 0 0 l 29,0,-1 197 | EndSplineSet 198 | Validated: 1 199 | EndChar 200 | 201 | StartChar: B 202 | Encoding: 66 66 9 203 | Width: 800 204 | VWidth: 0 205 | Flags: W 206 | LayerCount: 2 207 | Fore 208 | SplineSet 209 | 0 0 m 29,0,-1 210 | 400 800 l 25,1,-1 211 | 800 0 l 25,2,-1 212 | 0 0 l 29,0,-1 213 | EndSplineSet 214 | Validated: 1 215 | EndChar 216 | 217 | StartChar: a 218 | Encoding: 97 97 10 219 | Width: 800 220 | VWidth: 0 221 | Flags: W 222 | LayerCount: 2 223 | Fore 224 | SplineSet 225 | 0 0 m 29,0,-1 226 | 400 800 l 25,1,-1 227 | 800 0 l 25,2,-1 228 | 0 0 l 29,0,-1 229 | EndSplineSet 230 | Validated: 1 231 | EndChar 232 | 233 | StartChar: u1F0B1 234 | Encoding: 127153 127153 11 235 | Width: 800 236 | VWidth: 0 237 | Flags: W 238 | LayerCount: 2 239 | Fore 240 | SplineSet 241 | 0 0 m 29,0,-1 242 | 400 800 l 25,1,-1 243 | 800 0 l 25,2,-1 244 | 0 0 l 29,0,-1 245 | EndSplineSet 246 | Validated: 1 247 | EndChar 248 | 249 | StartChar: u1F0B2 250 | Encoding: 127154 127154 12 251 | Width: 800 252 | VWidth: 0 253 | Flags: W 254 | LayerCount: 2 255 | Fore 256 | SplineSet 257 | 0 0 m 29,0,-1 258 | 400 800 l 25,1,-1 259 | 800 0 l 25,2,-1 260 | 0 0 l 29,0,-1 261 | EndSplineSet 262 | Validated: 1 263 | EndChar 264 | EndChars 265 | EndSplineFont 266 | -------------------------------------------------------------------------------- /font/testdata/cmapTest.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/cmapTest.ttf -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.0000: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.0000 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.0100: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.0100 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.0200: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.0200 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.0300: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.0300 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.0400: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.0400 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.0500: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.0500 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.0E00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.0E00 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.1000: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.1000 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.1600: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.1600 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.1E00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.1E00 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.1F00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.1F00 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2000: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2000 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2100: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2100 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2200: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2200 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2300: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2300 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2400: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2400 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2500: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2500 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2600: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2600 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2700: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2700 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2800: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2800 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.2A00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.2A00 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.3000: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.3000 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.FB00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.FB00 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.FE00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.FE00 -------------------------------------------------------------------------------- /font/testdata/fixed/7x13.FF00: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/fixed/7x13.FF00 -------------------------------------------------------------------------------- /font/testdata/fixed/README: -------------------------------------------------------------------------------- 1 | These font files were copied from the Plan 9 Port's font/fixed directory. The 2 | README in that directory states that: "These fonts are converted from the BDFs 3 | in the XFree86 distribution. They were all marked as public domain." 4 | 5 | The Plan 9 Port is at https://github.com/9fans/plan9port and the copy was made 6 | from commit a78b1841 (2015-08-18). 7 | 8 | The unicode.7x13.font file also refers to a ../shinonome directory, but this 9 | testdata does not include those subfont files. 10 | -------------------------------------------------------------------------------- /font/testdata/fixed/unicode.7x13.font: -------------------------------------------------------------------------------- 1 | 13 11 2 | 0x0000 0x001F 7x13.2400 3 | 0x0000 0x00FF 7x13.0000 4 | 0x0100 0x01FF 7x13.0100 5 | 0x0200 0x02FF 7x13.0200 6 | 0x0300 0x03FF 7x13.0300 7 | 0x0400 0x04FF 7x13.0400 8 | 0x0500 0x05FF 7x13.0500 9 | 0x0E00 0x0EFF 7x13.0E00 10 | 0x1000 0x10FF 7x13.1000 11 | 0x1600 0x16FF 7x13.1600 12 | 0x1E00 0x1EFF 7x13.1E00 13 | 0x1F00 0x1FFF 7x13.1F00 14 | 0x2000 0x20FF 7x13.2000 15 | 0x2100 0x21FF 7x13.2100 16 | 0x2200 0x22FF 7x13.2200 17 | 0x2300 0x23FF 7x13.2300 18 | 0x2400 0x24FF 7x13.2400 19 | 0x2500 0x25FF 7x13.2500 20 | 0x2600 0x26FF 7x13.2600 21 | 0x2700 0x27FF 7x13.2700 22 | 0x2800 0x28FF 7x13.2800 23 | 0x2A00 0x2AFF 7x13.2A00 24 | 0x3000 0x30fe ../shinonome/k12.3000 25 | 0x4e00 0x4ffe ../shinonome/k12.4e00 26 | 0x5005 0x51fe ../shinonome/k12.5005 27 | 0x5200 0x53fa ../shinonome/k12.5200 28 | 0x5401 0x55fe ../shinonome/k12.5401 29 | 0x5606 0x57fc ../shinonome/k12.5606 30 | 0x5800 0x59ff ../shinonome/k12.5800 31 | 0x5a01 0x5bff ../shinonome/k12.5a01 32 | 0x5c01 0x5dfe ../shinonome/k12.5c01 33 | 0x5e02 0x5fff ../shinonome/k12.5e02 34 | 0x600e 0x61ff ../shinonome/k12.600e 35 | 0x6200 0x63fa ../shinonome/k12.6200 36 | 0x6406 0x65fb ../shinonome/k12.6406 37 | 0x6602 0x67ff ../shinonome/k12.6602 38 | 0x6802 0x69ff ../shinonome/k12.6802 39 | 0x6a02 0x6bf3 ../shinonome/k12.6a02 40 | 0x6c08 0x6dfb ../shinonome/k12.6c08 41 | 0x6e05 0x6ffe ../shinonome/k12.6e05 42 | 0x7001 0x71ff ../shinonome/k12.7001 43 | 0x7206 0x73fe ../shinonome/k12.7206 44 | 0x7403 0x75ff ../shinonome/k12.7403 45 | 0x7601 0x77fc ../shinonome/k12.7601 46 | 0x7802 0x79fb ../shinonome/k12.7802 47 | 0x7a00 0x7bf7 ../shinonome/k12.7a00 48 | 0x7c00 0x7dfb ../shinonome/k12.7c00 49 | 0x7e01 0x7ffc ../shinonome/k12.7e01 50 | 0x8000 0x81fe ../shinonome/k12.8000 51 | 0x8201 0x83fd ../shinonome/k12.8201 52 | 0x8403 0x85fe ../shinonome/k12.8403 53 | 0x8602 0x87fe ../shinonome/k12.8602 54 | 0x8805 0x89f8 ../shinonome/k12.8805 55 | 0x8a00 0x8b9a ../shinonome/k12.8a00 56 | 0x8c37 0x8dff ../shinonome/k12.8c37 57 | 0x8e08 0x8ffd ../shinonome/k12.8e08 58 | 0x9000 0x91ff ../shinonome/k12.9000 59 | 0x920d 0x93e8 ../shinonome/k12.920d 60 | 0x9403 0x95e5 ../shinonome/k12.9403 61 | 0x961c 0x97ff ../shinonome/k12.961c 62 | 0x9801 0x99ff ../shinonome/k12.9801 63 | 0x9a01 0x9bf5 ../shinonome/k12.9a01 64 | 0x9c04 0x9dfd ../shinonome/k12.9c04 65 | 0x9e1a 0x9fa0 ../shinonome/k12.9e1a 66 | 0xFB00 0xFBFF 7x13.FB00 67 | 0xFE00 0xFEFF 7x13.FE00 68 | 0xFF00 0xFFFF 7x13.FF00 69 | -------------------------------------------------------------------------------- /font/testdata/glyfTest.sfd: -------------------------------------------------------------------------------- 1 | SplineFontDB: 3.0 2 | FontName: glyfTest 3 | FullName: glyfTest 4 | FamilyName: glyfTest 5 | Weight: Book 6 | 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. 7 | Version: 001.000 8 | ItalicAngle: -11.25 9 | UnderlinePosition: -204 10 | UnderlineWidth: 102 11 | Ascent: 1638 12 | Descent: 410 13 | sfntRevision: 0x00010000 14 | LayerCount: 2 15 | Layer: 0 1 "Back" 1 16 | Layer: 1 1 "Fore" 0 17 | XUID: [1021 367 888937226 5879518] 18 | FSType: 8 19 | OS2Version: 4 20 | OS2_WeightWidthSlopeOnly: 0 21 | OS2_UseTypoMetrics: 1 22 | CreationTime: 1484386143 23 | ModificationTime: 1489831626 24 | PfmFamily: 17 25 | TTFWeight: 400 26 | TTFWidth: 5 27 | LineGap: 184 28 | VLineGap: 0 29 | Panose: 2 0 5 3 0 0 0 0 0 0 30 | OS2TypoAscent: 1638 31 | OS2TypoAOffset: 0 32 | OS2TypoDescent: -410 33 | OS2TypoDOffset: 0 34 | OS2TypoLinegap: 184 35 | OS2WinAscent: 1984 36 | OS2WinAOffset: 0 37 | OS2WinDescent: 0 38 | OS2WinDOffset: 0 39 | HheadAscent: 1984 40 | HheadAOffset: 0 41 | HheadDescent: 0 42 | HheadDOffset: 0 43 | OS2SubXSize: 1331 44 | OS2SubYSize: 1433 45 | OS2SubXOff: 55 46 | OS2SubYOff: 286 47 | OS2SupXSize: 1331 48 | OS2SupYSize: 1433 49 | OS2SupXOff: -191 50 | OS2SupYOff: 983 51 | OS2StrikeYSize: 102 52 | OS2StrikeYPos: 530 53 | OS2Vendor: 'PfEd' 54 | OS2CodePages: 00000001.00000000 55 | OS2UnicodeRanges: 00000001.00000000.00000000.00000000 56 | MarkAttachClasses: 1 57 | DEI: 91125 58 | ShortTable: cvt 2 59 | 68 60 | 1297 61 | EndShort 62 | ShortTable: maxp 16 63 | 1 64 | 0 65 | 10 66 | 18 67 | 2 68 | 8 69 | 2 70 | 2 71 | 0 72 | 1 73 | 1 74 | 0 75 | 64 76 | 46 77 | 2 78 | 1 79 | EndShort 80 | LangName: 1033 "" "" "Regular" "FontForge : glyfTest : 18-3-2017" "" "Version 001.000" 81 | GaspTable: 1 65535 2 0 82 | Encoding: UnicodeBmp 83 | UnicodeInterp: none 84 | NameList: Adobe Glyph List 85 | DisplaySize: -24 86 | AntiAlias: 1 87 | FitToEm: 1 88 | WinInfo: 0 32 23 89 | BeginChars: 65539 10 90 | 91 | StartChar: .notdef 92 | Encoding: 65536 -1 0 93 | Width: 748 94 | Flags: W 95 | LayerCount: 2 96 | Fore 97 | SplineSet 98 | 68 0 m 1,0,-1 99 | 68 1365 l 1,1,-1 100 | 612 1365 l 1,2,-1 101 | 612 0 l 1,3,-1 102 | 68 0 l 1,0,-1 103 | 136 68 m 1,4,-1 104 | 544 68 l 1,5,-1 105 | 544 1297 l 1,6,-1 106 | 136 1297 l 1,7,-1 107 | 136 68 l 1,4,-1 108 | EndSplineSet 109 | Validated: 1 110 | EndChar 111 | 112 | StartChar: .null 113 | Encoding: 65537 -1 1 114 | Width: 0 115 | Flags: W 116 | LayerCount: 2 117 | EndChar 118 | 119 | StartChar: nonmarkingreturn 120 | Encoding: 65538 -1 2 121 | Width: 682 122 | Flags: W 123 | LayerCount: 2 124 | EndChar 125 | 126 | StartChar: zero 127 | Encoding: 48 48 3 128 | Width: 1228 129 | Flags: W 130 | LayerCount: 2 131 | Fore 132 | SplineSet 133 | 614 1434 m 0,0,1 134 | 369 1434 369 1434 369 614 c 0,2,3 135 | 369 471 369 471 435 338 c 0,4,5 136 | 502 205 502 205 614 205 c 0,6,7 137 | 860 205 860 205 860 1024 c 0,8,9 138 | 860 1167 860 1167 793 1300 c 1,10,11 139 | 727 1434 727 1434 614 1434 c 0,0,1 140 | 614 1638 m 0,12,13 141 | 1024 1638 1024 1638 1024 819 c 128,-1,14 142 | 1024 0 1024 0 614 0 c 0,15,16 143 | 205 0 205 0 205 819 c 128,-1,17 144 | 205 1638 205 1638 614 1638 c 0,12,13 145 | EndSplineSet 146 | Validated: 1 147 | EndChar 148 | 149 | StartChar: one 150 | Encoding: 49 49 4 151 | Width: 819 152 | Flags: W 153 | LayerCount: 2 154 | Fore 155 | SplineSet 156 | 205 0 m 1,0,-1 157 | 205 1638 l 1,1,-1 158 | 614 1638 l 1,2,-1 159 | 614 0 l 1,3,-1 160 | 205 0 l 1,0,-1 161 | EndSplineSet 162 | Validated: 1 163 | EndChar 164 | 165 | StartChar: five 166 | Encoding: 53 53 5 167 | Width: 400 168 | Flags: W 169 | LayerCount: 2 170 | Fore 171 | SplineSet 172 | 0 0 m 1,0,-1 173 | 0 100 l 1,1,-1 174 | 400 100 l 1,2,-1 175 | 400 0 l 1,3,-1 176 | 0 0 l 1,0,-1 177 | EndSplineSet 178 | Validated: 1 179 | EndChar 180 | 181 | StartChar: six 182 | Encoding: 54 54 6 183 | Width: 400 184 | Flags: W 185 | LayerCount: 2 186 | Fore 187 | Refer: 5 53 N 1 0 0 1 0 0 2 188 | Refer: 4 49 N 1 0 0 1 111 234 2 189 | Validated: 1 190 | EndChar 191 | 192 | StartChar: seven 193 | Encoding: 55 55 7 194 | Width: 400 195 | Flags: W 196 | LayerCount: 2 197 | Fore 198 | Refer: 5 53 N 1 0 0 1 0 0 2 199 | Refer: 4 49 N 0.5 0 0 0.5 56 117 2 200 | Validated: 1 201 | EndChar 202 | 203 | StartChar: eight 204 | Encoding: 56 56 8 205 | Width: 400 206 | Flags: W 207 | LayerCount: 2 208 | Fore 209 | Refer: 5 53 N 1 0 0 1 0 0 2 210 | Refer: 4 49 N 1.5 0 0 0.5 56 117 2 211 | Validated: 1 212 | EndChar 213 | 214 | StartChar: nine 215 | Encoding: 57 57 9 216 | Width: 400 217 | Flags: W 218 | LayerCount: 2 219 | Fore 220 | Refer: 5 53 N 1 0 0 1 0 0 2 221 | Refer: 4 49 N 1.36603 0.5 0.365967 0.865967 237 258 2 222 | Validated: 1 223 | EndChar 224 | EndChars 225 | EndSplineFont 226 | -------------------------------------------------------------------------------- /font/testdata/glyfTest.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/font/testdata/glyfTest.ttf -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module golang.org/x/image 2 | 3 | go 1.23.0 4 | 5 | require golang.org/x/text v0.26.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= 2 | golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= 3 | -------------------------------------------------------------------------------- /math/f32/f32.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package f32 implements float32 vector and matrix types. 6 | package f32 // import "golang.org/x/image/math/f32" 7 | 8 | // Vec2 is a 2-element vector. 9 | type Vec2 [2]float32 10 | 11 | // Vec3 is a 3-element vector. 12 | type Vec3 [3]float32 13 | 14 | // Vec4 is a 4-element vector. 15 | type Vec4 [4]float32 16 | 17 | // Mat3 is a 3x3 matrix in row major order. 18 | // 19 | // m[3*r + c] is the element in the r'th row and c'th column. 20 | type Mat3 [9]float32 21 | 22 | // Mat4 is a 4x4 matrix in row major order. 23 | // 24 | // m[4*r + c] is the element in the r'th row and c'th column. 25 | type Mat4 [16]float32 26 | 27 | // Aff3 is a 3x3 affine transformation matrix in row major order, where the 28 | // bottom row is implicitly [0 0 1]. 29 | // 30 | // m[3*r + c] is the element in the r'th row and c'th column. 31 | type Aff3 [6]float32 32 | 33 | // Aff4 is a 4x4 affine transformation matrix in row major order, where the 34 | // bottom row is implicitly [0 0 0 1]. 35 | // 36 | // m[4*r + c] is the element in the r'th row and c'th column. 37 | type Aff4 [12]float32 38 | -------------------------------------------------------------------------------- /math/f64/f64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package f64 implements float64 vector and matrix types. 6 | package f64 // import "golang.org/x/image/math/f64" 7 | 8 | // Vec2 is a 2-element vector. 9 | type Vec2 [2]float64 10 | 11 | // Vec3 is a 3-element vector. 12 | type Vec3 [3]float64 13 | 14 | // Vec4 is a 4-element vector. 15 | type Vec4 [4]float64 16 | 17 | // Mat3 is a 3x3 matrix in row major order. 18 | // 19 | // m[3*r + c] is the element in the r'th row and c'th column. 20 | type Mat3 [9]float64 21 | 22 | // Mat4 is a 4x4 matrix in row major order. 23 | // 24 | // m[4*r + c] is the element in the r'th row and c'th column. 25 | type Mat4 [16]float64 26 | 27 | // Aff3 is a 3x3 affine transformation matrix in row major order, where the 28 | // bottom row is implicitly [0 0 1]. 29 | // 30 | // m[3*r + c] is the element in the r'th row and c'th column. 31 | type Aff3 [6]float64 32 | 33 | // Aff4 is a 4x4 affine transformation matrix in row major order, where the 34 | // bottom row is implicitly [0 0 0 1]. 35 | // 36 | // m[4*r + c] is the element in the r'th row and c'th column. 37 | type Aff4 [12]float64 38 | -------------------------------------------------------------------------------- /riff/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package riff_test 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | "io/ioutil" 11 | "log" 12 | "strings" 13 | 14 | "golang.org/x/image/riff" 15 | ) 16 | 17 | func ExampleReader() { 18 | formType, r, err := riff.NewReader(strings.NewReader(data)) 19 | if err != nil { 20 | log.Fatal(err) 21 | } 22 | fmt.Printf("RIFF(%s)\n", formType) 23 | if err := dump(r, ".\t"); err != nil { 24 | log.Fatal(err) 25 | } 26 | // Output: 27 | // RIFF(ROOT) 28 | // . ZERO "" 29 | // . ONE "a" 30 | // . LIST(META) 31 | // . . LIST(GOOD) 32 | // . . . ONE "a" 33 | // . . . FIVE "klmno" 34 | // . . ZERO "" 35 | // . . LIST(BAD ) 36 | // . . . THRE "def" 37 | // . TWO "bc" 38 | // . LIST(UGLY) 39 | // . . FOUR "ghij" 40 | // . . SIX "pqrstu" 41 | } 42 | 43 | func dump(r *riff.Reader, indent string) error { 44 | for { 45 | chunkID, chunkLen, chunkData, err := r.Next() 46 | if err == io.EOF { 47 | return nil 48 | } 49 | if err != nil { 50 | return err 51 | } 52 | if chunkID == riff.LIST { 53 | listType, list, err := riff.NewListReader(chunkLen, chunkData) 54 | if err != nil { 55 | return err 56 | } 57 | fmt.Printf("%sLIST(%s)\n", indent, listType) 58 | if err := dump(list, indent+".\t"); err != nil { 59 | return err 60 | } 61 | continue 62 | } 63 | b, err := ioutil.ReadAll(chunkData) 64 | if err != nil { 65 | return err 66 | } 67 | fmt.Printf("%s%s %q\n", indent, chunkID, b) 68 | } 69 | } 70 | 71 | func encodeU32(u uint32) string { 72 | return string([]byte{ 73 | byte(u >> 0), 74 | byte(u >> 8), 75 | byte(u >> 16), 76 | byte(u >> 24), 77 | }) 78 | } 79 | 80 | func encode(chunkID, contents string) string { 81 | n := len(contents) 82 | if n&1 == 1 { 83 | contents += "\x00" 84 | } 85 | return chunkID + encodeU32(uint32(n)) + contents 86 | } 87 | 88 | func encodeMulti(typ0, typ1 string, chunks ...string) string { 89 | n := 4 90 | for _, c := range chunks { 91 | n += len(c) 92 | } 93 | s := typ0 + encodeU32(uint32(n)) + typ1 94 | for _, c := range chunks { 95 | s += c 96 | } 97 | return s 98 | } 99 | 100 | var ( 101 | d0 = encode("ZERO", "") 102 | d1 = encode("ONE ", "a") 103 | d2 = encode("TWO ", "bc") 104 | d3 = encode("THRE", "def") 105 | d4 = encode("FOUR", "ghij") 106 | d5 = encode("FIVE", "klmno") 107 | d6 = encode("SIX ", "pqrstu") 108 | l0 = encodeMulti("LIST", "GOOD", d1, d5) 109 | l1 = encodeMulti("LIST", "BAD ", d3) 110 | l2 = encodeMulti("LIST", "UGLY", d4, d6) 111 | l01 = encodeMulti("LIST", "META", l0, d0, l1) 112 | data = encodeMulti("RIFF", "ROOT", d0, d1, l01, d2, l2) 113 | ) 114 | -------------------------------------------------------------------------------- /riff/riff.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package riff implements the Resource Interchange File Format, used by media 6 | // formats such as AVI, WAVE and WEBP. 7 | // 8 | // A RIFF stream contains a sequence of chunks. Each chunk consists of an 8-byte 9 | // header (containing a 4-byte chunk type and a 4-byte chunk length), the chunk 10 | // data (presented as an io.Reader), and some padding bytes. 11 | // 12 | // A detailed description of the format is at 13 | // http://www.tactilemedia.com/info/MCI_Control_Info.html 14 | package riff // import "golang.org/x/image/riff" 15 | 16 | import ( 17 | "errors" 18 | "io" 19 | "io/ioutil" 20 | "math" 21 | ) 22 | 23 | var ( 24 | errMissingPaddingByte = errors.New("riff: missing padding byte") 25 | errMissingRIFFChunkHeader = errors.New("riff: missing RIFF chunk header") 26 | errListSubchunkTooLong = errors.New("riff: list subchunk too long") 27 | errShortChunkData = errors.New("riff: short chunk data") 28 | errShortChunkHeader = errors.New("riff: short chunk header") 29 | errStaleReader = errors.New("riff: stale reader") 30 | ) 31 | 32 | // u32 decodes the first four bytes of b as a little-endian integer. 33 | func u32(b []byte) uint32 { 34 | return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 35 | } 36 | 37 | const chunkHeaderSize = 8 38 | 39 | // FourCC is a four character code. 40 | type FourCC [4]byte 41 | 42 | // LIST is the "LIST" FourCC. 43 | var LIST = FourCC{'L', 'I', 'S', 'T'} 44 | 45 | // NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and 46 | // its chunks as a *Reader. 47 | func NewReader(r io.Reader) (formType FourCC, data *Reader, err error) { 48 | var buf [chunkHeaderSize]byte 49 | if _, err := io.ReadFull(r, buf[:]); err != nil { 50 | if err == io.EOF || err == io.ErrUnexpectedEOF { 51 | err = errMissingRIFFChunkHeader 52 | } 53 | return FourCC{}, nil, err 54 | } 55 | if buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' { 56 | return FourCC{}, nil, errMissingRIFFChunkHeader 57 | } 58 | return NewListReader(u32(buf[4:]), r) 59 | } 60 | 61 | // NewListReader returns a LIST chunk's list type, such as "movi" or "wavl", 62 | // and its chunks as a *Reader. 63 | func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error) { 64 | if chunkLen < 4 { 65 | return FourCC{}, nil, errShortChunkData 66 | } 67 | z := &Reader{r: chunkData} 68 | if _, err := io.ReadFull(chunkData, z.buf[:4]); err != nil { 69 | if err == io.EOF || err == io.ErrUnexpectedEOF { 70 | err = errShortChunkData 71 | } 72 | return FourCC{}, nil, err 73 | } 74 | z.totalLen = chunkLen - 4 75 | return FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}, z, nil 76 | } 77 | 78 | // Reader reads chunks from an underlying io.Reader. 79 | type Reader struct { 80 | r io.Reader 81 | err error 82 | 83 | totalLen uint32 84 | chunkLen uint32 85 | 86 | chunkReader *chunkReader 87 | buf [chunkHeaderSize]byte 88 | padded bool 89 | } 90 | 91 | // Next returns the next chunk's ID, length and data. It returns io.EOF if there 92 | // are no more chunks. The io.Reader returned becomes stale after the next Next 93 | // call, and should no longer be used. 94 | // 95 | // It is valid to call Next even if all of the previous chunk's data has not 96 | // been read. 97 | func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error) { 98 | if z.err != nil { 99 | return FourCC{}, 0, nil, z.err 100 | } 101 | 102 | // Drain the rest of the previous chunk. 103 | if z.chunkLen != 0 { 104 | want := z.chunkLen 105 | var got int64 106 | got, z.err = io.Copy(ioutil.Discard, z.chunkReader) 107 | if z.err == nil && uint32(got) != want { 108 | z.err = errShortChunkData 109 | } 110 | if z.err != nil { 111 | return FourCC{}, 0, nil, z.err 112 | } 113 | } 114 | z.chunkReader = nil 115 | if z.padded { 116 | if z.totalLen == 0 { 117 | z.err = errListSubchunkTooLong 118 | return FourCC{}, 0, nil, z.err 119 | } 120 | z.totalLen-- 121 | _, z.err = io.ReadFull(z.r, z.buf[:1]) 122 | if z.err != nil { 123 | if z.err == io.EOF { 124 | z.err = errMissingPaddingByte 125 | } 126 | return FourCC{}, 0, nil, z.err 127 | } 128 | } 129 | 130 | // We are done if we have no more data. 131 | if z.totalLen == 0 { 132 | z.err = io.EOF 133 | return FourCC{}, 0, nil, z.err 134 | } 135 | 136 | // Read the next chunk header. 137 | if z.totalLen < chunkHeaderSize { 138 | z.err = errShortChunkHeader 139 | return FourCC{}, 0, nil, z.err 140 | } 141 | z.totalLen -= chunkHeaderSize 142 | if _, z.err = io.ReadFull(z.r, z.buf[:chunkHeaderSize]); z.err != nil { 143 | if z.err == io.EOF || z.err == io.ErrUnexpectedEOF { 144 | z.err = errShortChunkHeader 145 | } 146 | return FourCC{}, 0, nil, z.err 147 | } 148 | chunkID = FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]} 149 | z.chunkLen = u32(z.buf[4:]) 150 | if z.chunkLen > z.totalLen { 151 | z.err = errListSubchunkTooLong 152 | return FourCC{}, 0, nil, z.err 153 | } 154 | z.padded = z.chunkLen&1 == 1 155 | z.chunkReader = &chunkReader{z} 156 | return chunkID, z.chunkLen, z.chunkReader, nil 157 | } 158 | 159 | type chunkReader struct { 160 | z *Reader 161 | } 162 | 163 | func (c *chunkReader) Read(p []byte) (int, error) { 164 | if c != c.z.chunkReader { 165 | return 0, errStaleReader 166 | } 167 | z := c.z 168 | if z.err != nil { 169 | if z.err == io.EOF { 170 | return 0, errStaleReader 171 | } 172 | return 0, z.err 173 | } 174 | 175 | n := int(z.chunkLen) 176 | if n == 0 { 177 | return 0, io.EOF 178 | } 179 | if n < 0 { 180 | // Converting uint32 to int overflowed. 181 | n = math.MaxInt32 182 | } 183 | if n > len(p) { 184 | n = len(p) 185 | } 186 | n, err := z.r.Read(p[:n]) 187 | z.totalLen -= uint32(n) 188 | z.chunkLen -= uint32(n) 189 | if err != io.EOF { 190 | z.err = err 191 | } 192 | return n, err 193 | } 194 | -------------------------------------------------------------------------------- /riff/riff_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package riff 6 | 7 | import ( 8 | "bytes" 9 | "testing" 10 | ) 11 | 12 | func encodeU32(u uint32) []byte { 13 | return []byte{ 14 | byte(u >> 0), 15 | byte(u >> 8), 16 | byte(u >> 16), 17 | byte(u >> 24), 18 | } 19 | } 20 | 21 | func TestShortChunks(t *testing.T) { 22 | // s is a RIFF(ABCD) with allegedly 256 bytes of data (excluding the 23 | // leading 8-byte "RIFF\x00\x01\x00\x00"). The first chunk of that ABCD 24 | // list is an abcd chunk of length m followed by n zeroes. 25 | for _, m := range []uint32{0, 8, 15, 200, 300} { 26 | for _, n := range []int{0, 1, 2, 7} { 27 | s := []byte("RIFF\x00\x01\x00\x00ABCDabcd") 28 | s = append(s, encodeU32(m)...) 29 | s = append(s, make([]byte, n)...) 30 | _, r, err := NewReader(bytes.NewReader(s)) 31 | if err != nil { 32 | t.Errorf("m=%d, n=%d: NewReader: %v", m, n, err) 33 | continue 34 | } 35 | 36 | _, _, _, err0 := r.Next() 37 | // The total "ABCD" list length is 256 bytes, of which the first 12 38 | // bytes are "ABCDabcd" plus the 4-byte encoding of m. If the 39 | // "abcd" subchunk length (m) plus those 12 bytes is greater than 40 | // the total list length, we have an invalid RIFF, and we expect an 41 | // errListSubchunkTooLong error. 42 | if m+12 > 256 { 43 | if err0 != errListSubchunkTooLong { 44 | t.Errorf("m=%d, n=%d: Next #0: got %v, want %v", m, n, err0, errListSubchunkTooLong) 45 | } 46 | continue 47 | } 48 | // Otherwise, we expect a nil error. 49 | if err0 != nil { 50 | t.Errorf("m=%d, n=%d: Next #0: %v", m, n, err0) 51 | continue 52 | } 53 | 54 | _, _, _, err1 := r.Next() 55 | // If m > 0, then m > n, so that "abcd" subchunk doesn't have m 56 | // bytes of data. If m == 0, then that "abcd" subchunk is OK in 57 | // that it has 0 extra bytes of data, but the next subchunk (8 byte 58 | // header plus body) is missing, as we only have n < 8 more bytes. 59 | want := errShortChunkData 60 | if m == 0 { 61 | want = errShortChunkHeader 62 | } 63 | if err1 != want { 64 | t.Errorf("m=%d, n=%d: Next #1: got %v, want %v", m, n, err1, want) 65 | continue 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /testdata/blue-purple-pink-large.lossless.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink-large.lossless.webp -------------------------------------------------------------------------------- /testdata/blue-purple-pink-large.no-filter.lossy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink-large.no-filter.lossy.webp -------------------------------------------------------------------------------- /testdata/blue-purple-pink-large.no-filter.lossy.webp.ycbcr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink-large.no-filter.lossy.webp.ycbcr.png -------------------------------------------------------------------------------- /testdata/blue-purple-pink-large.normal-filter.lossy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink-large.normal-filter.lossy.webp -------------------------------------------------------------------------------- /testdata/blue-purple-pink-large.normal-filter.lossy.webp.ycbcr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink-large.normal-filter.lossy.webp.ycbcr.png -------------------------------------------------------------------------------- /testdata/blue-purple-pink-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink-large.png -------------------------------------------------------------------------------- /testdata/blue-purple-pink-large.simple-filter.lossy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink-large.simple-filter.lossy.webp -------------------------------------------------------------------------------- /testdata/blue-purple-pink-large.simple-filter.lossy.webp.ycbcr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink-large.simple-filter.lossy.webp.ycbcr.png -------------------------------------------------------------------------------- /testdata/blue-purple-pink.lossless.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink.lossless.webp -------------------------------------------------------------------------------- /testdata/blue-purple-pink.lossy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink.lossy.webp -------------------------------------------------------------------------------- /testdata/blue-purple-pink.lossy.webp.ycbcr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink.lossy.webp.ycbcr.png -------------------------------------------------------------------------------- /testdata/blue-purple-pink.lzwcompressed.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink.lzwcompressed.tiff -------------------------------------------------------------------------------- /testdata/blue-purple-pink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/blue-purple-pink.png -------------------------------------------------------------------------------- /testdata/bw-deflate.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/bw-deflate.tiff -------------------------------------------------------------------------------- /testdata/bw-gopher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/bw-gopher.png -------------------------------------------------------------------------------- /testdata/bw-gopher_ccittGroup3.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/bw-gopher_ccittGroup3.tiff -------------------------------------------------------------------------------- /testdata/bw-gopher_ccittGroup4.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/bw-gopher_ccittGroup4.tiff -------------------------------------------------------------------------------- /testdata/bw-packbits.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/bw-packbits.tiff -------------------------------------------------------------------------------- /testdata/bw-uncompressed.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/bw-uncompressed.tiff -------------------------------------------------------------------------------- /testdata/colormap-0.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/colormap-0.bmp -------------------------------------------------------------------------------- /testdata/colormap-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/colormap-0.png -------------------------------------------------------------------------------- /testdata/colormap-251.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/colormap-251.bmp -------------------------------------------------------------------------------- /testdata/colormap-251.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/colormap-251.png -------------------------------------------------------------------------------- /testdata/colormap.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/colormap.bmp -------------------------------------------------------------------------------- /testdata/colormap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/colormap.png -------------------------------------------------------------------------------- /testdata/go-turns-two-14x18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-14x18.png -------------------------------------------------------------------------------- /testdata/go-turns-two-280x360.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-280x360.jpeg -------------------------------------------------------------------------------- /testdata/go-turns-two-down-ab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-down-ab.png -------------------------------------------------------------------------------- /testdata/go-turns-two-down-bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-down-bl.png -------------------------------------------------------------------------------- /testdata/go-turns-two-down-cr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-down-cr.png -------------------------------------------------------------------------------- /testdata/go-turns-two-down-nn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-down-nn.png -------------------------------------------------------------------------------- /testdata/go-turns-two-rotate-ab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-rotate-ab.png -------------------------------------------------------------------------------- /testdata/go-turns-two-rotate-bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-rotate-bl.png -------------------------------------------------------------------------------- /testdata/go-turns-two-rotate-cr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-rotate-cr.png -------------------------------------------------------------------------------- /testdata/go-turns-two-rotate-nn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-rotate-nn.png -------------------------------------------------------------------------------- /testdata/go-turns-two-up-ab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-up-ab.png -------------------------------------------------------------------------------- /testdata/go-turns-two-up-bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-up-bl.png -------------------------------------------------------------------------------- /testdata/go-turns-two-up-cr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-up-cr.png -------------------------------------------------------------------------------- /testdata/go-turns-two-up-nn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/go-turns-two-up-nn.png -------------------------------------------------------------------------------- /testdata/gopher-doc.1bpp.lossless.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/gopher-doc.1bpp.lossless.webp -------------------------------------------------------------------------------- /testdata/gopher-doc.1bpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/gopher-doc.1bpp.png -------------------------------------------------------------------------------- /testdata/gopher-doc.2bpp.lossless.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/gopher-doc.2bpp.lossless.webp -------------------------------------------------------------------------------- /testdata/gopher-doc.2bpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/gopher-doc.2bpp.png -------------------------------------------------------------------------------- /testdata/gopher-doc.4bpp.lossless.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/gopher-doc.4bpp.lossless.webp -------------------------------------------------------------------------------- /testdata/gopher-doc.4bpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/gopher-doc.4bpp.png -------------------------------------------------------------------------------- /testdata/gopher-doc.8bpp.lossless.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/gopher-doc.8bpp.lossless.webp -------------------------------------------------------------------------------- /testdata/gopher-doc.8bpp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/gopher-doc.8bpp.png -------------------------------------------------------------------------------- /testdata/invalid-palette-ref.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/invalid-palette-ref.tiff -------------------------------------------------------------------------------- /testdata/no_compress.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/no_compress.tiff -------------------------------------------------------------------------------- /testdata/no_rps.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/no_rps.tiff -------------------------------------------------------------------------------- /testdata/testpattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/testpattern.png -------------------------------------------------------------------------------- /testdata/tux-rotate-ab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/tux-rotate-ab.png -------------------------------------------------------------------------------- /testdata/tux-rotate-bl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/tux-rotate-bl.png -------------------------------------------------------------------------------- /testdata/tux-rotate-cr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/tux-rotate-cr.png -------------------------------------------------------------------------------- /testdata/tux-rotate-nn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/tux-rotate-nn.png -------------------------------------------------------------------------------- /testdata/tux.lossless.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/tux.lossless.webp -------------------------------------------------------------------------------- /testdata/tux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/tux.png -------------------------------------------------------------------------------- /testdata/video-001-16bit.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001-16bit.tiff -------------------------------------------------------------------------------- /testdata/video-001-gray-16bit.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001-gray-16bit.tiff -------------------------------------------------------------------------------- /testdata/video-001-gray.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001-gray.tiff -------------------------------------------------------------------------------- /testdata/video-001-paletted.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001-paletted.tiff -------------------------------------------------------------------------------- /testdata/video-001-strip-64.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001-strip-64.tiff -------------------------------------------------------------------------------- /testdata/video-001-tile-64x64.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001-tile-64x64.tiff -------------------------------------------------------------------------------- /testdata/video-001-uncompressed.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001-uncompressed.tiff -------------------------------------------------------------------------------- /testdata/video-001.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001.bmp -------------------------------------------------------------------------------- /testdata/video-001.lossy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001.lossy.webp -------------------------------------------------------------------------------- /testdata/video-001.lossy.webp.ycbcr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001.lossy.webp.ycbcr.png -------------------------------------------------------------------------------- /testdata/video-001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001.png -------------------------------------------------------------------------------- /testdata/video-001.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/video-001.tiff -------------------------------------------------------------------------------- /testdata/yellow_rose-small-v5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose-small-v5.bmp -------------------------------------------------------------------------------- /testdata/yellow_rose-small-v5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose-small-v5.png -------------------------------------------------------------------------------- /testdata/yellow_rose-small.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose-small.bmp -------------------------------------------------------------------------------- /testdata/yellow_rose-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose-small.png -------------------------------------------------------------------------------- /testdata/yellow_rose.lossless.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose.lossless.webp -------------------------------------------------------------------------------- /testdata/yellow_rose.lossy-with-alpha.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose.lossy-with-alpha.webp -------------------------------------------------------------------------------- /testdata/yellow_rose.lossy-with-alpha.webp.nycbcra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose.lossy-with-alpha.webp.nycbcra.png -------------------------------------------------------------------------------- /testdata/yellow_rose.lossy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose.lossy.webp -------------------------------------------------------------------------------- /testdata/yellow_rose.lossy.webp.ycbcr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose.lossy.webp.ycbcr.png -------------------------------------------------------------------------------- /testdata/yellow_rose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/golang/image/ea57e072c14c54059d94abe9e93e8e31721fa22c/testdata/yellow_rose.png -------------------------------------------------------------------------------- /tiff/buffer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | import "io" 8 | 9 | // buffer buffers an io.Reader to satisfy io.ReaderAt. 10 | type buffer struct { 11 | r io.Reader 12 | buf []byte 13 | } 14 | 15 | // fill reads data from b.r until the buffer contains at least end bytes. 16 | func (b *buffer) fill(end int) error { 17 | m := len(b.buf) 18 | if end > m { 19 | if end > cap(b.buf) { 20 | newcap := 1024 21 | for newcap < end { 22 | newcap *= 2 23 | } 24 | newbuf := make([]byte, end, newcap) 25 | copy(newbuf, b.buf) 26 | b.buf = newbuf 27 | } else { 28 | b.buf = b.buf[:end] 29 | } 30 | if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil { 31 | end = m + n 32 | b.buf = b.buf[:end] 33 | return err 34 | } 35 | } 36 | return nil 37 | } 38 | 39 | func (b *buffer) ReadAt(p []byte, off int64) (int, error) { 40 | o := int(off) 41 | end := o + len(p) 42 | if int64(end) != off+int64(len(p)) { 43 | return 0, io.ErrUnexpectedEOF 44 | } 45 | 46 | err := b.fill(end) 47 | return copy(p, b.buf[o:end]), err 48 | } 49 | 50 | // Slice returns a slice of the underlying buffer. The slice contains 51 | // n bytes starting at offset off. 52 | func (b *buffer) Slice(off, n int) ([]byte, error) { 53 | end := off + n 54 | if err := b.fill(end); err != nil { 55 | return nil, err 56 | } 57 | return b.buf[off:end], nil 58 | } 59 | 60 | // newReaderAt converts an io.Reader into an io.ReaderAt. 61 | func newReaderAt(r io.Reader) io.ReaderAt { 62 | if ra, ok := r.(io.ReaderAt); ok { 63 | return ra 64 | } 65 | return &buffer{ 66 | r: r, 67 | buf: make([]byte, 0, 1024), 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tiff/buffer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | import ( 8 | "io" 9 | "strings" 10 | "testing" 11 | ) 12 | 13 | var readAtTests = []struct { 14 | n int 15 | off int64 16 | s string 17 | err error 18 | }{ 19 | {2, 0, "ab", nil}, 20 | {6, 0, "abcdef", nil}, 21 | {3, 3, "def", nil}, 22 | {3, 5, "f", io.EOF}, 23 | {3, 6, "", io.EOF}, 24 | } 25 | 26 | func TestReadAt(t *testing.T) { 27 | r := newReaderAt(strings.NewReader("abcdef")) 28 | b := make([]byte, 10) 29 | for _, test := range readAtTests { 30 | n, err := r.ReadAt(b[:test.n], test.off) 31 | s := string(b[:n]) 32 | if s != test.s || err != test.err { 33 | t.Errorf("buffer.ReadAt(<%v bytes>, %v): got %v, %q; want %v, %q", test.n, test.off, err, s, test.err, test.s) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tiff/compress.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | import ( 8 | "bufio" 9 | "io" 10 | ) 11 | 12 | type byteReader interface { 13 | io.Reader 14 | io.ByteReader 15 | } 16 | 17 | // unpackBits decodes the PackBits-compressed data in src and returns the 18 | // uncompressed data. 19 | // 20 | // The PackBits compression format is described in section 9 (p. 42) 21 | // of the TIFF spec. 22 | func unpackBits(r io.Reader) ([]byte, error) { 23 | buf := make([]byte, 128) 24 | dst := make([]byte, 0, 1024) 25 | br, ok := r.(byteReader) 26 | if !ok { 27 | br = bufio.NewReader(r) 28 | } 29 | 30 | for { 31 | b, err := br.ReadByte() 32 | if err != nil { 33 | if err == io.EOF { 34 | return dst, nil 35 | } 36 | return nil, err 37 | } 38 | code := int(int8(b)) 39 | switch { 40 | case code >= 0: 41 | n, err := io.ReadFull(br, buf[:code+1]) 42 | if err != nil { 43 | return nil, err 44 | } 45 | dst = append(dst, buf[:n]...) 46 | case code == -128: 47 | // No-op. 48 | default: 49 | if b, err = br.ReadByte(); err != nil { 50 | return nil, err 51 | } 52 | for j := 0; j < 1-code; j++ { 53 | buf[j] = b 54 | } 55 | dst = append(dst, buf[:1-code]...) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tiff/consts.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | // A tiff image file contains one or more images. The metadata 8 | // of each image is contained in an Image File Directory (IFD), 9 | // which contains entries of 12 bytes each and is described 10 | // on page 14-16 of the specification. An IFD entry consists of 11 | // 12 | // - a tag, which describes the signification of the entry, 13 | // - the data type and length of the entry, 14 | // - the data itself or a pointer to it if it is more than 4 bytes. 15 | // 16 | // The presence of a length means that each IFD is effectively an array. 17 | 18 | const ( 19 | leHeader = "II\x2A\x00" // Header for little-endian files. 20 | beHeader = "MM\x00\x2A" // Header for big-endian files. 21 | 22 | ifdLen = 12 // Length of an IFD entry in bytes. 23 | ) 24 | 25 | // Data types (p. 14-16 of the spec). 26 | const ( 27 | dtByte = 1 28 | dtASCII = 2 29 | dtShort = 3 30 | dtLong = 4 31 | dtRational = 5 32 | ) 33 | 34 | // The length of one instance of each data type in bytes. 35 | var lengths = [...]uint32{0, 1, 1, 2, 4, 8} 36 | 37 | // Tags (see p. 28-41 of the spec). 38 | const ( 39 | tImageWidth = 256 40 | tImageLength = 257 41 | tBitsPerSample = 258 42 | tCompression = 259 43 | tPhotometricInterpretation = 262 44 | 45 | tFillOrder = 266 46 | 47 | tStripOffsets = 273 48 | tSamplesPerPixel = 277 49 | tRowsPerStrip = 278 50 | tStripByteCounts = 279 51 | 52 | tT4Options = 292 // CCITT Group 3 options, a set of 32 flag bits. 53 | tT6Options = 293 // CCITT Group 4 options, a set of 32 flag bits. 54 | 55 | tTileWidth = 322 56 | tTileLength = 323 57 | tTileOffsets = 324 58 | tTileByteCounts = 325 59 | 60 | tXResolution = 282 61 | tYResolution = 283 62 | tResolutionUnit = 296 63 | 64 | tPredictor = 317 65 | tColorMap = 320 66 | tExtraSamples = 338 67 | tSampleFormat = 339 68 | ) 69 | 70 | // Compression types (defined in various places in the spec and supplements). 71 | const ( 72 | cNone = 1 73 | cCCITT = 2 74 | cG3 = 3 // Group 3 Fax. 75 | cG4 = 4 // Group 4 Fax. 76 | cLZW = 5 77 | cJPEGOld = 6 // Superseded by cJPEG. 78 | cJPEG = 7 79 | cDeflate = 8 // zlib compression. 80 | cPackBits = 32773 81 | cDeflateOld = 32946 // Superseded by cDeflate. 82 | ) 83 | 84 | // Photometric interpretation values (see p. 37 of the spec). 85 | const ( 86 | pWhiteIsZero = 0 87 | pBlackIsZero = 1 88 | pRGB = 2 89 | pPaletted = 3 90 | pTransMask = 4 // transparency mask 91 | pCMYK = 5 92 | pYCbCr = 6 93 | pCIELab = 8 94 | ) 95 | 96 | // Values for the tPredictor tag (page 64-65 of the spec). 97 | const ( 98 | prNone = 1 99 | prHorizontal = 2 100 | ) 101 | 102 | // Values for the tResolutionUnit tag (page 18). 103 | const ( 104 | resNone = 1 105 | resPerInch = 2 // Dots per inch. 106 | resPerCM = 3 // Dots per centimeter. 107 | ) 108 | 109 | // imageMode represents the mode of the image. 110 | type imageMode int 111 | 112 | const ( 113 | mBilevel imageMode = iota 114 | mPaletted 115 | mGray 116 | mGrayInvert 117 | mRGB 118 | mRGBA 119 | mNRGBA 120 | mCMYK 121 | ) 122 | 123 | // CompressionType describes the type of compression used in Options. 124 | type CompressionType int 125 | 126 | // Constants for supported compression types. 127 | const ( 128 | Uncompressed CompressionType = iota 129 | Deflate 130 | LZW 131 | CCITTGroup3 132 | CCITTGroup4 133 | ) 134 | 135 | // specValue returns the compression type constant from the TIFF spec that 136 | // is equivalent to c. 137 | func (c CompressionType) specValue() uint32 { 138 | switch c { 139 | case LZW: 140 | return cLZW 141 | case Deflate: 142 | return cDeflate 143 | case CCITTGroup3: 144 | return cG3 145 | case CCITTGroup4: 146 | return cG4 147 | } 148 | return cNone 149 | } 150 | -------------------------------------------------------------------------------- /tiff/fuzz.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build gofuzz 6 | 7 | package tiff 8 | 9 | import "bytes" 10 | 11 | func Fuzz(data []byte) int { 12 | cfg, err := DecodeConfig(bytes.NewReader(data)) 13 | if err != nil { 14 | return 0 15 | } 16 | if cfg.Width*cfg.Height > 1e6 { 17 | return 0 18 | } 19 | img, err := Decode(bytes.NewReader(data)) 20 | if err != nil { 21 | return 0 22 | } 23 | var w bytes.Buffer 24 | err = Encode(&w, img, nil) 25 | if err != nil { 26 | panic(err) 27 | } 28 | return 1 29 | } 30 | -------------------------------------------------------------------------------- /tiff/writer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package tiff 6 | 7 | import ( 8 | "bytes" 9 | "image" 10 | "io/ioutil" 11 | "os" 12 | "testing" 13 | ) 14 | 15 | var roundtripTests = []struct { 16 | filename string 17 | opts *Options 18 | }{ 19 | {"video-001.tiff", nil}, 20 | {"video-001-16bit.tiff", nil}, 21 | {"video-001-gray.tiff", nil}, 22 | {"video-001-gray-16bit.tiff", nil}, 23 | {"video-001-paletted.tiff", nil}, 24 | {"bw-packbits.tiff", nil}, 25 | {"video-001.tiff", &Options{Predictor: true}}, 26 | {"video-001.tiff", &Options{Compression: Deflate}}, 27 | {"video-001.tiff", &Options{Predictor: true, Compression: Deflate}}, 28 | } 29 | 30 | func openImage(filename string) (image.Image, error) { 31 | f, err := os.Open(testdataDir + filename) 32 | if err != nil { 33 | return nil, err 34 | } 35 | defer f.Close() 36 | return Decode(f) 37 | } 38 | 39 | func TestRoundtrip(t *testing.T) { 40 | for _, rt := range roundtripTests { 41 | img, err := openImage(rt.filename) 42 | if err != nil { 43 | t.Fatal(err) 44 | } 45 | 46 | out := new(bytes.Buffer) 47 | err = Encode(out, img, rt.opts) 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | 52 | img2, err := Decode(&buffer{buf: out.Bytes()}) 53 | if err != nil { 54 | t.Fatal(err) 55 | } 56 | compare(t, img, img2) 57 | } 58 | } 59 | 60 | // TestRoundtrip2 tests that encoding and decoding an image whose 61 | // origin is not (0, 0) gives the same thing. 62 | func TestRoundtrip2(t *testing.T) { 63 | m0 := image.NewRGBA(image.Rect(3, 4, 9, 8)) 64 | for i := range m0.Pix { 65 | m0.Pix[i] = byte(i) 66 | } 67 | out := new(bytes.Buffer) 68 | if err := Encode(out, m0, nil); err != nil { 69 | t.Fatal(err) 70 | } 71 | m1, err := Decode(&buffer{buf: out.Bytes()}) 72 | if err != nil { 73 | t.Fatal(err) 74 | } 75 | compare(t, m0, m1) 76 | } 77 | 78 | func TestUnsupported(t *testing.T) { 79 | img := image.NewGray(image.Rect(0, 0, 1, 1)) 80 | out := new(bytes.Buffer) 81 | err := Encode(out, img, &Options{Compression: LZW}) 82 | if err == nil { 83 | t.Error("tiff.Encode(LZW): no error returned, expected an error") 84 | } 85 | } 86 | 87 | func benchmarkEncode(b *testing.B, name string, pixelSize int) { 88 | b.Helper() 89 | img, err := openImage(name) 90 | if err != nil { 91 | b.Fatal(err) 92 | } 93 | s := img.Bounds().Size() 94 | b.SetBytes(int64(s.X * s.Y * pixelSize)) 95 | b.ResetTimer() 96 | for i := 0; i < b.N; i++ { 97 | Encode(ioutil.Discard, img, nil) 98 | } 99 | } 100 | 101 | func BenchmarkEncode(b *testing.B) { benchmarkEncode(b, "video-001.tiff", 4) } 102 | func BenchmarkEncodePaletted(b *testing.B) { benchmarkEncode(b, "video-001-paletted.tiff", 1) } 103 | func BenchmarkEncodeGray(b *testing.B) { benchmarkEncode(b, "video-001-gray.tiff", 1) } 104 | func BenchmarkEncodeGray16(b *testing.B) { benchmarkEncode(b, "video-001-gray-16bit.tiff", 2) } 105 | func BenchmarkEncodeRGBA(b *testing.B) { benchmarkEncode(b, "video-001.tiff", 4) } 106 | func BenchmarkEncodeRGBA64(b *testing.B) { benchmarkEncode(b, "video-001-16bit.tiff", 8) } 107 | -------------------------------------------------------------------------------- /vector/acc_amd64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build !appengine && gc && !noasm 6 | 7 | package vector 8 | 9 | func haveSSE4_1() bool 10 | 11 | var haveAccumulateSIMD = haveSSE4_1() 12 | 13 | //go:noescape 14 | func fixedAccumulateOpOverSIMD(dst []uint8, src []uint32) 15 | 16 | //go:noescape 17 | func fixedAccumulateOpSrcSIMD(dst []uint8, src []uint32) 18 | 19 | //go:noescape 20 | func fixedAccumulateMaskSIMD(buf []uint32) 21 | 22 | //go:noescape 23 | func floatingAccumulateOpOverSIMD(dst []uint8, src []float32) 24 | 25 | //go:noescape 26 | func floatingAccumulateOpSrcSIMD(dst []uint8, src []float32) 27 | 28 | //go:noescape 29 | func floatingAccumulateMaskSIMD(dst []uint32, src []float32) 30 | -------------------------------------------------------------------------------- /vector/acc_other.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build !amd64 || appengine || !gc || noasm 6 | 7 | package vector 8 | 9 | const haveAccumulateSIMD = false 10 | 11 | func fixedAccumulateOpOverSIMD(dst []uint8, src []uint32) {} 12 | func fixedAccumulateOpSrcSIMD(dst []uint8, src []uint32) {} 13 | func fixedAccumulateMaskSIMD(buf []uint32) {} 14 | func floatingAccumulateOpOverSIMD(dst []uint8, src []float32) {} 15 | func floatingAccumulateOpSrcSIMD(dst []uint8, src []float32) {} 16 | func floatingAccumulateMaskSIMD(dst []uint32, src []float32) {} 17 | -------------------------------------------------------------------------------- /vector/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package vector_test 6 | 7 | import ( 8 | "image" 9 | "image/draw" 10 | "os" 11 | 12 | "golang.org/x/image/vector" 13 | ) 14 | 15 | func Example_draw() { 16 | const ( 17 | width = 30 18 | height = 20 19 | ) 20 | 21 | // Define a closed shape with three edges: two linear and one quadratic. 22 | // One of its vertices is at the top-left corner of the (1, 2) pixel, which 23 | // is also the bottom-right corner of the (0, 1) pixel. 24 | // 25 | // Co-ordinates can be floating point numbers, not just integers. They can 26 | // also be outside the vector.Rasterizer's dimensions. The shapes will be 27 | // clipped during rasterization. 28 | r := vector.NewRasterizer(width, height) 29 | r.DrawOp = draw.Src 30 | r.MoveTo(1, 2) 31 | r.LineTo(20, 2) 32 | r.QuadTo(40.5, 15, 10, 20) 33 | r.ClosePath() 34 | 35 | // Finish the rasterization: the conversion from vector graphics (shapes) 36 | // to raster graphics (pixels). Co-ordinates are now integers. 37 | dst := image.NewAlpha(image.Rect(0, 0, width, height)) 38 | r.Draw(dst, dst.Bounds(), image.Opaque, image.Point{}) 39 | 40 | // Visualize the pixels. 41 | const asciiArt = ".++8" 42 | buf := make([]byte, 0, height*(width+1)) 43 | for y := 0; y < height; y++ { 44 | for x := 0; x < width; x++ { 45 | a := dst.AlphaAt(x, y).A 46 | buf = append(buf, asciiArt[a>>6]) 47 | } 48 | buf = append(buf, '\n') 49 | } 50 | os.Stdout.Write(buf) 51 | 52 | // Output: 53 | // .............................. 54 | // .............................. 55 | // .8888888888888888888+......... 56 | // .+88888888888888888888+....... 57 | // ..888888888888888888888+...... 58 | // ..+888888888888888888888+..... 59 | // ...8888888888888888888888+.... 60 | // ...+8888888888888888888888+... 61 | // ....88888888888888888888888+.. 62 | // ....+88888888888888888888888.. 63 | // .....88888888888888888888888.. 64 | // .....+8888888888888888888888.. 65 | // ......8888888888888888888888.. 66 | // ......+88888888888888888888+.. 67 | // .......8888888888888888888+... 68 | // .......+88888888888888888..... 69 | // ........888888888888888+...... 70 | // ........+88888888888+......... 71 | // .........8888888++............ 72 | // .........+8+++................ 73 | } 74 | -------------------------------------------------------------------------------- /vector/gen_acc_amd64.s.tmpl: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build !appengine 6 | // +build gc 7 | // +build !noasm 8 | 9 | #include "textflag.h" 10 | 11 | // fl is short for floating point math. fx is short for fixed point math. 12 | 13 | DATA flAlmost65536<>+0x00(SB)/8, $0x477fffff477fffff 14 | DATA flAlmost65536<>+0x08(SB)/8, $0x477fffff477fffff 15 | DATA flOne<>+0x00(SB)/8, $0x3f8000003f800000 16 | DATA flOne<>+0x08(SB)/8, $0x3f8000003f800000 17 | DATA flSignMask<>+0x00(SB)/8, $0x7fffffff7fffffff 18 | DATA flSignMask<>+0x08(SB)/8, $0x7fffffff7fffffff 19 | 20 | // scatterAndMulBy0x101 is a PSHUFB mask that brings the low four bytes of an 21 | // XMM register to the low byte of that register's four uint32 values. It 22 | // duplicates those bytes, effectively multiplying each uint32 by 0x101. 23 | // 24 | // It transforms a little-endian 16-byte XMM value from 25 | // ijkl???????????? 26 | // to 27 | // ii00jj00kk00ll00 28 | DATA scatterAndMulBy0x101<>+0x00(SB)/8, $0x8080010180800000 29 | DATA scatterAndMulBy0x101<>+0x08(SB)/8, $0x8080030380800202 30 | 31 | // gather is a PSHUFB mask that brings the second-lowest byte of the XMM 32 | // register's four uint32 values to the low four bytes of that register. 33 | // 34 | // It transforms a little-endian 16-byte XMM value from 35 | // ?i???j???k???l?? 36 | // to 37 | // ijkl000000000000 38 | DATA gather<>+0x00(SB)/8, $0x808080800d090501 39 | DATA gather<>+0x08(SB)/8, $0x8080808080808080 40 | 41 | DATA fxAlmost65536<>+0x00(SB)/8, $0x0000ffff0000ffff 42 | DATA fxAlmost65536<>+0x08(SB)/8, $0x0000ffff0000ffff 43 | DATA inverseFFFF<>+0x00(SB)/8, $0x8000800180008001 44 | DATA inverseFFFF<>+0x08(SB)/8, $0x8000800180008001 45 | 46 | GLOBL flAlmost65536<>(SB), (NOPTR+RODATA), $16 47 | GLOBL flOne<>(SB), (NOPTR+RODATA), $16 48 | GLOBL flSignMask<>(SB), (NOPTR+RODATA), $16 49 | GLOBL scatterAndMulBy0x101<>(SB), (NOPTR+RODATA), $16 50 | GLOBL gather<>(SB), (NOPTR+RODATA), $16 51 | GLOBL fxAlmost65536<>(SB), (NOPTR+RODATA), $16 52 | GLOBL inverseFFFF<>(SB), (NOPTR+RODATA), $16 53 | 54 | // func haveSSE4_1() bool 55 | TEXT ·haveSSE4_1(SB), NOSPLIT, $0 56 | MOVQ $1, AX 57 | CPUID 58 | SHRQ $19, CX 59 | ANDQ $1, CX 60 | MOVB CX, ret+0(FP) 61 | RET 62 | 63 | // ---------------------------------------------------------------------------- 64 | 65 | // func {{.LongName}}SIMD({{.Args}}) 66 | // 67 | // XMM registers. Variable names are per 68 | // https://github.com/google/font-rs/blob/master/src/accumulate.c 69 | // 70 | // xmm0 scratch 71 | // xmm1 x 72 | // xmm2 y, z 73 | // xmm3 {{.XMM3}} 74 | // xmm4 {{.XMM4}} 75 | // xmm5 {{.XMM5}} 76 | // xmm6 {{.XMM6}} 77 | // xmm7 offset 78 | // xmm8 {{.XMM8}} 79 | // xmm9 {{.XMM9}} 80 | // xmm10 {{.XMM10}} 81 | TEXT ·{{.LongName}}SIMD(SB), NOSPLIT, ${{.FrameSize}}-{{.ArgsSize}} 82 | {{.LoadArgs}} 83 | 84 | // R10 = len(src) &^ 3 85 | // R11 = len(src) 86 | MOVQ R10, R11 87 | ANDQ $-4, R10 88 | 89 | {{.Setup}} 90 | 91 | {{.LoadXMMRegs}} 92 | 93 | // offset := XMM(0x00000000 repeated four times) // Cumulative sum. 94 | XORPS X7, X7 95 | 96 | // i := 0 97 | MOVQ $0, R9 98 | 99 | {{.ShortName}}Loop4: 100 | // for i < (len(src) &^ 3) 101 | CMPQ R9, R10 102 | JAE {{.ShortName}}Loop1 103 | 104 | // x = XMM(s0, s1, s2, s3) 105 | // 106 | // Where s0 is src[i+0], s1 is src[i+1], etc. 107 | MOVOU (SI), X1 108 | 109 | // scratch = XMM(0, s0, s1, s2) 110 | // x += scratch // yields x == XMM(s0, s0+s1, s1+s2, s2+s3) 111 | MOVOU X1, X0 112 | PSLLO $4, X0 113 | {{.Add}} X0, X1 114 | 115 | // scratch = XMM(0, 0, 0, 0) 116 | // scratch = XMM(scratch@0, scratch@0, x@0, x@1) // yields scratch == XMM(0, 0, s0, s0+s1) 117 | // x += scratch // yields x == XMM(s0, s0+s1, s0+s1+s2, s0+s1+s2+s3) 118 | XORPS X0, X0 119 | SHUFPS $0x40, X1, X0 120 | {{.Add}} X0, X1 121 | 122 | // x += offset 123 | {{.Add}} X7, X1 124 | 125 | {{.ClampAndScale}} 126 | 127 | {{.ConvertToInt32}} 128 | 129 | {{.Store4}} 130 | 131 | // offset = XMM(x@3, x@3, x@3, x@3) 132 | MOVOU X1, X7 133 | SHUFPS $0xff, X1, X7 134 | 135 | // i += 4 136 | // dst = dst[4:] 137 | // src = src[4:] 138 | ADDQ $4, R9 139 | ADDQ ${{.DstElemSize4}}, DI 140 | ADDQ $16, SI 141 | JMP {{.ShortName}}Loop4 142 | 143 | {{.ShortName}}Loop1: 144 | // for i < len(src) 145 | CMPQ R9, R11 146 | JAE {{.ShortName}}End 147 | 148 | // x = src[i] + offset 149 | MOVL (SI), X1 150 | {{.Add}} X7, X1 151 | 152 | {{.ClampAndScale}} 153 | 154 | {{.ConvertToInt32}} 155 | 156 | {{.Store1}} 157 | 158 | // offset = x 159 | MOVOU X1, X7 160 | 161 | // i += 1 162 | // dst = dst[1:] 163 | // src = src[1:] 164 | ADDQ $1, R9 165 | ADDQ ${{.DstElemSize1}}, DI 166 | ADDQ $4, SI 167 | JMP {{.ShortName}}Loop1 168 | 169 | {{.ShortName}}End: 170 | RET 171 | -------------------------------------------------------------------------------- /vector/raster_floating.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package vector 6 | 7 | // This file contains a floating point math implementation of the vector 8 | // graphics rasterizer. 9 | 10 | import ( 11 | "math" 12 | ) 13 | 14 | func floatingMax(x, y float32) float32 { 15 | if x > y { 16 | return x 17 | } 18 | return y 19 | } 20 | 21 | func floatingMin(x, y float32) float32 { 22 | if x < y { 23 | return x 24 | } 25 | return y 26 | } 27 | 28 | func floatingFloor(x float32) int32 { return int32(math.Floor(float64(x))) } 29 | func floatingCeil(x float32) int32 { return int32(math.Ceil(float64(x))) } 30 | 31 | func (z *Rasterizer) floatingLineTo(bx, by float32) { 32 | ax, ay := z.penX, z.penY 33 | z.penX, z.penY = bx, by 34 | dir := float32(1) 35 | if ay > by { 36 | dir, ax, ay, bx, by = -1, bx, by, ax, ay 37 | } 38 | // Horizontal line segments yield no change in coverage. Almost horizontal 39 | // segments would yield some change, in ideal math, but the computation 40 | // further below, involving 1 / (by - ay), is unstable in floating point 41 | // math, so we treat the segment as if it was perfectly horizontal. 42 | if by-ay <= 0.000001 { 43 | return 44 | } 45 | dxdy := (bx - ax) / (by - ay) 46 | 47 | x := ax 48 | y := floatingFloor(ay) 49 | yMax := floatingCeil(by) 50 | if yMax > int32(z.size.Y) { 51 | yMax = int32(z.size.Y) 52 | } 53 | width := int32(z.size.X) 54 | 55 | for ; y < yMax; y++ { 56 | dy := floatingMin(float32(y+1), by) - floatingMax(float32(y), ay) 57 | 58 | // The "float32" in expressions like "float32(foo*bar)" here and below 59 | // look redundant, since foo and bar already have type float32, but are 60 | // explicit in order to disable the compiler's Fused Multiply Add (FMA) 61 | // instruction selection, which can improve performance but can result 62 | // in different rounding errors in floating point computations. 63 | // 64 | // This package aims to have bit-exact identical results across all 65 | // GOARCHes, and across pure Go code and assembly, so it disables FMA. 66 | // 67 | // See the discussion at 68 | // https://groups.google.com/d/topic/golang-dev/Sti0bl2xUXQ/discussion 69 | xNext := x + float32(dy*dxdy) 70 | if y < 0 { 71 | x = xNext 72 | continue 73 | } 74 | buf := z.bufF32[y*width:] 75 | d := float32(dy * dir) 76 | x0, x1 := x, xNext 77 | if x > xNext { 78 | x0, x1 = x1, x0 79 | } 80 | x0i := floatingFloor(x0) 81 | x0Floor := float32(x0i) 82 | x1i := floatingCeil(x1) 83 | x1Ceil := float32(x1i) 84 | 85 | if x1i <= x0i+1 { 86 | xmf := float32(0.5*(x+xNext)) - x0Floor 87 | if i := clamp(x0i+0, width); i < uint(len(buf)) { 88 | buf[i] += d - float32(d*xmf) 89 | } 90 | if i := clamp(x0i+1, width); i < uint(len(buf)) { 91 | buf[i] += float32(d * xmf) 92 | } 93 | } else { 94 | s := 1 / (x1 - x0) 95 | x0f := x0 - x0Floor 96 | oneMinusX0f := 1 - x0f 97 | a0 := float32(0.5 * s * oneMinusX0f * oneMinusX0f) 98 | x1f := x1 - x1Ceil + 1 99 | am := float32(0.5 * s * x1f * x1f) 100 | 101 | if i := clamp(x0i, width); i < uint(len(buf)) { 102 | buf[i] += float32(d * a0) 103 | } 104 | 105 | if x1i == x0i+2 { 106 | if i := clamp(x0i+1, width); i < uint(len(buf)) { 107 | buf[i] += float32(d * (1 - a0 - am)) 108 | } 109 | } else { 110 | a1 := float32(s * (1.5 - x0f)) 111 | if i := clamp(x0i+1, width); i < uint(len(buf)) { 112 | buf[i] += float32(d * (a1 - a0)) 113 | } 114 | dTimesS := float32(d * s) 115 | for xi := x0i + 2; xi < x1i-1; xi++ { 116 | if i := clamp(xi, width); i < uint(len(buf)) { 117 | buf[i] += dTimesS 118 | } 119 | } 120 | a2 := a1 + float32(s*float32(x1i-x0i-3)) 121 | if i := clamp(x1i-1, width); i < uint(len(buf)) { 122 | buf[i] += float32(d * (1 - a2 - am)) 123 | } 124 | } 125 | 126 | if i := clamp(x1i, width); i < uint(len(buf)) { 127 | buf[i] += float32(d * am) 128 | } 129 | } 130 | 131 | x = xNext 132 | } 133 | } 134 | 135 | const ( 136 | // almost256 scales a floating point value in the range [0, 1] to a uint8 137 | // value in the range [0x00, 0xff]. 138 | // 139 | // 255 is too small. Floating point math accumulates rounding errors, so a 140 | // fully covered src value that would in ideal math be float32(1) might be 141 | // float32(1-ε), and uint8(255 * (1-ε)) would be 0xfe instead of 0xff. The 142 | // uint8 conversion rounds to zero, not to nearest. 143 | // 144 | // 256 is too big. If we multiplied by 256, below, then a fully covered src 145 | // value of float32(1) would translate to uint8(256 * 1), which can be 0x00 146 | // instead of the maximal value 0xff. 147 | // 148 | // math.Float32bits(almost256) is 0x437fffff. 149 | almost256 = 255.99998 150 | 151 | // almost65536 scales a floating point value in the range [0, 1] to a 152 | // uint16 value in the range [0x0000, 0xffff]. 153 | // 154 | // math.Float32bits(almost65536) is 0x477fffff. 155 | almost65536 = almost256 * 256 156 | ) 157 | 158 | func floatingAccumulateOpOver(dst []uint8, src []float32) { 159 | // Sanity check that len(dst) >= len(src). 160 | if len(dst) < len(src) { 161 | return 162 | } 163 | 164 | acc := float32(0) 165 | for i, v := range src { 166 | acc += v 167 | a := acc 168 | if a < 0 { 169 | a = -a 170 | } 171 | if a > 1 { 172 | a = 1 173 | } 174 | // This algorithm comes from the standard library's image/draw package. 175 | dstA := uint32(dst[i]) * 0x101 176 | maskA := uint32(almost65536 * a) 177 | outA := dstA*(0xffff-maskA)/0xffff + maskA 178 | dst[i] = uint8(outA >> 8) 179 | } 180 | } 181 | 182 | func floatingAccumulateOpSrc(dst []uint8, src []float32) { 183 | // Sanity check that len(dst) >= len(src). 184 | if len(dst) < len(src) { 185 | return 186 | } 187 | 188 | acc := float32(0) 189 | for i, v := range src { 190 | acc += v 191 | a := acc 192 | if a < 0 { 193 | a = -a 194 | } 195 | if a > 1 { 196 | a = 1 197 | } 198 | dst[i] = uint8(almost256 * a) 199 | } 200 | } 201 | 202 | func floatingAccumulateMask(dst []uint32, src []float32) { 203 | // Sanity check that len(dst) >= len(src). 204 | if len(dst) < len(src) { 205 | return 206 | } 207 | 208 | acc := float32(0) 209 | for i, v := range src { 210 | acc += v 211 | a := acc 212 | if a < 0 { 213 | a = -a 214 | } 215 | if a > 1 { 216 | a = 1 217 | } 218 | dst[i] = uint32(almost65536 * a) 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /vp8/idct.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package vp8 6 | 7 | // This file implements the inverse Discrete Cosine Transform and the inverse 8 | // Walsh Hadamard Transform (WHT), as specified in sections 14.3 and 14.4. 9 | 10 | func clip8(i int32) uint8 { 11 | if i < 0 { 12 | return 0 13 | } 14 | if i > 255 { 15 | return 255 16 | } 17 | return uint8(i) 18 | } 19 | 20 | func (z *Decoder) inverseDCT4(y, x, coeffBase int) { 21 | const ( 22 | c1 = 85627 // 65536 * cos(pi/8) * sqrt(2). 23 | c2 = 35468 // 65536 * sin(pi/8) * sqrt(2). 24 | ) 25 | var m [4][4]int32 26 | for i := 0; i < 4; i++ { 27 | a := int32(z.coeff[coeffBase+0]) + int32(z.coeff[coeffBase+8]) 28 | b := int32(z.coeff[coeffBase+0]) - int32(z.coeff[coeffBase+8]) 29 | c := (int32(z.coeff[coeffBase+4])*c2)>>16 - (int32(z.coeff[coeffBase+12])*c1)>>16 30 | d := (int32(z.coeff[coeffBase+4])*c1)>>16 + (int32(z.coeff[coeffBase+12])*c2)>>16 31 | m[i][0] = a + d 32 | m[i][1] = b + c 33 | m[i][2] = b - c 34 | m[i][3] = a - d 35 | coeffBase++ 36 | } 37 | for j := 0; j < 4; j++ { 38 | dc := m[0][j] + 4 39 | a := dc + m[2][j] 40 | b := dc - m[2][j] 41 | c := (m[1][j]*c2)>>16 - (m[3][j]*c1)>>16 42 | d := (m[1][j]*c1)>>16 + (m[3][j]*c2)>>16 43 | z.ybr[y+j][x+0] = clip8(int32(z.ybr[y+j][x+0]) + (a+d)>>3) 44 | z.ybr[y+j][x+1] = clip8(int32(z.ybr[y+j][x+1]) + (b+c)>>3) 45 | z.ybr[y+j][x+2] = clip8(int32(z.ybr[y+j][x+2]) + (b-c)>>3) 46 | z.ybr[y+j][x+3] = clip8(int32(z.ybr[y+j][x+3]) + (a-d)>>3) 47 | } 48 | } 49 | 50 | func (z *Decoder) inverseDCT4DCOnly(y, x, coeffBase int) { 51 | dc := (int32(z.coeff[coeffBase+0]) + 4) >> 3 52 | for j := 0; j < 4; j++ { 53 | for i := 0; i < 4; i++ { 54 | z.ybr[y+j][x+i] = clip8(int32(z.ybr[y+j][x+i]) + dc) 55 | } 56 | } 57 | } 58 | 59 | func (z *Decoder) inverseDCT8(y, x, coeffBase int) { 60 | z.inverseDCT4(y+0, x+0, coeffBase+0*16) 61 | z.inverseDCT4(y+0, x+4, coeffBase+1*16) 62 | z.inverseDCT4(y+4, x+0, coeffBase+2*16) 63 | z.inverseDCT4(y+4, x+4, coeffBase+3*16) 64 | } 65 | 66 | func (z *Decoder) inverseDCT8DCOnly(y, x, coeffBase int) { 67 | z.inverseDCT4DCOnly(y+0, x+0, coeffBase+0*16) 68 | z.inverseDCT4DCOnly(y+0, x+4, coeffBase+1*16) 69 | z.inverseDCT4DCOnly(y+4, x+0, coeffBase+2*16) 70 | z.inverseDCT4DCOnly(y+4, x+4, coeffBase+3*16) 71 | } 72 | 73 | func (d *Decoder) inverseWHT16() { 74 | var m [16]int32 75 | for i := 0; i < 4; i++ { 76 | a0 := int32(d.coeff[384+0+i]) + int32(d.coeff[384+12+i]) 77 | a1 := int32(d.coeff[384+4+i]) + int32(d.coeff[384+8+i]) 78 | a2 := int32(d.coeff[384+4+i]) - int32(d.coeff[384+8+i]) 79 | a3 := int32(d.coeff[384+0+i]) - int32(d.coeff[384+12+i]) 80 | m[0+i] = a0 + a1 81 | m[8+i] = a0 - a1 82 | m[4+i] = a3 + a2 83 | m[12+i] = a3 - a2 84 | } 85 | out := 0 86 | for i := 0; i < 4; i++ { 87 | dc := m[0+i*4] + 3 88 | a0 := dc + m[3+i*4] 89 | a1 := m[1+i*4] + m[2+i*4] 90 | a2 := m[1+i*4] - m[2+i*4] 91 | a3 := dc - m[3+i*4] 92 | d.coeff[out+0] = int16((a0 + a1) >> 3) 93 | d.coeff[out+16] = int16((a3 + a2) >> 3) 94 | d.coeff[out+32] = int16((a0 - a1) >> 3) 95 | d.coeff[out+48] = int16((a3 - a2) >> 3) 96 | out += 64 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /vp8/partition.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package vp8 6 | 7 | // Each VP8 frame consists of between 2 and 9 bitstream partitions. 8 | // Each partition is byte-aligned and is independently arithmetic-encoded. 9 | // 10 | // This file implements decoding a partition's bitstream, as specified in 11 | // chapter 7. The implementation follows libwebp's approach instead of the 12 | // specification's reference C implementation. For example, we use a look-up 13 | // table instead of a for loop to recalibrate the encoded range. 14 | 15 | var ( 16 | lutShift = [127]uint8{ 17 | 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 18 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 19 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 20 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 24 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25 | } 26 | lutRangeM1 = [127]uint8{ 27 | 127, 28 | 127, 191, 29 | 127, 159, 191, 223, 30 | 127, 143, 159, 175, 191, 207, 223, 239, 31 | 127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, 247, 32 | 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 183, 187, 33 | 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 34 | 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 35 | 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 36 | 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 37 | 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 38 | } 39 | ) 40 | 41 | // uniformProb represents a 50% probability that the next bit is 0. 42 | const uniformProb = 128 43 | 44 | // partition holds arithmetic-coded bits. 45 | type partition struct { 46 | // buf is the input bytes. 47 | buf []byte 48 | // r is how many of buf's bytes have been consumed. 49 | r int 50 | // rangeM1 is range minus 1, where range is in the arithmetic coding sense, 51 | // not the Go language sense. 52 | rangeM1 uint32 53 | // bits and nBits hold those bits shifted out of buf but not yet consumed. 54 | bits uint32 55 | nBits uint8 56 | // unexpectedEOF tells whether we tried to read past buf. 57 | unexpectedEOF bool 58 | } 59 | 60 | // init initializes the partition. 61 | func (p *partition) init(buf []byte) { 62 | p.buf = buf 63 | p.r = 0 64 | p.rangeM1 = 254 65 | p.bits = 0 66 | p.nBits = 0 67 | p.unexpectedEOF = false 68 | } 69 | 70 | // readBit returns the next bit. 71 | func (p *partition) readBit(prob uint8) bool { 72 | if p.nBits < 8 { 73 | if p.r >= len(p.buf) { 74 | p.unexpectedEOF = true 75 | return false 76 | } 77 | // Expression split for 386 compiler. 78 | x := uint32(p.buf[p.r]) 79 | p.bits |= x << (8 - p.nBits) 80 | p.r++ 81 | p.nBits += 8 82 | } 83 | split := (p.rangeM1*uint32(prob))>>8 + 1 84 | bit := p.bits >= split<<8 85 | if bit { 86 | p.rangeM1 -= split 87 | p.bits -= split << 8 88 | } else { 89 | p.rangeM1 = split - 1 90 | } 91 | if p.rangeM1 < 127 { 92 | shift := lutShift[p.rangeM1] 93 | p.rangeM1 = uint32(lutRangeM1[p.rangeM1]) 94 | p.bits <<= shift 95 | p.nBits -= shift 96 | } 97 | return bit 98 | } 99 | 100 | // readUint returns the next n-bit unsigned integer. 101 | func (p *partition) readUint(prob, n uint8) uint32 { 102 | var u uint32 103 | for n > 0 { 104 | n-- 105 | if p.readBit(prob) { 106 | u |= 1 << n 107 | } 108 | } 109 | return u 110 | } 111 | 112 | // readInt returns the next n-bit signed integer. 113 | func (p *partition) readInt(prob, n uint8) int32 { 114 | u := p.readUint(prob, n) 115 | b := p.readBit(prob) 116 | if b { 117 | return -int32(u) 118 | } 119 | return int32(u) 120 | } 121 | 122 | // readOptionalInt returns the next n-bit signed integer in an encoding 123 | // where the likely result is zero. 124 | func (p *partition) readOptionalInt(prob, n uint8) int32 { 125 | if !p.readBit(prob) { 126 | return 0 127 | } 128 | return p.readInt(prob, n) 129 | } 130 | -------------------------------------------------------------------------------- /vp8/pred.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package vp8 6 | 7 | // This file implements parsing the predictor modes, as specified in chapter 8 | // 11. 9 | 10 | func (d *Decoder) parsePredModeY16(mbx int) { 11 | var p uint8 12 | if !d.fp.readBit(156) { 13 | if !d.fp.readBit(163) { 14 | p = predDC 15 | } else { 16 | p = predVE 17 | } 18 | } else if !d.fp.readBit(128) { 19 | p = predHE 20 | } else { 21 | p = predTM 22 | } 23 | for i := 0; i < 4; i++ { 24 | d.upMB[mbx].pred[i] = p 25 | d.leftMB.pred[i] = p 26 | } 27 | d.predY16 = p 28 | } 29 | 30 | func (d *Decoder) parsePredModeC8() { 31 | if !d.fp.readBit(142) { 32 | d.predC8 = predDC 33 | } else if !d.fp.readBit(114) { 34 | d.predC8 = predVE 35 | } else if !d.fp.readBit(183) { 36 | d.predC8 = predHE 37 | } else { 38 | d.predC8 = predTM 39 | } 40 | } 41 | 42 | func (d *Decoder) parsePredModeY4(mbx int) { 43 | for j := 0; j < 4; j++ { 44 | p := d.leftMB.pred[j] 45 | for i := 0; i < 4; i++ { 46 | prob := &predProb[d.upMB[mbx].pred[i]][p] 47 | if !d.fp.readBit(prob[0]) { 48 | p = predDC 49 | } else if !d.fp.readBit(prob[1]) { 50 | p = predTM 51 | } else if !d.fp.readBit(prob[2]) { 52 | p = predVE 53 | } else if !d.fp.readBit(prob[3]) { 54 | if !d.fp.readBit(prob[4]) { 55 | p = predHE 56 | } else if !d.fp.readBit(prob[5]) { 57 | p = predRD 58 | } else { 59 | p = predVR 60 | } 61 | } else if !d.fp.readBit(prob[6]) { 62 | p = predLD 63 | } else if !d.fp.readBit(prob[7]) { 64 | p = predVL 65 | } else if !d.fp.readBit(prob[8]) { 66 | p = predHD 67 | } else { 68 | p = predHU 69 | } 70 | d.predY4[j][i] = p 71 | d.upMB[mbx].pred[i] = p 72 | } 73 | d.leftMB.pred[j] = p 74 | } 75 | } 76 | 77 | // predProb are the probabilities to decode a 4x4 region's predictor mode given 78 | // the predictor modes of the regions above and left of it. 79 | // These values are specified in section 11.5. 80 | var predProb = [nPred][nPred][9]uint8{ 81 | { 82 | {231, 120, 48, 89, 115, 113, 120, 152, 112}, 83 | {152, 179, 64, 126, 170, 118, 46, 70, 95}, 84 | {175, 69, 143, 80, 85, 82, 72, 155, 103}, 85 | {56, 58, 10, 171, 218, 189, 17, 13, 152}, 86 | {114, 26, 17, 163, 44, 195, 21, 10, 173}, 87 | {121, 24, 80, 195, 26, 62, 44, 64, 85}, 88 | {144, 71, 10, 38, 171, 213, 144, 34, 26}, 89 | {170, 46, 55, 19, 136, 160, 33, 206, 71}, 90 | {63, 20, 8, 114, 114, 208, 12, 9, 226}, 91 | {81, 40, 11, 96, 182, 84, 29, 16, 36}, 92 | }, 93 | { 94 | {134, 183, 89, 137, 98, 101, 106, 165, 148}, 95 | {72, 187, 100, 130, 157, 111, 32, 75, 80}, 96 | {66, 102, 167, 99, 74, 62, 40, 234, 128}, 97 | {41, 53, 9, 178, 241, 141, 26, 8, 107}, 98 | {74, 43, 26, 146, 73, 166, 49, 23, 157}, 99 | {65, 38, 105, 160, 51, 52, 31, 115, 128}, 100 | {104, 79, 12, 27, 217, 255, 87, 17, 7}, 101 | {87, 68, 71, 44, 114, 51, 15, 186, 23}, 102 | {47, 41, 14, 110, 182, 183, 21, 17, 194}, 103 | {66, 45, 25, 102, 197, 189, 23, 18, 22}, 104 | }, 105 | { 106 | {88, 88, 147, 150, 42, 46, 45, 196, 205}, 107 | {43, 97, 183, 117, 85, 38, 35, 179, 61}, 108 | {39, 53, 200, 87, 26, 21, 43, 232, 171}, 109 | {56, 34, 51, 104, 114, 102, 29, 93, 77}, 110 | {39, 28, 85, 171, 58, 165, 90, 98, 64}, 111 | {34, 22, 116, 206, 23, 34, 43, 166, 73}, 112 | {107, 54, 32, 26, 51, 1, 81, 43, 31}, 113 | {68, 25, 106, 22, 64, 171, 36, 225, 114}, 114 | {34, 19, 21, 102, 132, 188, 16, 76, 124}, 115 | {62, 18, 78, 95, 85, 57, 50, 48, 51}, 116 | }, 117 | { 118 | {193, 101, 35, 159, 215, 111, 89, 46, 111}, 119 | {60, 148, 31, 172, 219, 228, 21, 18, 111}, 120 | {112, 113, 77, 85, 179, 255, 38, 120, 114}, 121 | {40, 42, 1, 196, 245, 209, 10, 25, 109}, 122 | {88, 43, 29, 140, 166, 213, 37, 43, 154}, 123 | {61, 63, 30, 155, 67, 45, 68, 1, 209}, 124 | {100, 80, 8, 43, 154, 1, 51, 26, 71}, 125 | {142, 78, 78, 16, 255, 128, 34, 197, 171}, 126 | {41, 40, 5, 102, 211, 183, 4, 1, 221}, 127 | {51, 50, 17, 168, 209, 192, 23, 25, 82}, 128 | }, 129 | { 130 | {138, 31, 36, 171, 27, 166, 38, 44, 229}, 131 | {67, 87, 58, 169, 82, 115, 26, 59, 179}, 132 | {63, 59, 90, 180, 59, 166, 93, 73, 154}, 133 | {40, 40, 21, 116, 143, 209, 34, 39, 175}, 134 | {47, 15, 16, 183, 34, 223, 49, 45, 183}, 135 | {46, 17, 33, 183, 6, 98, 15, 32, 183}, 136 | {57, 46, 22, 24, 128, 1, 54, 17, 37}, 137 | {65, 32, 73, 115, 28, 128, 23, 128, 205}, 138 | {40, 3, 9, 115, 51, 192, 18, 6, 223}, 139 | {87, 37, 9, 115, 59, 77, 64, 21, 47}, 140 | }, 141 | { 142 | {104, 55, 44, 218, 9, 54, 53, 130, 226}, 143 | {64, 90, 70, 205, 40, 41, 23, 26, 57}, 144 | {54, 57, 112, 184, 5, 41, 38, 166, 213}, 145 | {30, 34, 26, 133, 152, 116, 10, 32, 134}, 146 | {39, 19, 53, 221, 26, 114, 32, 73, 255}, 147 | {31, 9, 65, 234, 2, 15, 1, 118, 73}, 148 | {75, 32, 12, 51, 192, 255, 160, 43, 51}, 149 | {88, 31, 35, 67, 102, 85, 55, 186, 85}, 150 | {56, 21, 23, 111, 59, 205, 45, 37, 192}, 151 | {55, 38, 70, 124, 73, 102, 1, 34, 98}, 152 | }, 153 | { 154 | {125, 98, 42, 88, 104, 85, 117, 175, 82}, 155 | {95, 84, 53, 89, 128, 100, 113, 101, 45}, 156 | {75, 79, 123, 47, 51, 128, 81, 171, 1}, 157 | {57, 17, 5, 71, 102, 57, 53, 41, 49}, 158 | {38, 33, 13, 121, 57, 73, 26, 1, 85}, 159 | {41, 10, 67, 138, 77, 110, 90, 47, 114}, 160 | {115, 21, 2, 10, 102, 255, 166, 23, 6}, 161 | {101, 29, 16, 10, 85, 128, 101, 196, 26}, 162 | {57, 18, 10, 102, 102, 213, 34, 20, 43}, 163 | {117, 20, 15, 36, 163, 128, 68, 1, 26}, 164 | }, 165 | { 166 | {102, 61, 71, 37, 34, 53, 31, 243, 192}, 167 | {69, 60, 71, 38, 73, 119, 28, 222, 37}, 168 | {68, 45, 128, 34, 1, 47, 11, 245, 171}, 169 | {62, 17, 19, 70, 146, 85, 55, 62, 70}, 170 | {37, 43, 37, 154, 100, 163, 85, 160, 1}, 171 | {63, 9, 92, 136, 28, 64, 32, 201, 85}, 172 | {75, 15, 9, 9, 64, 255, 184, 119, 16}, 173 | {86, 6, 28, 5, 64, 255, 25, 248, 1}, 174 | {56, 8, 17, 132, 137, 255, 55, 116, 128}, 175 | {58, 15, 20, 82, 135, 57, 26, 121, 40}, 176 | }, 177 | { 178 | {164, 50, 31, 137, 154, 133, 25, 35, 218}, 179 | {51, 103, 44, 131, 131, 123, 31, 6, 158}, 180 | {86, 40, 64, 135, 148, 224, 45, 183, 128}, 181 | {22, 26, 17, 131, 240, 154, 14, 1, 209}, 182 | {45, 16, 21, 91, 64, 222, 7, 1, 197}, 183 | {56, 21, 39, 155, 60, 138, 23, 102, 213}, 184 | {83, 12, 13, 54, 192, 255, 68, 47, 28}, 185 | {85, 26, 85, 85, 128, 128, 32, 146, 171}, 186 | {18, 11, 7, 63, 144, 171, 4, 4, 246}, 187 | {35, 27, 10, 146, 174, 171, 12, 26, 128}, 188 | }, 189 | { 190 | {190, 80, 35, 99, 180, 80, 126, 54, 45}, 191 | {85, 126, 47, 87, 176, 51, 41, 20, 32}, 192 | {101, 75, 128, 139, 118, 146, 116, 128, 85}, 193 | {56, 41, 15, 176, 236, 85, 37, 9, 62}, 194 | {71, 30, 17, 119, 118, 255, 17, 18, 138}, 195 | {101, 38, 60, 138, 55, 70, 43, 26, 142}, 196 | {146, 36, 19, 30, 171, 255, 97, 27, 20}, 197 | {138, 45, 61, 62, 219, 1, 81, 188, 64}, 198 | {32, 41, 20, 117, 151, 142, 20, 21, 163}, 199 | {112, 19, 12, 61, 195, 128, 48, 4, 24}, 200 | }, 201 | } 202 | -------------------------------------------------------------------------------- /vp8/quant.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package vp8 6 | 7 | // This file implements parsing the quantization factors. 8 | 9 | // quant are DC/AC quantization factors. 10 | type quant struct { 11 | y1 [2]uint16 12 | y2 [2]uint16 13 | uv [2]uint16 14 | } 15 | 16 | // clip clips x to the range [min, max] inclusive. 17 | func clip(x, min, max int32) int32 { 18 | if x < min { 19 | return min 20 | } 21 | if x > max { 22 | return max 23 | } 24 | return x 25 | } 26 | 27 | // parseQuant parses the quantization factors, as specified in section 9.6. 28 | func (d *Decoder) parseQuant() { 29 | baseQ0 := d.fp.readUint(uniformProb, 7) 30 | dqy1DC := d.fp.readOptionalInt(uniformProb, 4) 31 | const dqy1AC = 0 32 | dqy2DC := d.fp.readOptionalInt(uniformProb, 4) 33 | dqy2AC := d.fp.readOptionalInt(uniformProb, 4) 34 | dquvDC := d.fp.readOptionalInt(uniformProb, 4) 35 | dquvAC := d.fp.readOptionalInt(uniformProb, 4) 36 | for i := 0; i < nSegment; i++ { 37 | q := int32(baseQ0) 38 | if d.segmentHeader.useSegment { 39 | if d.segmentHeader.relativeDelta { 40 | q += int32(d.segmentHeader.quantizer[i]) 41 | } else { 42 | q = int32(d.segmentHeader.quantizer[i]) 43 | } 44 | } 45 | d.quant[i].y1[0] = dequantTableDC[clip(q+dqy1DC, 0, 127)] 46 | d.quant[i].y1[1] = dequantTableAC[clip(q+dqy1AC, 0, 127)] 47 | d.quant[i].y2[0] = dequantTableDC[clip(q+dqy2DC, 0, 127)] * 2 48 | d.quant[i].y2[1] = dequantTableAC[clip(q+dqy2AC, 0, 127)] * 155 / 100 49 | if d.quant[i].y2[1] < 8 { 50 | d.quant[i].y2[1] = 8 51 | } 52 | // The 117 is not a typo. The dequant_init function in the spec's Reference 53 | // Decoder Source Code (http://tools.ietf.org/html/rfc6386#section-9.6 Page 145) 54 | // says to clamp the LHS value at 132, which is equal to dequantTableDC[117]. 55 | d.quant[i].uv[0] = dequantTableDC[clip(q+dquvDC, 0, 117)] 56 | d.quant[i].uv[1] = dequantTableAC[clip(q+dquvAC, 0, 127)] 57 | } 58 | } 59 | 60 | // The dequantization tables are specified in section 14.1. 61 | var ( 62 | dequantTableDC = [128]uint16{ 63 | 4, 5, 6, 7, 8, 9, 10, 10, 64 | 11, 12, 13, 14, 15, 16, 17, 17, 65 | 18, 19, 20, 20, 21, 21, 22, 22, 66 | 23, 23, 24, 25, 25, 26, 27, 28, 67 | 29, 30, 31, 32, 33, 34, 35, 36, 68 | 37, 37, 38, 39, 40, 41, 42, 43, 69 | 44, 45, 46, 46, 47, 48, 49, 50, 70 | 51, 52, 53, 54, 55, 56, 57, 58, 71 | 59, 60, 61, 62, 63, 64, 65, 66, 72 | 67, 68, 69, 70, 71, 72, 73, 74, 73 | 75, 76, 76, 77, 78, 79, 80, 81, 74 | 82, 83, 84, 85, 86, 87, 88, 89, 75 | 91, 93, 95, 96, 98, 100, 101, 102, 76 | 104, 106, 108, 110, 112, 114, 116, 118, 77 | 122, 124, 126, 128, 130, 132, 134, 136, 78 | 138, 140, 143, 145, 148, 151, 154, 157, 79 | } 80 | dequantTableAC = [128]uint16{ 81 | 4, 5, 6, 7, 8, 9, 10, 11, 82 | 12, 13, 14, 15, 16, 17, 18, 19, 83 | 20, 21, 22, 23, 24, 25, 26, 27, 84 | 28, 29, 30, 31, 32, 33, 34, 35, 85 | 36, 37, 38, 39, 40, 41, 42, 43, 86 | 44, 45, 46, 47, 48, 49, 50, 51, 87 | 52, 53, 54, 55, 56, 57, 58, 60, 88 | 62, 64, 66, 68, 70, 72, 74, 76, 89 | 78, 80, 82, 84, 86, 88, 90, 92, 90 | 94, 96, 98, 100, 102, 104, 106, 108, 91 | 110, 112, 114, 116, 119, 122, 125, 128, 92 | 131, 134, 137, 140, 143, 146, 149, 152, 93 | 155, 158, 161, 164, 167, 170, 173, 177, 94 | 181, 185, 189, 193, 197, 201, 205, 209, 95 | 213, 217, 221, 225, 229, 234, 239, 245, 96 | 249, 254, 259, 264, 269, 274, 279, 284, 97 | } 98 | ) 99 | -------------------------------------------------------------------------------- /webp/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package webp implements a decoder for WEBP images. 6 | // 7 | // WEBP is defined at: 8 | // https://developers.google.com/speed/webp/docs/riff_container 9 | package webp // import "golang.org/x/image/webp" 10 | --------------------------------------------------------------------------------