Initial QSfera import
This commit is contained in:
+27
@@ -0,0 +1,27 @@
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
|
||||
"This implementation" means the copyrightable works distributed by
|
||||
Google as part of the Go project.
|
||||
|
||||
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||
patent license to make, have made, use, offer to sell, sell, import,
|
||||
transfer and otherwise run, modify and propagate the contents of this
|
||||
implementation of Go, where such license applies only to those patent
|
||||
claims, both currently owned or controlled by Google and acquired in
|
||||
the future, licensable by Google that are necessarily infringed by this
|
||||
implementation of Go. This grant does not include claims that would be
|
||||
infringed only as a consequence of further modification of this
|
||||
implementation. If you or your agent or exclusive licensee institute or
|
||||
order or agree to the institution of patent litigation against any
|
||||
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that this implementation of Go or any code incorporated within this
|
||||
implementation of Go constitutes direct or contributory patent
|
||||
infringement, or inducement of patent infringement, then any patent
|
||||
rights granted to you under this License for this implementation of Go
|
||||
shall terminate as of the date such litigation is filed.
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package bmp implements a BMP image decoder and encoder.
|
||||
//
|
||||
// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
|
||||
package bmp // import "golang.org/x/image/bmp"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ErrUnsupported means that the input BMP image uses a valid but unsupported
|
||||
// feature.
|
||||
var ErrUnsupported = errors.New("bmp: unsupported BMP image")
|
||||
|
||||
func readUint16(b []byte) uint16 {
|
||||
return uint16(b[0]) | uint16(b[1])<<8
|
||||
}
|
||||
|
||||
func readUint32(b []byte) uint32 {
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
// decodePaletted reads a 1, 2, 4 or 8 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodePaletted(r io.Reader, c image.Config, topDown bool, bpp int) (image.Image, error) {
|
||||
paletted := image.NewPaletted(image.Rect(0, 0, c.Width, c.Height), c.ColorModel.(color.Palette))
|
||||
if c.Width == 0 || c.Height == 0 {
|
||||
return paletted, nil
|
||||
}
|
||||
y0, y1, yDelta := c.Height-1, -1, -1
|
||||
if topDown {
|
||||
y0, y1, yDelta = 0, c.Height, +1
|
||||
}
|
||||
|
||||
pixelsPerByte := 8 / bpp
|
||||
// Pad up to ensure each row is 4-bytes aligned.
|
||||
bytesPerRow := ((c.Width+pixelsPerByte-1)/pixelsPerByte + 3) &^ 3
|
||||
b := make([]byte, bytesPerRow)
|
||||
|
||||
for y := y0; y != y1; y += yDelta {
|
||||
p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
|
||||
if _, err := io.ReadFull(r, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
byteIndex, bitIndex, mask := 0, 8, byte((1<<bpp)-1)
|
||||
for pixIndex := 0; pixIndex < c.Width; pixIndex++ {
|
||||
bitIndex -= bpp
|
||||
p[pixIndex] = (b[byteIndex]) >> bitIndex & mask
|
||||
if bitIndex == 0 {
|
||||
byteIndex++
|
||||
bitIndex = 8
|
||||
}
|
||||
}
|
||||
}
|
||||
return paletted, nil
|
||||
}
|
||||
|
||||
// decodeRGB reads a 24 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodeRGB(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
|
||||
rgba := image.NewRGBA(image.Rect(0, 0, c.Width, c.Height))
|
||||
if c.Width == 0 || c.Height == 0 {
|
||||
return rgba, nil
|
||||
}
|
||||
// There are 3 bytes per pixel, and each row is 4-byte aligned.
|
||||
b := make([]byte, (3*c.Width+3)&^3)
|
||||
y0, y1, yDelta := c.Height-1, -1, -1
|
||||
if topDown {
|
||||
y0, y1, yDelta = 0, c.Height, +1
|
||||
}
|
||||
for y := y0; y != y1; y += yDelta {
|
||||
if _, err := io.ReadFull(r, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
|
||||
for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
|
||||
// BMP images are stored in BGR order rather than RGB order.
|
||||
p[i+0] = b[j+2]
|
||||
p[i+1] = b[j+1]
|
||||
p[i+2] = b[j+0]
|
||||
p[i+3] = 0xFF
|
||||
}
|
||||
}
|
||||
return rgba, nil
|
||||
}
|
||||
|
||||
// decodeNRGBA reads a 32 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodeNRGBA(r io.Reader, c image.Config, topDown, allowAlpha bool) (image.Image, error) {
|
||||
rgba := image.NewNRGBA(image.Rect(0, 0, c.Width, c.Height))
|
||||
if c.Width == 0 || c.Height == 0 {
|
||||
return rgba, nil
|
||||
}
|
||||
y0, y1, yDelta := c.Height-1, -1, -1
|
||||
if topDown {
|
||||
y0, y1, yDelta = 0, c.Height, +1
|
||||
}
|
||||
for y := y0; y != y1; y += yDelta {
|
||||
p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
|
||||
if _, err := io.ReadFull(r, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(p); i += 4 {
|
||||
// BMP images are stored in BGRA order rather than RGBA order.
|
||||
p[i+0], p[i+2] = p[i+2], p[i+0]
|
||||
if !allowAlpha {
|
||||
p[i+3] = 0xFF
|
||||
}
|
||||
}
|
||||
}
|
||||
return rgba, nil
|
||||
}
|
||||
|
||||
// Decode reads a BMP image from r and returns it as an image.Image.
|
||||
// Limitation: The file must be 8, 24 or 32 bits per pixel.
|
||||
func Decode(r io.Reader) (image.Image, error) {
|
||||
c, bpp, topDown, allowAlpha, err := decodeConfig(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch bpp {
|
||||
case 1, 2, 4, 8:
|
||||
return decodePaletted(r, c, topDown, bpp)
|
||||
case 24:
|
||||
return decodeRGB(r, c, topDown)
|
||||
case 32:
|
||||
return decodeNRGBA(r, c, topDown, allowAlpha)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// DecodeConfig returns the color model and dimensions of a BMP image without
|
||||
// decoding the entire image.
|
||||
// Limitation: The file must be 8, 24 or 32 bits per pixel.
|
||||
func DecodeConfig(r io.Reader) (image.Config, error) {
|
||||
config, _, _, _, err := decodeConfig(r)
|
||||
return config, err
|
||||
}
|
||||
|
||||
func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown bool, allowAlpha bool, err error) {
|
||||
// We only support those BMP images with one of the following DIB headers:
|
||||
// - BITMAPINFOHEADER (40 bytes)
|
||||
// - BITMAPV4HEADER (108 bytes)
|
||||
// - BITMAPV5HEADER (124 bytes)
|
||||
const (
|
||||
fileHeaderLen = 14
|
||||
infoHeaderLen = 40
|
||||
v4InfoHeaderLen = 108
|
||||
v5InfoHeaderLen = 124
|
||||
)
|
||||
var b [1024]byte
|
||||
if _, err := io.ReadFull(r, b[:fileHeaderLen+4]); err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return image.Config{}, 0, false, false, err
|
||||
}
|
||||
if string(b[:2]) != "BM" {
|
||||
return image.Config{}, 0, false, false, errors.New("bmp: invalid format")
|
||||
}
|
||||
offset := readUint32(b[10:14])
|
||||
infoLen := readUint32(b[14:18])
|
||||
if infoLen != infoHeaderLen && infoLen != v4InfoHeaderLen && infoLen != v5InfoHeaderLen {
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
if _, err := io.ReadFull(r, b[fileHeaderLen+4:fileHeaderLen+infoLen]); err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return image.Config{}, 0, false, false, err
|
||||
}
|
||||
width := int(int32(readUint32(b[18:22])))
|
||||
height := int(int32(readUint32(b[22:26])))
|
||||
if height < 0 {
|
||||
height, topDown = -height, true
|
||||
}
|
||||
if width < 0 || height < 0 {
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
// We only support 1 plane and 8, 24 or 32 bits per pixel and no
|
||||
// compression.
|
||||
planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
|
||||
// if compression is set to BI_BITFIELDS, but the bitmask is set to the default bitmask
|
||||
// that would be used if compression was set to 0, we can continue as if compression was 0
|
||||
if compression == 3 && infoLen > infoHeaderLen &&
|
||||
readUint32(b[54:58]) == 0xff0000 && readUint32(b[58:62]) == 0xff00 &&
|
||||
readUint32(b[62:66]) == 0xff && readUint32(b[66:70]) == 0xff000000 {
|
||||
compression = 0
|
||||
}
|
||||
if planes != 1 || compression != 0 {
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
switch bpp {
|
||||
case 1, 2, 4, 8:
|
||||
colorUsed := readUint32(b[46:50])
|
||||
|
||||
if colorUsed == 0 {
|
||||
colorUsed = 1 << bpp
|
||||
} else if colorUsed > (1 << bpp) {
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
|
||||
if offset != fileHeaderLen+infoLen+colorUsed*4 {
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
_, err = io.ReadFull(r, b[:colorUsed*4])
|
||||
if err != nil {
|
||||
return image.Config{}, 0, false, false, err
|
||||
}
|
||||
pcm := make(color.Palette, colorUsed)
|
||||
for i := range pcm {
|
||||
// BMP images are stored in BGR order rather than RGB order.
|
||||
// Every 4th byte is padding.
|
||||
pcm[i] = color.RGBA{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF}
|
||||
}
|
||||
return image.Config{ColorModel: pcm, Width: width, Height: height}, int(bpp), topDown, false, nil
|
||||
case 24:
|
||||
if offset != fileHeaderLen+infoLen {
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, false, nil
|
||||
case 32:
|
||||
if offset != fileHeaderLen+infoLen {
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
// 32 bits per pixel is possibly RGBX (X is padding) or RGBA (A is
|
||||
// alpha transparency). However, for BMP images, "Alpha is a
|
||||
// poorly-documented and inconsistently-used feature" says
|
||||
// https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc;l=621
|
||||
//
|
||||
// That goes on to say "BITMAPV3HEADER+ have an alpha bitmask in the
|
||||
// info header... so we respect it at all times... [For earlier
|
||||
// (smaller) headers we] ignore alpha in Windows V3 BMPs except inside
|
||||
// ICO files".
|
||||
//
|
||||
// "Ignore" means to always set alpha to 0xFF (fully opaque):
|
||||
// https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.h;l=272
|
||||
//
|
||||
// Confusingly, "Windows V3" does not correspond to BITMAPV3HEADER, but
|
||||
// instead corresponds to the earlier (smaller) BITMAPINFOHEADER:
|
||||
// https://source.chromium.org/chromium/chromium/src/+/bc0a792d7ebc587190d1a62ccddba10abeea274b:third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc;l=258
|
||||
//
|
||||
// This Go package does not support ICO files and the (infoLen >
|
||||
// infoHeaderLen) condition distinguishes BITMAPINFOHEADER (40 bytes)
|
||||
// vs later (larger) headers.
|
||||
allowAlpha = infoLen > infoHeaderLen
|
||||
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, allowAlpha, nil
|
||||
}
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
|
||||
func init() {
|
||||
image.RegisterFormat("bmp", "BM????\x00\x00\x00\x00", Decode, DecodeConfig)
|
||||
}
|
||||
+262
@@ -0,0 +1,262 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bmp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
)
|
||||
|
||||
type header struct {
|
||||
sigBM [2]byte
|
||||
fileSize uint32
|
||||
resverved [2]uint16
|
||||
pixOffset uint32
|
||||
dibHeaderSize uint32
|
||||
width uint32
|
||||
height uint32
|
||||
colorPlane uint16
|
||||
bpp uint16
|
||||
compression uint32
|
||||
imageSize uint32
|
||||
xPixelsPerMeter uint32
|
||||
yPixelsPerMeter uint32
|
||||
colorUse uint32
|
||||
colorImportant uint32
|
||||
}
|
||||
|
||||
func encodePaletted(w io.Writer, pix []uint8, dx, dy, stride, step int) error {
|
||||
var padding []byte
|
||||
if dx < step {
|
||||
padding = make([]byte, step-dx)
|
||||
}
|
||||
for y := dy - 1; y >= 0; y-- {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx
|
||||
if _, err := w.Write(pix[min:max]); err != nil {
|
||||
return err
|
||||
}
|
||||
if padding != nil {
|
||||
if _, err := w.Write(padding); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
|
||||
buf := make([]byte, step)
|
||||
if opaque {
|
||||
for y := dy - 1; y >= 0; y-- {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx*4
|
||||
off := 0
|
||||
for i := min; i < max; i += 4 {
|
||||
buf[off+2] = pix[i+0]
|
||||
buf[off+1] = pix[i+1]
|
||||
buf[off+0] = pix[i+2]
|
||||
off += 3
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for y := dy - 1; y >= 0; y-- {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx*4
|
||||
off := 0
|
||||
for i := min; i < max; i += 4 {
|
||||
a := uint32(pix[i+3])
|
||||
if a == 0 {
|
||||
buf[off+2] = 0
|
||||
buf[off+1] = 0
|
||||
buf[off+0] = 0
|
||||
buf[off+3] = 0
|
||||
off += 4
|
||||
continue
|
||||
} else if a == 0xff {
|
||||
buf[off+2] = pix[i+0]
|
||||
buf[off+1] = pix[i+1]
|
||||
buf[off+0] = pix[i+2]
|
||||
buf[off+3] = 0xff
|
||||
off += 4
|
||||
continue
|
||||
}
|
||||
buf[off+2] = uint8(((uint32(pix[i+0]) * 0xffff) / a) >> 8)
|
||||
buf[off+1] = uint8(((uint32(pix[i+1]) * 0xffff) / a) >> 8)
|
||||
buf[off+0] = uint8(((uint32(pix[i+2]) * 0xffff) / a) >> 8)
|
||||
buf[off+3] = uint8(a)
|
||||
off += 4
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeNRGBA(w io.Writer, pix []uint8, dx, dy, stride, step int, opaque bool) error {
|
||||
buf := make([]byte, step)
|
||||
if opaque {
|
||||
for y := dy - 1; y >= 0; y-- {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx*4
|
||||
off := 0
|
||||
for i := min; i < max; i += 4 {
|
||||
buf[off+2] = pix[i+0]
|
||||
buf[off+1] = pix[i+1]
|
||||
buf[off+0] = pix[i+2]
|
||||
off += 3
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for y := dy - 1; y >= 0; y-- {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx*4
|
||||
off := 0
|
||||
for i := min; i < max; i += 4 {
|
||||
buf[off+2] = pix[i+0]
|
||||
buf[off+1] = pix[i+1]
|
||||
buf[off+0] = pix[i+2]
|
||||
buf[off+3] = pix[i+3]
|
||||
off += 4
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encode(w io.Writer, m image.Image, step int) error {
|
||||
b := m.Bounds()
|
||||
buf := make([]byte, step)
|
||||
for y := b.Max.Y - 1; y >= b.Min.Y; y-- {
|
||||
off := 0
|
||||
for x := b.Min.X; x < b.Max.X; x++ {
|
||||
r, g, b, _ := m.At(x, y).RGBA()
|
||||
buf[off+2] = byte(r >> 8)
|
||||
buf[off+1] = byte(g >> 8)
|
||||
buf[off+0] = byte(b >> 8)
|
||||
off += 3
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Encode writes the image m to w in BMP format.
|
||||
func Encode(w io.Writer, m image.Image) error {
|
||||
d := m.Bounds().Size()
|
||||
if d.X < 0 || d.Y < 0 {
|
||||
return errors.New("bmp: negative bounds")
|
||||
}
|
||||
h := &header{
|
||||
sigBM: [2]byte{'B', 'M'},
|
||||
fileSize: 14 + 40,
|
||||
pixOffset: 14 + 40,
|
||||
dibHeaderSize: 40,
|
||||
width: uint32(d.X),
|
||||
height: uint32(d.Y),
|
||||
colorPlane: 1,
|
||||
}
|
||||
|
||||
var step int
|
||||
var palette []byte
|
||||
var opaque bool
|
||||
switch m := m.(type) {
|
||||
case *image.Gray:
|
||||
step = (d.X + 3) &^ 3
|
||||
palette = make([]byte, 1024)
|
||||
for i := 0; i < 256; i++ {
|
||||
palette[i*4+0] = uint8(i)
|
||||
palette[i*4+1] = uint8(i)
|
||||
palette[i*4+2] = uint8(i)
|
||||
palette[i*4+3] = 0xFF
|
||||
}
|
||||
h.imageSize = uint32(d.Y * step)
|
||||
h.fileSize += uint32(len(palette)) + h.imageSize
|
||||
h.pixOffset += uint32(len(palette))
|
||||
h.bpp = 8
|
||||
|
||||
case *image.Paletted:
|
||||
step = (d.X + 3) &^ 3
|
||||
palette = make([]byte, 1024)
|
||||
for i := 0; i < len(m.Palette) && i < 256; i++ {
|
||||
r, g, b, _ := m.Palette[i].RGBA()
|
||||
palette[i*4+0] = uint8(b >> 8)
|
||||
palette[i*4+1] = uint8(g >> 8)
|
||||
palette[i*4+2] = uint8(r >> 8)
|
||||
palette[i*4+3] = 0xFF
|
||||
}
|
||||
h.imageSize = uint32(d.Y * step)
|
||||
h.fileSize += uint32(len(palette)) + h.imageSize
|
||||
h.pixOffset += uint32(len(palette))
|
||||
h.bpp = 8
|
||||
case *image.RGBA:
|
||||
opaque = m.Opaque()
|
||||
if opaque {
|
||||
step = (3*d.X + 3) &^ 3
|
||||
h.bpp = 24
|
||||
} else {
|
||||
step = 4 * d.X
|
||||
h.bpp = 32
|
||||
}
|
||||
h.imageSize = uint32(d.Y * step)
|
||||
h.fileSize += h.imageSize
|
||||
case *image.NRGBA:
|
||||
opaque = m.Opaque()
|
||||
if opaque {
|
||||
step = (3*d.X + 3) &^ 3
|
||||
h.bpp = 24
|
||||
} else {
|
||||
step = 4 * d.X
|
||||
h.bpp = 32
|
||||
}
|
||||
h.imageSize = uint32(d.Y * step)
|
||||
h.fileSize += h.imageSize
|
||||
default:
|
||||
step = (3*d.X + 3) &^ 3
|
||||
h.imageSize = uint32(d.Y * step)
|
||||
h.fileSize += h.imageSize
|
||||
h.bpp = 24
|
||||
}
|
||||
|
||||
if err := binary.Write(w, binary.LittleEndian, h); err != nil {
|
||||
return err
|
||||
}
|
||||
if palette != nil {
|
||||
if err := binary.Write(w, binary.LittleEndian, palette); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if d.X == 0 || d.Y == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *image.Gray:
|
||||
return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
|
||||
case *image.Paletted:
|
||||
return encodePaletted(w, m.Pix, d.X, d.Y, m.Stride, step)
|
||||
case *image.RGBA:
|
||||
return encodeRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
|
||||
case *image.NRGBA:
|
||||
return encodeNRGBA(w, m.Pix, d.X, d.Y, m.Stride, step, opaque)
|
||||
}
|
||||
return encode(w, m, step)
|
||||
}
|
||||
+795
@@ -0,0 +1,795 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
// Package ccitt implements a CCITT (fax) image decoder.
|
||||
package ccitt
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
var (
|
||||
errIncompleteCode = errors.New("ccitt: incomplete code")
|
||||
errInvalidBounds = errors.New("ccitt: invalid bounds")
|
||||
errInvalidCode = errors.New("ccitt: invalid code")
|
||||
errInvalidMode = errors.New("ccitt: invalid mode")
|
||||
errInvalidOffset = errors.New("ccitt: invalid offset")
|
||||
errMissingEOL = errors.New("ccitt: missing End-of-Line")
|
||||
errRunLengthOverflowsWidth = errors.New("ccitt: run length overflows width")
|
||||
errRunLengthTooLong = errors.New("ccitt: run length too long")
|
||||
errUnsupportedMode = errors.New("ccitt: unsupported mode")
|
||||
errUnsupportedSubFormat = errors.New("ccitt: unsupported sub-format")
|
||||
errUnsupportedWidth = errors.New("ccitt: unsupported width")
|
||||
)
|
||||
|
||||
// Order specifies the bit ordering in a CCITT data stream.
|
||||
type Order uint32
|
||||
|
||||
const (
|
||||
// LSB means Least Significant Bits first.
|
||||
LSB Order = iota
|
||||
// MSB means Most Significant Bits first.
|
||||
MSB
|
||||
)
|
||||
|
||||
// SubFormat represents that the CCITT format consists of a number of
|
||||
// sub-formats. Decoding or encoding a CCITT data stream requires knowing the
|
||||
// sub-format context. It is not represented in the data stream per se.
|
||||
type SubFormat uint32
|
||||
|
||||
const (
|
||||
Group3 SubFormat = iota
|
||||
Group4
|
||||
)
|
||||
|
||||
// AutoDetectHeight is passed as the height argument to NewReader to indicate
|
||||
// that the image height (the number of rows) is not known in advance.
|
||||
const AutoDetectHeight = -1
|
||||
|
||||
// Options are optional parameters.
|
||||
type Options struct {
|
||||
// Align means that some variable-bit-width codes are byte-aligned.
|
||||
Align bool
|
||||
// Invert means that black is the 1 bit or 0xFF byte, and white is 0.
|
||||
Invert bool
|
||||
}
|
||||
|
||||
// maxWidth is the maximum (inclusive) supported width. This is a limitation of
|
||||
// this implementation, to guard against integer overflow, and not anything
|
||||
// inherent to the CCITT format.
|
||||
const maxWidth = 1 << 20
|
||||
|
||||
func invertBytes(b []byte) {
|
||||
for i, c := range b {
|
||||
b[i] = ^c
|
||||
}
|
||||
}
|
||||
|
||||
func reverseBitsWithinBytes(b []byte) {
|
||||
for i, c := range b {
|
||||
b[i] = bits.Reverse8(c)
|
||||
}
|
||||
}
|
||||
|
||||
// highBits writes to dst (1 bit per pixel, most significant bit first) the
|
||||
// high (0x80) bits from src (1 byte per pixel). It returns the number of bytes
|
||||
// written and read such that dst[:d] is the packed form of src[:s].
|
||||
//
|
||||
// For example, if src starts with the 8 bytes [0x7D, 0x7E, 0x7F, 0x80, 0x81,
|
||||
// 0x82, 0x00, 0xFF] then 0x1D will be written to dst[0].
|
||||
//
|
||||
// If src has (8 * len(dst)) or more bytes then only len(dst) bytes are
|
||||
// written, (8 * len(dst)) bytes are read, and invert is ignored.
|
||||
//
|
||||
// Otherwise, if len(src) is not a multiple of 8 then the final byte written to
|
||||
// dst is padded with 1 bits (if invert is true) or 0 bits. If inverted, the 1s
|
||||
// are typically temporary, e.g. they will be flipped back to 0s by an
|
||||
// invertBytes call in the highBits caller, reader.Read.
|
||||
func highBits(dst []byte, src []byte, invert bool) (d int, s int) {
|
||||
// Pack as many complete groups of 8 src bytes as we can.
|
||||
n := len(src) / 8
|
||||
if n > len(dst) {
|
||||
n = len(dst)
|
||||
}
|
||||
dstN := dst[:n]
|
||||
for i := range dstN {
|
||||
src8 := src[i*8 : i*8+8]
|
||||
dstN[i] = ((src8[0] & 0x80) >> 0) |
|
||||
((src8[1] & 0x80) >> 1) |
|
||||
((src8[2] & 0x80) >> 2) |
|
||||
((src8[3] & 0x80) >> 3) |
|
||||
((src8[4] & 0x80) >> 4) |
|
||||
((src8[5] & 0x80) >> 5) |
|
||||
((src8[6] & 0x80) >> 6) |
|
||||
((src8[7] & 0x80) >> 7)
|
||||
}
|
||||
d, s = n, 8*n
|
||||
dst, src = dst[d:], src[s:]
|
||||
|
||||
// Pack up to 7 remaining src bytes, if there's room in dst.
|
||||
if (len(dst) > 0) && (len(src) > 0) {
|
||||
dstByte := byte(0)
|
||||
if invert {
|
||||
dstByte = 0xFF >> uint(len(src))
|
||||
}
|
||||
for n, srcByte := range src {
|
||||
dstByte |= (srcByte & 0x80) >> uint(n)
|
||||
}
|
||||
dst[0] = dstByte
|
||||
d, s = d+1, s+len(src)
|
||||
}
|
||||
return d, s
|
||||
}
|
||||
|
||||
type bitReader struct {
|
||||
r io.Reader
|
||||
|
||||
// readErr is the error returned from the most recent r.Read call. As the
|
||||
// io.Reader documentation says, when r.Read returns (n, err), "always
|
||||
// process the n > 0 bytes returned before considering the error err".
|
||||
readErr error
|
||||
|
||||
// order is whether to process r's bytes LSB first or MSB first.
|
||||
order Order
|
||||
|
||||
// The high nBits bits of the bits field hold upcoming bits in MSB order.
|
||||
bits uint64
|
||||
nBits uint32
|
||||
|
||||
// bytes[br:bw] holds bytes read from r but not yet loaded into bits.
|
||||
br uint32
|
||||
bw uint32
|
||||
bytes [1024]uint8
|
||||
}
|
||||
|
||||
func (b *bitReader) alignToByteBoundary() {
|
||||
n := b.nBits & 7
|
||||
b.bits <<= n
|
||||
b.nBits -= n
|
||||
}
|
||||
|
||||
// nextBitMaxNBits is the maximum possible value of bitReader.nBits after a
|
||||
// bitReader.nextBit call, provided that bitReader.nBits was not more than this
|
||||
// value before that call.
|
||||
//
|
||||
// Note that the decode function can unread bits, which can temporarily set the
|
||||
// bitReader.nBits value above nextBitMaxNBits.
|
||||
const nextBitMaxNBits = 31
|
||||
|
||||
func (b *bitReader) nextBit() (uint64, error) {
|
||||
for {
|
||||
if b.nBits > 0 {
|
||||
bit := b.bits >> 63
|
||||
b.bits <<= 1
|
||||
b.nBits--
|
||||
return bit, nil
|
||||
}
|
||||
|
||||
if available := b.bw - b.br; available >= 4 {
|
||||
// Read 32 bits, even though b.bits is a uint64, since the decode
|
||||
// function may need to unread up to maxCodeLength bits, putting
|
||||
// them back in the remaining (64 - 32) bits. TestMaxCodeLength
|
||||
// checks that the generated maxCodeLength constant fits.
|
||||
//
|
||||
// If changing the Uint32 call, also change nextBitMaxNBits.
|
||||
b.bits = uint64(binary.BigEndian.Uint32(b.bytes[b.br:])) << 32
|
||||
b.br += 4
|
||||
b.nBits = 32
|
||||
continue
|
||||
} else if available > 0 {
|
||||
b.bits = uint64(b.bytes[b.br]) << (7 * 8)
|
||||
b.br++
|
||||
b.nBits = 8
|
||||
continue
|
||||
}
|
||||
|
||||
if b.readErr != nil {
|
||||
return 0, b.readErr
|
||||
}
|
||||
|
||||
n, err := b.r.Read(b.bytes[:])
|
||||
b.br = 0
|
||||
b.bw = uint32(n)
|
||||
b.readErr = err
|
||||
|
||||
if b.order != MSB {
|
||||
reverseBitsWithinBytes(b.bytes[:b.bw])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decode(b *bitReader, decodeTable [][2]int16) (uint32, error) {
|
||||
nBitsRead, bitsRead, state := uint32(0), uint64(0), int32(1)
|
||||
for {
|
||||
bit, err := b.nextBit()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = errIncompleteCode
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
bitsRead |= bit << (63 - nBitsRead)
|
||||
nBitsRead++
|
||||
|
||||
// The "&1" is redundant, but can eliminate a bounds check.
|
||||
state = int32(decodeTable[state][bit&1])
|
||||
if state < 0 {
|
||||
return uint32(^state), nil
|
||||
} else if state == 0 {
|
||||
// Unread the bits we've read, then return errInvalidCode.
|
||||
b.bits = (b.bits >> nBitsRead) | bitsRead
|
||||
b.nBits += nBitsRead
|
||||
return 0, errInvalidCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decodeEOL decodes the 12-bit EOL code 0000_0000_0001.
|
||||
func decodeEOL(b *bitReader) error {
|
||||
nBitsRead, bitsRead := uint32(0), uint64(0)
|
||||
for {
|
||||
bit, err := b.nextBit()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = errMissingEOL
|
||||
}
|
||||
return err
|
||||
}
|
||||
bitsRead |= bit << (63 - nBitsRead)
|
||||
nBitsRead++
|
||||
|
||||
if nBitsRead < 12 {
|
||||
if bit&1 == 0 {
|
||||
continue
|
||||
}
|
||||
} else if bit&1 != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unread the bits we've read, then return errMissingEOL.
|
||||
b.bits = (b.bits >> nBitsRead) | bitsRead
|
||||
b.nBits += nBitsRead
|
||||
return errMissingEOL
|
||||
}
|
||||
}
|
||||
|
||||
type reader struct {
|
||||
br bitReader
|
||||
subFormat SubFormat
|
||||
|
||||
// width is the image width in pixels.
|
||||
width int
|
||||
|
||||
// rowsRemaining starts at the image height in pixels, when the reader is
|
||||
// driven through the io.Reader interface, and decrements to zero as rows
|
||||
// are decoded. Alternatively, it may be negative if the image height is
|
||||
// not known in advance at the time of the NewReader call.
|
||||
//
|
||||
// When driven through DecodeIntoGray, this field is unused.
|
||||
rowsRemaining int
|
||||
|
||||
// curr and prev hold the current and previous rows. Each element is either
|
||||
// 0x00 (black) or 0xFF (white).
|
||||
//
|
||||
// prev may be nil, when processing the first row.
|
||||
curr []byte
|
||||
prev []byte
|
||||
|
||||
// ri is the read index. curr[:ri] are those bytes of curr that have been
|
||||
// passed along via the Read method.
|
||||
//
|
||||
// When the reader is driven through DecodeIntoGray, instead of through the
|
||||
// io.Reader interface, this field is unused.
|
||||
ri int
|
||||
|
||||
// wi is the write index. curr[:wi] are those bytes of curr that have
|
||||
// already been decoded via the decodeRow method.
|
||||
//
|
||||
// What this implementation calls wi is roughly equivalent to what the spec
|
||||
// calls the a0 index.
|
||||
wi int
|
||||
|
||||
// These fields are copied from the *Options (which may be nil).
|
||||
align bool
|
||||
invert bool
|
||||
|
||||
// atStartOfRow is whether we have just started the row. Some parts of the
|
||||
// spec say to treat this situation as if "wi = -1".
|
||||
atStartOfRow bool
|
||||
|
||||
// penColorIsWhite is whether the next run is black or white.
|
||||
penColorIsWhite bool
|
||||
|
||||
// seenStartOfImage is whether we've called the startDecode method.
|
||||
seenStartOfImage bool
|
||||
|
||||
// truncated is whether the input is missing the final 6 consecutive EOL's
|
||||
// (for Group3) or 2 consecutive EOL's (for Group4). Omitting that trailer
|
||||
// (but otherwise padding to a byte boundary, with either all 0 bits or all
|
||||
// 1 bits) is invalid according to the spec, but happens in practice when
|
||||
// exporting from Adobe Acrobat to TIFF + CCITT. This package silently
|
||||
// ignores the format error for CCITT input that has been truncated in that
|
||||
// fashion, returning the full decoded image.
|
||||
//
|
||||
// Detecting trailer truncation (just after the final row of pixels)
|
||||
// requires knowing which row is the final row, and therefore does not
|
||||
// trigger if the image height is not known in advance.
|
||||
truncated bool
|
||||
|
||||
// readErr is a sticky error for the Read method.
|
||||
readErr error
|
||||
}
|
||||
|
||||
func (z *reader) Read(p []byte) (int, error) {
|
||||
if z.readErr != nil {
|
||||
return 0, z.readErr
|
||||
}
|
||||
originalP := p
|
||||
|
||||
for len(p) > 0 {
|
||||
// Allocate buffers (and decode any start-of-image codes), if
|
||||
// processing the first or second row.
|
||||
if z.curr == nil {
|
||||
if !z.seenStartOfImage {
|
||||
if z.readErr = z.startDecode(); z.readErr != nil {
|
||||
break
|
||||
}
|
||||
z.atStartOfRow = true
|
||||
}
|
||||
z.curr = make([]byte, z.width)
|
||||
}
|
||||
|
||||
// Decode the next row, if necessary.
|
||||
if z.atStartOfRow {
|
||||
if z.rowsRemaining < 0 {
|
||||
// We do not know the image height in advance. See if the next
|
||||
// code is an EOL. If it is, it is consumed. If it isn't, the
|
||||
// bitReader shouldn't advance along the bit stream, and we
|
||||
// simply decode another row of pixel data.
|
||||
//
|
||||
// For the Group4 subFormat, we may need to align to a byte
|
||||
// boundary. For the Group3 subFormat, the previous z.decodeRow
|
||||
// call (or z.startDecode call) has already consumed one of the
|
||||
// 6 consecutive EOL's. The next EOL is actually the second of
|
||||
// 6, in the middle, and we shouldn't align at that point.
|
||||
if z.align && (z.subFormat == Group4) {
|
||||
z.br.alignToByteBoundary()
|
||||
}
|
||||
|
||||
if err := z.decodeEOL(); err == errMissingEOL {
|
||||
// No-op. It's another row of pixel data.
|
||||
} else if err != nil {
|
||||
z.readErr = err
|
||||
break
|
||||
} else {
|
||||
if z.readErr = z.finishDecode(true); z.readErr != nil {
|
||||
break
|
||||
}
|
||||
z.readErr = io.EOF
|
||||
break
|
||||
}
|
||||
|
||||
} else if z.rowsRemaining == 0 {
|
||||
// We do know the image height in advance, and we have already
|
||||
// decoded exactly that many rows.
|
||||
if z.readErr = z.finishDecode(false); z.readErr != nil {
|
||||
break
|
||||
}
|
||||
z.readErr = io.EOF
|
||||
break
|
||||
|
||||
} else {
|
||||
z.rowsRemaining--
|
||||
}
|
||||
|
||||
if z.readErr = z.decodeRow(z.rowsRemaining == 0); z.readErr != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Pack from z.curr (1 byte per pixel) to p (1 bit per pixel).
|
||||
packD, packS := highBits(p, z.curr[z.ri:], z.invert)
|
||||
p = p[packD:]
|
||||
z.ri += packS
|
||||
|
||||
// Prepare to decode the next row, if necessary.
|
||||
if z.ri == len(z.curr) {
|
||||
z.ri, z.curr, z.prev = 0, z.prev, z.curr
|
||||
z.atStartOfRow = true
|
||||
}
|
||||
}
|
||||
|
||||
n := len(originalP) - len(p)
|
||||
if z.invert {
|
||||
invertBytes(originalP[:n])
|
||||
}
|
||||
return n, z.readErr
|
||||
}
|
||||
|
||||
func (z *reader) penColor() byte {
|
||||
if z.penColorIsWhite {
|
||||
return 0xFF
|
||||
}
|
||||
return 0x00
|
||||
}
|
||||
|
||||
func (z *reader) startDecode() error {
|
||||
switch z.subFormat {
|
||||
case Group3:
|
||||
if err := z.decodeEOL(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case Group4:
|
||||
// No-op.
|
||||
|
||||
default:
|
||||
return errUnsupportedSubFormat
|
||||
}
|
||||
|
||||
z.seenStartOfImage = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (z *reader) finishDecode(alreadySeenEOL bool) error {
|
||||
numberOfEOLs := 0
|
||||
switch z.subFormat {
|
||||
case Group3:
|
||||
if z.truncated {
|
||||
return nil
|
||||
}
|
||||
// The stream ends with a RTC (Return To Control) of 6 consecutive
|
||||
// EOL's, but we should have already just seen an EOL, either in
|
||||
// z.startDecode (for a zero-height image) or in z.decodeRow.
|
||||
numberOfEOLs = 5
|
||||
|
||||
case Group4:
|
||||
autoDetectHeight := z.rowsRemaining < 0
|
||||
if autoDetectHeight {
|
||||
// Aligning to a byte boundary was already handled by reader.Read.
|
||||
} else if z.align {
|
||||
z.br.alignToByteBoundary()
|
||||
}
|
||||
// The stream ends with two EOL's. If the first one is missing, and we
|
||||
// had an explicit image height, we just assume that the trailing two
|
||||
// EOL's were truncated and return a nil error.
|
||||
if err := z.decodeEOL(); err != nil {
|
||||
if (err == errMissingEOL) && !autoDetectHeight {
|
||||
z.truncated = true
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
numberOfEOLs = 1
|
||||
|
||||
default:
|
||||
return errUnsupportedSubFormat
|
||||
}
|
||||
|
||||
if alreadySeenEOL {
|
||||
numberOfEOLs--
|
||||
}
|
||||
for ; numberOfEOLs > 0; numberOfEOLs-- {
|
||||
if err := z.decodeEOL(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (z *reader) decodeEOL() error {
|
||||
return decodeEOL(&z.br)
|
||||
}
|
||||
|
||||
func (z *reader) decodeRow(finalRow bool) error {
|
||||
z.wi = 0
|
||||
z.atStartOfRow = true
|
||||
z.penColorIsWhite = true
|
||||
|
||||
if z.align {
|
||||
z.br.alignToByteBoundary()
|
||||
}
|
||||
|
||||
switch z.subFormat {
|
||||
case Group3:
|
||||
for ; z.wi < len(z.curr); z.atStartOfRow = false {
|
||||
if err := z.decodeRun(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
err := z.decodeEOL()
|
||||
if finalRow && (err == errMissingEOL) {
|
||||
z.truncated = true
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
|
||||
case Group4:
|
||||
for ; z.wi < len(z.curr); z.atStartOfRow = false {
|
||||
mode, err := decode(&z.br, modeDecodeTable[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rm := readerMode{}
|
||||
if mode < uint32(len(readerModes)) {
|
||||
rm = readerModes[mode]
|
||||
}
|
||||
if rm.function == nil {
|
||||
return errInvalidMode
|
||||
}
|
||||
if err := rm.function(z, rm.arg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return errUnsupportedSubFormat
|
||||
}
|
||||
|
||||
func (z *reader) decodeRun() error {
|
||||
table := blackDecodeTable[:]
|
||||
if z.penColorIsWhite {
|
||||
table = whiteDecodeTable[:]
|
||||
}
|
||||
|
||||
total := 0
|
||||
for {
|
||||
n, err := decode(&z.br, table)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n > maxWidth {
|
||||
panic("unreachable")
|
||||
}
|
||||
total += int(n)
|
||||
if total > maxWidth {
|
||||
return errRunLengthTooLong
|
||||
}
|
||||
// Anything 0x3F or below is a terminal code.
|
||||
if n <= 0x3F {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if total > (len(z.curr) - z.wi) {
|
||||
return errRunLengthOverflowsWidth
|
||||
}
|
||||
dst := z.curr[z.wi : z.wi+total]
|
||||
penColor := z.penColor()
|
||||
for i := range dst {
|
||||
dst[i] = penColor
|
||||
}
|
||||
z.wi += total
|
||||
z.penColorIsWhite = !z.penColorIsWhite
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The various modes' semantics are based on determining a row of pixels'
|
||||
// "changing elements": those pixels whose color differs from the one on its
|
||||
// immediate left.
|
||||
//
|
||||
// The row above the first row is implicitly all white. Similarly, the column
|
||||
// to the left of the first column is implicitly all white.
|
||||
//
|
||||
// For example, here's Figure 1 in "ITU-T Recommendation T.6", where the
|
||||
// current and previous rows contain black (B) and white (w) pixels. The a?
|
||||
// indexes point into curr, the b? indexes point into prev.
|
||||
//
|
||||
// b1 b2
|
||||
// v v
|
||||
// prev: BBBBBwwwwwBBBwwwww
|
||||
// curr: BBBwwwwwBBBBBBwwww
|
||||
// ^ ^ ^
|
||||
// a0 a1 a2
|
||||
//
|
||||
// a0 is the "reference element" or current decoder position, roughly
|
||||
// equivalent to what this implementation calls reader.wi.
|
||||
//
|
||||
// a1 is the next changing element to the right of a0, on the "coding line"
|
||||
// (the current row).
|
||||
//
|
||||
// a2 is the next changing element to the right of a1, again on curr.
|
||||
//
|
||||
// b1 is the first changing element on the "reference line" (the previous row)
|
||||
// to the right of a0 and of opposite color to a0.
|
||||
//
|
||||
// b2 is the next changing element to the right of b1, again on prev.
|
||||
//
|
||||
// The various modes calculate a1 (and a2, for modeH):
|
||||
// - modePass calculates that a1 is at or to the right of b2.
|
||||
// - modeH calculates a1 and a2 without considering b1 or b2.
|
||||
// - modeV* calculates a1 to be b1 plus an adjustment (between -3 and +3).
|
||||
|
||||
const (
|
||||
findB1 = false
|
||||
findB2 = true
|
||||
)
|
||||
|
||||
// findB finds either the b1 or b2 value.
|
||||
func (z *reader) findB(whichB bool) int {
|
||||
// The initial row is a special case. The previous row is implicitly all
|
||||
// white, so that there are no changing pixel elements. We return b1 or b2
|
||||
// to be at the end of the row.
|
||||
if len(z.prev) != len(z.curr) {
|
||||
return len(z.curr)
|
||||
}
|
||||
|
||||
i := z.wi
|
||||
|
||||
if z.atStartOfRow {
|
||||
// a0 is implicitly at -1, on a white pixel. b1 is the first black
|
||||
// pixel in the previous row. b2 is the first white pixel after that.
|
||||
for ; (i < len(z.prev)) && (z.prev[i] == 0xFF); i++ {
|
||||
}
|
||||
if whichB == findB2 {
|
||||
for ; (i < len(z.prev)) && (z.prev[i] == 0x00); i++ {
|
||||
}
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// As per figure 1 above, assume that the current pen color is white.
|
||||
// First, walk past every contiguous black pixel in prev, starting at a0.
|
||||
oppositeColor := ^z.penColor()
|
||||
for ; (i < len(z.prev)) && (z.prev[i] == oppositeColor); i++ {
|
||||
}
|
||||
|
||||
// Then walk past every contiguous white pixel.
|
||||
penColor := ^oppositeColor
|
||||
for ; (i < len(z.prev)) && (z.prev[i] == penColor); i++ {
|
||||
}
|
||||
|
||||
// We're now at a black pixel (or at the end of the row). That's b1.
|
||||
if whichB == findB2 {
|
||||
// If we're looking for b2, walk past every contiguous black pixel
|
||||
// again.
|
||||
oppositeColor := ^penColor
|
||||
for ; (i < len(z.prev)) && (z.prev[i] == oppositeColor); i++ {
|
||||
}
|
||||
}
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
type readerMode struct {
|
||||
function func(z *reader, arg int) error
|
||||
arg int
|
||||
}
|
||||
|
||||
var readerModes = [...]readerMode{
|
||||
modePass: {function: readerModePass},
|
||||
modeH: {function: readerModeH},
|
||||
modeV0: {function: readerModeV, arg: +0},
|
||||
modeVR1: {function: readerModeV, arg: +1},
|
||||
modeVR2: {function: readerModeV, arg: +2},
|
||||
modeVR3: {function: readerModeV, arg: +3},
|
||||
modeVL1: {function: readerModeV, arg: -1},
|
||||
modeVL2: {function: readerModeV, arg: -2},
|
||||
modeVL3: {function: readerModeV, arg: -3},
|
||||
modeExt: {function: readerModeExt},
|
||||
}
|
||||
|
||||
func readerModePass(z *reader, arg int) error {
|
||||
b2 := z.findB(findB2)
|
||||
if (b2 < z.wi) || (len(z.curr) < b2) {
|
||||
return errInvalidOffset
|
||||
}
|
||||
dst := z.curr[z.wi:b2]
|
||||
penColor := z.penColor()
|
||||
for i := range dst {
|
||||
dst[i] = penColor
|
||||
}
|
||||
z.wi = b2
|
||||
return nil
|
||||
}
|
||||
|
||||
func readerModeH(z *reader, arg int) error {
|
||||
// The first iteration finds a1. The second finds a2.
|
||||
for i := 0; i < 2; i++ {
|
||||
if err := z.decodeRun(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readerModeV(z *reader, arg int) error {
|
||||
a1 := z.findB(findB1) + arg
|
||||
if (a1 < z.wi) || (len(z.curr) < a1) {
|
||||
return errInvalidOffset
|
||||
}
|
||||
dst := z.curr[z.wi:a1]
|
||||
penColor := z.penColor()
|
||||
for i := range dst {
|
||||
dst[i] = penColor
|
||||
}
|
||||
z.wi = a1
|
||||
z.penColorIsWhite = !z.penColorIsWhite
|
||||
return nil
|
||||
}
|
||||
|
||||
func readerModeExt(z *reader, arg int) error {
|
||||
return errUnsupportedMode
|
||||
}
|
||||
|
||||
// DecodeIntoGray decodes the CCITT-formatted data in r into dst.
|
||||
//
|
||||
// It returns an error if dst's width and height don't match the implied width
|
||||
// and height of CCITT-formatted data.
|
||||
func DecodeIntoGray(dst *image.Gray, r io.Reader, order Order, sf SubFormat, opts *Options) error {
|
||||
bounds := dst.Bounds()
|
||||
if (bounds.Dx() < 0) || (bounds.Dy() < 0) {
|
||||
return errInvalidBounds
|
||||
}
|
||||
if bounds.Dx() > maxWidth {
|
||||
return errUnsupportedWidth
|
||||
}
|
||||
|
||||
z := reader{
|
||||
br: bitReader{r: r, order: order},
|
||||
subFormat: sf,
|
||||
align: (opts != nil) && opts.Align,
|
||||
invert: (opts != nil) && opts.Invert,
|
||||
width: bounds.Dx(),
|
||||
}
|
||||
if err := z.startDecode(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
width := bounds.Dx()
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
p := (y - bounds.Min.Y) * dst.Stride
|
||||
z.curr = dst.Pix[p : p+width]
|
||||
if err := z.decodeRow(y+1 == bounds.Max.Y); err != nil {
|
||||
return err
|
||||
}
|
||||
z.curr, z.prev = nil, z.curr
|
||||
}
|
||||
|
||||
if err := z.finishDecode(false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if z.invert {
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
p := (y - bounds.Min.Y) * dst.Stride
|
||||
invertBytes(dst.Pix[p : p+width])
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewReader returns an io.Reader that decodes the CCITT-formatted data in r.
|
||||
// The resultant byte stream is one bit per pixel (MSB first), with 1 meaning
|
||||
// white and 0 meaning black. Each row in the result is byte-aligned.
|
||||
//
|
||||
// A negative height, such as passing AutoDetectHeight, means that the image
|
||||
// height is not known in advance. A negative width is invalid.
|
||||
func NewReader(r io.Reader, order Order, sf SubFormat, width int, height int, opts *Options) io.Reader {
|
||||
readErr := error(nil)
|
||||
if width < 0 {
|
||||
readErr = errInvalidBounds
|
||||
} else if width > maxWidth {
|
||||
readErr = errUnsupportedWidth
|
||||
}
|
||||
|
||||
return &reader{
|
||||
br: bitReader{r: r, order: order},
|
||||
subFormat: sf,
|
||||
align: (opts != nil) && opts.Align,
|
||||
invert: (opts != nil) && opts.Invert,
|
||||
width: width,
|
||||
rowsRemaining: height,
|
||||
readErr: readErr,
|
||||
}
|
||||
}
|
||||
+972
@@ -0,0 +1,972 @@
|
||||
// generated by "go run gen.go". DO NOT EDIT.
|
||||
|
||||
package ccitt
|
||||
|
||||
// Each decodeTable is represented by an array of [2]int16's: a binary tree.
|
||||
// Each array element (other than element 0, which means invalid) is a branch
|
||||
// node in that tree. The root node is always element 1 (the second element).
|
||||
//
|
||||
// To walk the tree, look at the next bit in the bit stream, using it to select
|
||||
// the first or second element of the [2]int16. If that int16 is 0, we have an
|
||||
// invalid code. If it is positive, go to that branch node. If it is negative,
|
||||
// then we have a leaf node, whose value is the bitwise complement (the ^
|
||||
// operator) of that int16.
|
||||
//
|
||||
// Comments above each decodeTable also show the same structure visually. The
|
||||
// "b123" lines show the 123'rd branch node. The "=XXXXX" lines show an invalid
|
||||
// code. The "=v1234" lines show a leaf node with value 1234. When reading the
|
||||
// bit stream, a 0 or 1 bit means to go up or down, as you move left to right.
|
||||
//
|
||||
// For example, in modeDecodeTable, branch node b005 is three steps up from the
|
||||
// root node, meaning that we have already seen "000". If the next bit is "0"
|
||||
// then we move to branch node b006. Otherwise, the next bit is "1", and we
|
||||
// move to the leaf node v0000 (also known as the modePass constant). Indeed,
|
||||
// the bits that encode modePass are "0001".
|
||||
//
|
||||
// Tables 1, 2 and 3 come from the "ITU-T Recommendation T.6: FACSIMILE CODING
|
||||
// SCHEMES AND CODING CONTROL FUNCTIONS FOR GROUP 4 FACSIMILE APPARATUS"
|
||||
// specification:
|
||||
//
|
||||
// https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-T.6-198811-I!!PDF-E&type=items
|
||||
|
||||
// modeDecodeTable represents Table 1 and the End-of-Line code.
|
||||
//
|
||||
// +=XXXXX
|
||||
// b009 +-+
|
||||
// | +=v0009
|
||||
// b007 +-+
|
||||
// | | +=v0008
|
||||
// b010 | +-+
|
||||
// | +=v0005
|
||||
// b006 +-+
|
||||
// | | +=v0007
|
||||
// b008 | +-+
|
||||
// | +=v0004
|
||||
// b005 +-+
|
||||
// | +=v0000
|
||||
// b003 +-+
|
||||
// | +=v0001
|
||||
// b002 +-+
|
||||
// | | +=v0006
|
||||
// b004 | +-+
|
||||
// | +=v0003
|
||||
// b001 +-+
|
||||
// +=v0002
|
||||
var modeDecodeTable = [...][2]int16{
|
||||
0: {0, 0},
|
||||
1: {2, ^2},
|
||||
2: {3, 4},
|
||||
3: {5, ^1},
|
||||
4: {^6, ^3},
|
||||
5: {6, ^0},
|
||||
6: {7, 8},
|
||||
7: {9, 10},
|
||||
8: {^7, ^4},
|
||||
9: {0, ^9},
|
||||
10: {^8, ^5},
|
||||
}
|
||||
|
||||
// whiteDecodeTable represents Tables 2 and 3 for a white run.
|
||||
//
|
||||
// +=XXXXX
|
||||
// b059 +-+
|
||||
// | | +=v1792
|
||||
// b096 | | +-+
|
||||
// | | | | +=v1984
|
||||
// b100 | | | +-+
|
||||
// | | | +=v2048
|
||||
// b094 | | +-+
|
||||
// | | | | +=v2112
|
||||
// b101 | | | | +-+
|
||||
// | | | | | +=v2176
|
||||
// b097 | | | +-+
|
||||
// | | | | +=v2240
|
||||
// b102 | | | +-+
|
||||
// | | | +=v2304
|
||||
// b085 | +-+
|
||||
// | | +=v1856
|
||||
// b098 | | +-+
|
||||
// | | | +=v1920
|
||||
// b095 | +-+
|
||||
// | | +=v2368
|
||||
// b103 | | +-+
|
||||
// | | | +=v2432
|
||||
// b099 | +-+
|
||||
// | | +=v2496
|
||||
// b104 | +-+
|
||||
// | +=v2560
|
||||
// b040 +-+
|
||||
// | | +=v0029
|
||||
// b060 | +-+
|
||||
// | +=v0030
|
||||
// b026 +-+
|
||||
// | | +=v0045
|
||||
// b061 | | +-+
|
||||
// | | | +=v0046
|
||||
// b041 | +-+
|
||||
// | +=v0022
|
||||
// b016 +-+
|
||||
// | | +=v0023
|
||||
// b042 | | +-+
|
||||
// | | | | +=v0047
|
||||
// b062 | | | +-+
|
||||
// | | | +=v0048
|
||||
// b027 | +-+
|
||||
// | +=v0013
|
||||
// b008 +-+
|
||||
// | | +=v0020
|
||||
// b043 | | +-+
|
||||
// | | | | +=v0033
|
||||
// b063 | | | +-+
|
||||
// | | | +=v0034
|
||||
// b028 | | +-+
|
||||
// | | | | +=v0035
|
||||
// b064 | | | | +-+
|
||||
// | | | | | +=v0036
|
||||
// b044 | | | +-+
|
||||
// | | | | +=v0037
|
||||
// b065 | | | +-+
|
||||
// | | | +=v0038
|
||||
// b017 | +-+
|
||||
// | | +=v0019
|
||||
// b045 | | +-+
|
||||
// | | | | +=v0031
|
||||
// b066 | | | +-+
|
||||
// | | | +=v0032
|
||||
// b029 | +-+
|
||||
// | +=v0001
|
||||
// b004 +-+
|
||||
// | | +=v0012
|
||||
// b030 | | +-+
|
||||
// | | | | +=v0053
|
||||
// b067 | | | | +-+
|
||||
// | | | | | +=v0054
|
||||
// b046 | | | +-+
|
||||
// | | | +=v0026
|
||||
// b018 | | +-+
|
||||
// | | | | +=v0039
|
||||
// b068 | | | | +-+
|
||||
// | | | | | +=v0040
|
||||
// b047 | | | | +-+
|
||||
// | | | | | | +=v0041
|
||||
// b069 | | | | | +-+
|
||||
// | | | | | +=v0042
|
||||
// b031 | | | +-+
|
||||
// | | | | +=v0043
|
||||
// b070 | | | | +-+
|
||||
// | | | | | +=v0044
|
||||
// b048 | | | +-+
|
||||
// | | | +=v0021
|
||||
// b009 | +-+
|
||||
// | | +=v0028
|
||||
// b049 | | +-+
|
||||
// | | | | +=v0061
|
||||
// b071 | | | +-+
|
||||
// | | | +=v0062
|
||||
// b032 | | +-+
|
||||
// | | | | +=v0063
|
||||
// b072 | | | | +-+
|
||||
// | | | | | +=v0000
|
||||
// b050 | | | +-+
|
||||
// | | | | +=v0320
|
||||
// b073 | | | +-+
|
||||
// | | | +=v0384
|
||||
// b019 | +-+
|
||||
// | +=v0010
|
||||
// b002 +-+
|
||||
// | | +=v0011
|
||||
// b020 | | +-+
|
||||
// | | | | +=v0027
|
||||
// b051 | | | | +-+
|
||||
// | | | | | | +=v0059
|
||||
// b074 | | | | | +-+
|
||||
// | | | | | +=v0060
|
||||
// b033 | | | +-+
|
||||
// | | | | +=v1472
|
||||
// b086 | | | | +-+
|
||||
// | | | | | +=v1536
|
||||
// b075 | | | | +-+
|
||||
// | | | | | | +=v1600
|
||||
// b087 | | | | | +-+
|
||||
// | | | | | +=v1728
|
||||
// b052 | | | +-+
|
||||
// | | | +=v0018
|
||||
// b010 | | +-+
|
||||
// | | | | +=v0024
|
||||
// b053 | | | | +-+
|
||||
// | | | | | | +=v0049
|
||||
// b076 | | | | | +-+
|
||||
// | | | | | +=v0050
|
||||
// b034 | | | | +-+
|
||||
// | | | | | | +=v0051
|
||||
// b077 | | | | | | +-+
|
||||
// | | | | | | | +=v0052
|
||||
// b054 | | | | | +-+
|
||||
// | | | | | +=v0025
|
||||
// b021 | | | +-+
|
||||
// | | | | +=v0055
|
||||
// b078 | | | | +-+
|
||||
// | | | | | +=v0056
|
||||
// b055 | | | | +-+
|
||||
// | | | | | | +=v0057
|
||||
// b079 | | | | | +-+
|
||||
// | | | | | +=v0058
|
||||
// b035 | | | +-+
|
||||
// | | | +=v0192
|
||||
// b005 | +-+
|
||||
// | | +=v1664
|
||||
// b036 | | +-+
|
||||
// | | | | +=v0448
|
||||
// b080 | | | | +-+
|
||||
// | | | | | +=v0512
|
||||
// b056 | | | +-+
|
||||
// | | | | +=v0704
|
||||
// b088 | | | | +-+
|
||||
// | | | | | +=v0768
|
||||
// b081 | | | +-+
|
||||
// | | | +=v0640
|
||||
// b022 | | +-+
|
||||
// | | | | +=v0576
|
||||
// b082 | | | | +-+
|
||||
// | | | | | | +=v0832
|
||||
// b089 | | | | | +-+
|
||||
// | | | | | +=v0896
|
||||
// b057 | | | | +-+
|
||||
// | | | | | | +=v0960
|
||||
// b090 | | | | | | +-+
|
||||
// | | | | | | | +=v1024
|
||||
// b083 | | | | | +-+
|
||||
// | | | | | | +=v1088
|
||||
// b091 | | | | | +-+
|
||||
// | | | | | +=v1152
|
||||
// b037 | | | +-+
|
||||
// | | | | +=v1216
|
||||
// b092 | | | | +-+
|
||||
// | | | | | +=v1280
|
||||
// b084 | | | | +-+
|
||||
// | | | | | | +=v1344
|
||||
// b093 | | | | | +-+
|
||||
// | | | | | +=v1408
|
||||
// b058 | | | +-+
|
||||
// | | | +=v0256
|
||||
// b011 | +-+
|
||||
// | +=v0002
|
||||
// b001 +-+
|
||||
// | +=v0003
|
||||
// b012 | +-+
|
||||
// | | | +=v0128
|
||||
// b023 | | +-+
|
||||
// | | +=v0008
|
||||
// b006 | +-+
|
||||
// | | | +=v0009
|
||||
// b024 | | | +-+
|
||||
// | | | | | +=v0016
|
||||
// b038 | | | | +-+
|
||||
// | | | | +=v0017
|
||||
// b013 | | +-+
|
||||
// | | +=v0004
|
||||
// b003 +-+
|
||||
// | +=v0005
|
||||
// b014 | +-+
|
||||
// | | | +=v0014
|
||||
// b039 | | | +-+
|
||||
// | | | | +=v0015
|
||||
// b025 | | +-+
|
||||
// | | +=v0064
|
||||
// b007 +-+
|
||||
// | +=v0006
|
||||
// b015 +-+
|
||||
// +=v0007
|
||||
var whiteDecodeTable = [...][2]int16{
|
||||
0: {0, 0},
|
||||
1: {2, 3},
|
||||
2: {4, 5},
|
||||
3: {6, 7},
|
||||
4: {8, 9},
|
||||
5: {10, 11},
|
||||
6: {12, 13},
|
||||
7: {14, 15},
|
||||
8: {16, 17},
|
||||
9: {18, 19},
|
||||
10: {20, 21},
|
||||
11: {22, ^2},
|
||||
12: {^3, 23},
|
||||
13: {24, ^4},
|
||||
14: {^5, 25},
|
||||
15: {^6, ^7},
|
||||
16: {26, 27},
|
||||
17: {28, 29},
|
||||
18: {30, 31},
|
||||
19: {32, ^10},
|
||||
20: {^11, 33},
|
||||
21: {34, 35},
|
||||
22: {36, 37},
|
||||
23: {^128, ^8},
|
||||
24: {^9, 38},
|
||||
25: {39, ^64},
|
||||
26: {40, 41},
|
||||
27: {42, ^13},
|
||||
28: {43, 44},
|
||||
29: {45, ^1},
|
||||
30: {^12, 46},
|
||||
31: {47, 48},
|
||||
32: {49, 50},
|
||||
33: {51, 52},
|
||||
34: {53, 54},
|
||||
35: {55, ^192},
|
||||
36: {^1664, 56},
|
||||
37: {57, 58},
|
||||
38: {^16, ^17},
|
||||
39: {^14, ^15},
|
||||
40: {59, 60},
|
||||
41: {61, ^22},
|
||||
42: {^23, 62},
|
||||
43: {^20, 63},
|
||||
44: {64, 65},
|
||||
45: {^19, 66},
|
||||
46: {67, ^26},
|
||||
47: {68, 69},
|
||||
48: {70, ^21},
|
||||
49: {^28, 71},
|
||||
50: {72, 73},
|
||||
51: {^27, 74},
|
||||
52: {75, ^18},
|
||||
53: {^24, 76},
|
||||
54: {77, ^25},
|
||||
55: {78, 79},
|
||||
56: {80, 81},
|
||||
57: {82, 83},
|
||||
58: {84, ^256},
|
||||
59: {0, 85},
|
||||
60: {^29, ^30},
|
||||
61: {^45, ^46},
|
||||
62: {^47, ^48},
|
||||
63: {^33, ^34},
|
||||
64: {^35, ^36},
|
||||
65: {^37, ^38},
|
||||
66: {^31, ^32},
|
||||
67: {^53, ^54},
|
||||
68: {^39, ^40},
|
||||
69: {^41, ^42},
|
||||
70: {^43, ^44},
|
||||
71: {^61, ^62},
|
||||
72: {^63, ^0},
|
||||
73: {^320, ^384},
|
||||
74: {^59, ^60},
|
||||
75: {86, 87},
|
||||
76: {^49, ^50},
|
||||
77: {^51, ^52},
|
||||
78: {^55, ^56},
|
||||
79: {^57, ^58},
|
||||
80: {^448, ^512},
|
||||
81: {88, ^640},
|
||||
82: {^576, 89},
|
||||
83: {90, 91},
|
||||
84: {92, 93},
|
||||
85: {94, 95},
|
||||
86: {^1472, ^1536},
|
||||
87: {^1600, ^1728},
|
||||
88: {^704, ^768},
|
||||
89: {^832, ^896},
|
||||
90: {^960, ^1024},
|
||||
91: {^1088, ^1152},
|
||||
92: {^1216, ^1280},
|
||||
93: {^1344, ^1408},
|
||||
94: {96, 97},
|
||||
95: {98, 99},
|
||||
96: {^1792, 100},
|
||||
97: {101, 102},
|
||||
98: {^1856, ^1920},
|
||||
99: {103, 104},
|
||||
100: {^1984, ^2048},
|
||||
101: {^2112, ^2176},
|
||||
102: {^2240, ^2304},
|
||||
103: {^2368, ^2432},
|
||||
104: {^2496, ^2560},
|
||||
}
|
||||
|
||||
// blackDecodeTable represents Tables 2 and 3 for a black run.
|
||||
//
|
||||
// +=XXXXX
|
||||
// b017 +-+
|
||||
// | | +=v1792
|
||||
// b042 | | +-+
|
||||
// | | | | +=v1984
|
||||
// b063 | | | +-+
|
||||
// | | | +=v2048
|
||||
// b029 | | +-+
|
||||
// | | | | +=v2112
|
||||
// b064 | | | | +-+
|
||||
// | | | | | +=v2176
|
||||
// b043 | | | +-+
|
||||
// | | | | +=v2240
|
||||
// b065 | | | +-+
|
||||
// | | | +=v2304
|
||||
// b022 | +-+
|
||||
// | | +=v1856
|
||||
// b044 | | +-+
|
||||
// | | | +=v1920
|
||||
// b030 | +-+
|
||||
// | | +=v2368
|
||||
// b066 | | +-+
|
||||
// | | | +=v2432
|
||||
// b045 | +-+
|
||||
// | | +=v2496
|
||||
// b067 | +-+
|
||||
// | +=v2560
|
||||
// b013 +-+
|
||||
// | | +=v0018
|
||||
// b031 | | +-+
|
||||
// | | | | +=v0052
|
||||
// b068 | | | | +-+
|
||||
// | | | | | | +=v0640
|
||||
// b095 | | | | | +-+
|
||||
// | | | | | +=v0704
|
||||
// b046 | | | +-+
|
||||
// | | | | +=v0768
|
||||
// b096 | | | | +-+
|
||||
// | | | | | +=v0832
|
||||
// b069 | | | +-+
|
||||
// | | | +=v0055
|
||||
// b023 | | +-+
|
||||
// | | | | +=v0056
|
||||
// b070 | | | | +-+
|
||||
// | | | | | | +=v1280
|
||||
// b097 | | | | | +-+
|
||||
// | | | | | +=v1344
|
||||
// b047 | | | | +-+
|
||||
// | | | | | | +=v1408
|
||||
// b098 | | | | | | +-+
|
||||
// | | | | | | | +=v1472
|
||||
// b071 | | | | | +-+
|
||||
// | | | | | +=v0059
|
||||
// b032 | | | +-+
|
||||
// | | | | +=v0060
|
||||
// b072 | | | | +-+
|
||||
// | | | | | | +=v1536
|
||||
// b099 | | | | | +-+
|
||||
// | | | | | +=v1600
|
||||
// b048 | | | +-+
|
||||
// | | | +=v0024
|
||||
// b018 | +-+
|
||||
// | | +=v0025
|
||||
// b049 | | +-+
|
||||
// | | | | +=v1664
|
||||
// b100 | | | | +-+
|
||||
// | | | | | +=v1728
|
||||
// b073 | | | +-+
|
||||
// | | | +=v0320
|
||||
// b033 | | +-+
|
||||
// | | | | +=v0384
|
||||
// b074 | | | | +-+
|
||||
// | | | | | +=v0448
|
||||
// b050 | | | +-+
|
||||
// | | | | +=v0512
|
||||
// b101 | | | | +-+
|
||||
// | | | | | +=v0576
|
||||
// b075 | | | +-+
|
||||
// | | | +=v0053
|
||||
// b024 | +-+
|
||||
// | | +=v0054
|
||||
// b076 | | +-+
|
||||
// | | | | +=v0896
|
||||
// b102 | | | +-+
|
||||
// | | | +=v0960
|
||||
// b051 | | +-+
|
||||
// | | | | +=v1024
|
||||
// b103 | | | | +-+
|
||||
// | | | | | +=v1088
|
||||
// b077 | | | +-+
|
||||
// | | | | +=v1152
|
||||
// b104 | | | +-+
|
||||
// | | | +=v1216
|
||||
// b034 | +-+
|
||||
// | +=v0064
|
||||
// b010 +-+
|
||||
// | | +=v0013
|
||||
// b019 | | +-+
|
||||
// | | | | +=v0023
|
||||
// b052 | | | | +-+
|
||||
// | | | | | | +=v0050
|
||||
// b078 | | | | | +-+
|
||||
// | | | | | +=v0051
|
||||
// b035 | | | | +-+
|
||||
// | | | | | | +=v0044
|
||||
// b079 | | | | | | +-+
|
||||
// | | | | | | | +=v0045
|
||||
// b053 | | | | | +-+
|
||||
// | | | | | | +=v0046
|
||||
// b080 | | | | | +-+
|
||||
// | | | | | +=v0047
|
||||
// b025 | | | +-+
|
||||
// | | | | +=v0057
|
||||
// b081 | | | | +-+
|
||||
// | | | | | +=v0058
|
||||
// b054 | | | | +-+
|
||||
// | | | | | | +=v0061
|
||||
// b082 | | | | | +-+
|
||||
// | | | | | +=v0256
|
||||
// b036 | | | +-+
|
||||
// | | | +=v0016
|
||||
// b014 | +-+
|
||||
// | | +=v0017
|
||||
// b037 | | +-+
|
||||
// | | | | +=v0048
|
||||
// b083 | | | | +-+
|
||||
// | | | | | +=v0049
|
||||
// b055 | | | +-+
|
||||
// | | | | +=v0062
|
||||
// b084 | | | +-+
|
||||
// | | | +=v0063
|
||||
// b026 | | +-+
|
||||
// | | | | +=v0030
|
||||
// b085 | | | | +-+
|
||||
// | | | | | +=v0031
|
||||
// b056 | | | | +-+
|
||||
// | | | | | | +=v0032
|
||||
// b086 | | | | | +-+
|
||||
// | | | | | +=v0033
|
||||
// b038 | | | +-+
|
||||
// | | | | +=v0040
|
||||
// b087 | | | | +-+
|
||||
// | | | | | +=v0041
|
||||
// b057 | | | +-+
|
||||
// | | | +=v0022
|
||||
// b020 | +-+
|
||||
// | +=v0014
|
||||
// b008 +-+
|
||||
// | | +=v0010
|
||||
// b015 | | +-+
|
||||
// | | | +=v0011
|
||||
// b011 | +-+
|
||||
// | | +=v0015
|
||||
// b027 | | +-+
|
||||
// | | | | +=v0128
|
||||
// b088 | | | | +-+
|
||||
// | | | | | +=v0192
|
||||
// b058 | | | | +-+
|
||||
// | | | | | | +=v0026
|
||||
// b089 | | | | | +-+
|
||||
// | | | | | +=v0027
|
||||
// b039 | | | +-+
|
||||
// | | | | +=v0028
|
||||
// b090 | | | | +-+
|
||||
// | | | | | +=v0029
|
||||
// b059 | | | +-+
|
||||
// | | | +=v0019
|
||||
// b021 | | +-+
|
||||
// | | | | +=v0020
|
||||
// b060 | | | | +-+
|
||||
// | | | | | | +=v0034
|
||||
// b091 | | | | | +-+
|
||||
// | | | | | +=v0035
|
||||
// b040 | | | | +-+
|
||||
// | | | | | | +=v0036
|
||||
// b092 | | | | | | +-+
|
||||
// | | | | | | | +=v0037
|
||||
// b061 | | | | | +-+
|
||||
// | | | | | | +=v0038
|
||||
// b093 | | | | | +-+
|
||||
// | | | | | +=v0039
|
||||
// b028 | | | +-+
|
||||
// | | | | +=v0021
|
||||
// b062 | | | | +-+
|
||||
// | | | | | | +=v0042
|
||||
// b094 | | | | | +-+
|
||||
// | | | | | +=v0043
|
||||
// b041 | | | +-+
|
||||
// | | | +=v0000
|
||||
// b016 | +-+
|
||||
// | +=v0012
|
||||
// b006 +-+
|
||||
// | | +=v0009
|
||||
// b012 | | +-+
|
||||
// | | | +=v0008
|
||||
// b009 | +-+
|
||||
// | +=v0007
|
||||
// b004 +-+
|
||||
// | | +=v0006
|
||||
// b007 | +-+
|
||||
// | +=v0005
|
||||
// b002 +-+
|
||||
// | | +=v0001
|
||||
// b005 | +-+
|
||||
// | +=v0004
|
||||
// b001 +-+
|
||||
// | +=v0003
|
||||
// b003 +-+
|
||||
// +=v0002
|
||||
var blackDecodeTable = [...][2]int16{
|
||||
0: {0, 0},
|
||||
1: {2, 3},
|
||||
2: {4, 5},
|
||||
3: {^3, ^2},
|
||||
4: {6, 7},
|
||||
5: {^1, ^4},
|
||||
6: {8, 9},
|
||||
7: {^6, ^5},
|
||||
8: {10, 11},
|
||||
9: {12, ^7},
|
||||
10: {13, 14},
|
||||
11: {15, 16},
|
||||
12: {^9, ^8},
|
||||
13: {17, 18},
|
||||
14: {19, 20},
|
||||
15: {^10, ^11},
|
||||
16: {21, ^12},
|
||||
17: {0, 22},
|
||||
18: {23, 24},
|
||||
19: {^13, 25},
|
||||
20: {26, ^14},
|
||||
21: {27, 28},
|
||||
22: {29, 30},
|
||||
23: {31, 32},
|
||||
24: {33, 34},
|
||||
25: {35, 36},
|
||||
26: {37, 38},
|
||||
27: {^15, 39},
|
||||
28: {40, 41},
|
||||
29: {42, 43},
|
||||
30: {44, 45},
|
||||
31: {^18, 46},
|
||||
32: {47, 48},
|
||||
33: {49, 50},
|
||||
34: {51, ^64},
|
||||
35: {52, 53},
|
||||
36: {54, ^16},
|
||||
37: {^17, 55},
|
||||
38: {56, 57},
|
||||
39: {58, 59},
|
||||
40: {60, 61},
|
||||
41: {62, ^0},
|
||||
42: {^1792, 63},
|
||||
43: {64, 65},
|
||||
44: {^1856, ^1920},
|
||||
45: {66, 67},
|
||||
46: {68, 69},
|
||||
47: {70, 71},
|
||||
48: {72, ^24},
|
||||
49: {^25, 73},
|
||||
50: {74, 75},
|
||||
51: {76, 77},
|
||||
52: {^23, 78},
|
||||
53: {79, 80},
|
||||
54: {81, 82},
|
||||
55: {83, 84},
|
||||
56: {85, 86},
|
||||
57: {87, ^22},
|
||||
58: {88, 89},
|
||||
59: {90, ^19},
|
||||
60: {^20, 91},
|
||||
61: {92, 93},
|
||||
62: {^21, 94},
|
||||
63: {^1984, ^2048},
|
||||
64: {^2112, ^2176},
|
||||
65: {^2240, ^2304},
|
||||
66: {^2368, ^2432},
|
||||
67: {^2496, ^2560},
|
||||
68: {^52, 95},
|
||||
69: {96, ^55},
|
||||
70: {^56, 97},
|
||||
71: {98, ^59},
|
||||
72: {^60, 99},
|
||||
73: {100, ^320},
|
||||
74: {^384, ^448},
|
||||
75: {101, ^53},
|
||||
76: {^54, 102},
|
||||
77: {103, 104},
|
||||
78: {^50, ^51},
|
||||
79: {^44, ^45},
|
||||
80: {^46, ^47},
|
||||
81: {^57, ^58},
|
||||
82: {^61, ^256},
|
||||
83: {^48, ^49},
|
||||
84: {^62, ^63},
|
||||
85: {^30, ^31},
|
||||
86: {^32, ^33},
|
||||
87: {^40, ^41},
|
||||
88: {^128, ^192},
|
||||
89: {^26, ^27},
|
||||
90: {^28, ^29},
|
||||
91: {^34, ^35},
|
||||
92: {^36, ^37},
|
||||
93: {^38, ^39},
|
||||
94: {^42, ^43},
|
||||
95: {^640, ^704},
|
||||
96: {^768, ^832},
|
||||
97: {^1280, ^1344},
|
||||
98: {^1408, ^1472},
|
||||
99: {^1536, ^1600},
|
||||
100: {^1664, ^1728},
|
||||
101: {^512, ^576},
|
||||
102: {^896, ^960},
|
||||
103: {^1024, ^1088},
|
||||
104: {^1152, ^1216},
|
||||
}
|
||||
|
||||
const maxCodeLength = 13
|
||||
|
||||
// Each encodeTable is represented by an array of bitStrings.
|
||||
|
||||
// bitString is a pair of uint32 values representing a bit code.
|
||||
// The nBits low bits of bits make up the actual bit code.
|
||||
// Eg. bitString{0x0004, 8} represents the bitcode "00000100".
|
||||
type bitString struct {
|
||||
bits uint32
|
||||
nBits uint32
|
||||
}
|
||||
|
||||
// modeEncodeTable represents Table 1 and the End-of-Line code.
|
||||
var modeEncodeTable = [...]bitString{
|
||||
0: {0x0001, 4}, // "0001"
|
||||
1: {0x0001, 3}, // "001"
|
||||
2: {0x0001, 1}, // "1"
|
||||
3: {0x0003, 3}, // "011"
|
||||
4: {0x0003, 6}, // "000011"
|
||||
5: {0x0003, 7}, // "0000011"
|
||||
6: {0x0002, 3}, // "010"
|
||||
7: {0x0002, 6}, // "000010"
|
||||
8: {0x0002, 7}, // "0000010"
|
||||
9: {0x0001, 7}, // "0000001"
|
||||
}
|
||||
|
||||
// whiteEncodeTable2 represents Table 2 for a white run.
|
||||
var whiteEncodeTable2 = [...]bitString{
|
||||
0: {0x0035, 8}, // "00110101"
|
||||
1: {0x0007, 6}, // "000111"
|
||||
2: {0x0007, 4}, // "0111"
|
||||
3: {0x0008, 4}, // "1000"
|
||||
4: {0x000b, 4}, // "1011"
|
||||
5: {0x000c, 4}, // "1100"
|
||||
6: {0x000e, 4}, // "1110"
|
||||
7: {0x000f, 4}, // "1111"
|
||||
8: {0x0013, 5}, // "10011"
|
||||
9: {0x0014, 5}, // "10100"
|
||||
10: {0x0007, 5}, // "00111"
|
||||
11: {0x0008, 5}, // "01000"
|
||||
12: {0x0008, 6}, // "001000"
|
||||
13: {0x0003, 6}, // "000011"
|
||||
14: {0x0034, 6}, // "110100"
|
||||
15: {0x0035, 6}, // "110101"
|
||||
16: {0x002a, 6}, // "101010"
|
||||
17: {0x002b, 6}, // "101011"
|
||||
18: {0x0027, 7}, // "0100111"
|
||||
19: {0x000c, 7}, // "0001100"
|
||||
20: {0x0008, 7}, // "0001000"
|
||||
21: {0x0017, 7}, // "0010111"
|
||||
22: {0x0003, 7}, // "0000011"
|
||||
23: {0x0004, 7}, // "0000100"
|
||||
24: {0x0028, 7}, // "0101000"
|
||||
25: {0x002b, 7}, // "0101011"
|
||||
26: {0x0013, 7}, // "0010011"
|
||||
27: {0x0024, 7}, // "0100100"
|
||||
28: {0x0018, 7}, // "0011000"
|
||||
29: {0x0002, 8}, // "00000010"
|
||||
30: {0x0003, 8}, // "00000011"
|
||||
31: {0x001a, 8}, // "00011010"
|
||||
32: {0x001b, 8}, // "00011011"
|
||||
33: {0x0012, 8}, // "00010010"
|
||||
34: {0x0013, 8}, // "00010011"
|
||||
35: {0x0014, 8}, // "00010100"
|
||||
36: {0x0015, 8}, // "00010101"
|
||||
37: {0x0016, 8}, // "00010110"
|
||||
38: {0x0017, 8}, // "00010111"
|
||||
39: {0x0028, 8}, // "00101000"
|
||||
40: {0x0029, 8}, // "00101001"
|
||||
41: {0x002a, 8}, // "00101010"
|
||||
42: {0x002b, 8}, // "00101011"
|
||||
43: {0x002c, 8}, // "00101100"
|
||||
44: {0x002d, 8}, // "00101101"
|
||||
45: {0x0004, 8}, // "00000100"
|
||||
46: {0x0005, 8}, // "00000101"
|
||||
47: {0x000a, 8}, // "00001010"
|
||||
48: {0x000b, 8}, // "00001011"
|
||||
49: {0x0052, 8}, // "01010010"
|
||||
50: {0x0053, 8}, // "01010011"
|
||||
51: {0x0054, 8}, // "01010100"
|
||||
52: {0x0055, 8}, // "01010101"
|
||||
53: {0x0024, 8}, // "00100100"
|
||||
54: {0x0025, 8}, // "00100101"
|
||||
55: {0x0058, 8}, // "01011000"
|
||||
56: {0x0059, 8}, // "01011001"
|
||||
57: {0x005a, 8}, // "01011010"
|
||||
58: {0x005b, 8}, // "01011011"
|
||||
59: {0x004a, 8}, // "01001010"
|
||||
60: {0x004b, 8}, // "01001011"
|
||||
61: {0x0032, 8}, // "00110010"
|
||||
62: {0x0033, 8}, // "00110011"
|
||||
63: {0x0034, 8}, // "00110100"
|
||||
}
|
||||
|
||||
// whiteEncodeTable3 represents Table 3 for a white run.
|
||||
var whiteEncodeTable3 = [...]bitString{
|
||||
0: {0x001b, 5}, // "11011"
|
||||
1: {0x0012, 5}, // "10010"
|
||||
2: {0x0017, 6}, // "010111"
|
||||
3: {0x0037, 7}, // "0110111"
|
||||
4: {0x0036, 8}, // "00110110"
|
||||
5: {0x0037, 8}, // "00110111"
|
||||
6: {0x0064, 8}, // "01100100"
|
||||
7: {0x0065, 8}, // "01100101"
|
||||
8: {0x0068, 8}, // "01101000"
|
||||
9: {0x0067, 8}, // "01100111"
|
||||
10: {0x00cc, 9}, // "011001100"
|
||||
11: {0x00cd, 9}, // "011001101"
|
||||
12: {0x00d2, 9}, // "011010010"
|
||||
13: {0x00d3, 9}, // "011010011"
|
||||
14: {0x00d4, 9}, // "011010100"
|
||||
15: {0x00d5, 9}, // "011010101"
|
||||
16: {0x00d6, 9}, // "011010110"
|
||||
17: {0x00d7, 9}, // "011010111"
|
||||
18: {0x00d8, 9}, // "011011000"
|
||||
19: {0x00d9, 9}, // "011011001"
|
||||
20: {0x00da, 9}, // "011011010"
|
||||
21: {0x00db, 9}, // "011011011"
|
||||
22: {0x0098, 9}, // "010011000"
|
||||
23: {0x0099, 9}, // "010011001"
|
||||
24: {0x009a, 9}, // "010011010"
|
||||
25: {0x0018, 6}, // "011000"
|
||||
26: {0x009b, 9}, // "010011011"
|
||||
27: {0x0008, 11}, // "00000001000"
|
||||
28: {0x000c, 11}, // "00000001100"
|
||||
29: {0x000d, 11}, // "00000001101"
|
||||
30: {0x0012, 12}, // "000000010010"
|
||||
31: {0x0013, 12}, // "000000010011"
|
||||
32: {0x0014, 12}, // "000000010100"
|
||||
33: {0x0015, 12}, // "000000010101"
|
||||
34: {0x0016, 12}, // "000000010110"
|
||||
35: {0x0017, 12}, // "000000010111"
|
||||
36: {0x001c, 12}, // "000000011100"
|
||||
37: {0x001d, 12}, // "000000011101"
|
||||
38: {0x001e, 12}, // "000000011110"
|
||||
39: {0x001f, 12}, // "000000011111"
|
||||
}
|
||||
|
||||
// blackEncodeTable2 represents Table 2 for a black run.
|
||||
var blackEncodeTable2 = [...]bitString{
|
||||
0: {0x0037, 10}, // "0000110111"
|
||||
1: {0x0002, 3}, // "010"
|
||||
2: {0x0003, 2}, // "11"
|
||||
3: {0x0002, 2}, // "10"
|
||||
4: {0x0003, 3}, // "011"
|
||||
5: {0x0003, 4}, // "0011"
|
||||
6: {0x0002, 4}, // "0010"
|
||||
7: {0x0003, 5}, // "00011"
|
||||
8: {0x0005, 6}, // "000101"
|
||||
9: {0x0004, 6}, // "000100"
|
||||
10: {0x0004, 7}, // "0000100"
|
||||
11: {0x0005, 7}, // "0000101"
|
||||
12: {0x0007, 7}, // "0000111"
|
||||
13: {0x0004, 8}, // "00000100"
|
||||
14: {0x0007, 8}, // "00000111"
|
||||
15: {0x0018, 9}, // "000011000"
|
||||
16: {0x0017, 10}, // "0000010111"
|
||||
17: {0x0018, 10}, // "0000011000"
|
||||
18: {0x0008, 10}, // "0000001000"
|
||||
19: {0x0067, 11}, // "00001100111"
|
||||
20: {0x0068, 11}, // "00001101000"
|
||||
21: {0x006c, 11}, // "00001101100"
|
||||
22: {0x0037, 11}, // "00000110111"
|
||||
23: {0x0028, 11}, // "00000101000"
|
||||
24: {0x0017, 11}, // "00000010111"
|
||||
25: {0x0018, 11}, // "00000011000"
|
||||
26: {0x00ca, 12}, // "000011001010"
|
||||
27: {0x00cb, 12}, // "000011001011"
|
||||
28: {0x00cc, 12}, // "000011001100"
|
||||
29: {0x00cd, 12}, // "000011001101"
|
||||
30: {0x0068, 12}, // "000001101000"
|
||||
31: {0x0069, 12}, // "000001101001"
|
||||
32: {0x006a, 12}, // "000001101010"
|
||||
33: {0x006b, 12}, // "000001101011"
|
||||
34: {0x00d2, 12}, // "000011010010"
|
||||
35: {0x00d3, 12}, // "000011010011"
|
||||
36: {0x00d4, 12}, // "000011010100"
|
||||
37: {0x00d5, 12}, // "000011010101"
|
||||
38: {0x00d6, 12}, // "000011010110"
|
||||
39: {0x00d7, 12}, // "000011010111"
|
||||
40: {0x006c, 12}, // "000001101100"
|
||||
41: {0x006d, 12}, // "000001101101"
|
||||
42: {0x00da, 12}, // "000011011010"
|
||||
43: {0x00db, 12}, // "000011011011"
|
||||
44: {0x0054, 12}, // "000001010100"
|
||||
45: {0x0055, 12}, // "000001010101"
|
||||
46: {0x0056, 12}, // "000001010110"
|
||||
47: {0x0057, 12}, // "000001010111"
|
||||
48: {0x0064, 12}, // "000001100100"
|
||||
49: {0x0065, 12}, // "000001100101"
|
||||
50: {0x0052, 12}, // "000001010010"
|
||||
51: {0x0053, 12}, // "000001010011"
|
||||
52: {0x0024, 12}, // "000000100100"
|
||||
53: {0x0037, 12}, // "000000110111"
|
||||
54: {0x0038, 12}, // "000000111000"
|
||||
55: {0x0027, 12}, // "000000100111"
|
||||
56: {0x0028, 12}, // "000000101000"
|
||||
57: {0x0058, 12}, // "000001011000"
|
||||
58: {0x0059, 12}, // "000001011001"
|
||||
59: {0x002b, 12}, // "000000101011"
|
||||
60: {0x002c, 12}, // "000000101100"
|
||||
61: {0x005a, 12}, // "000001011010"
|
||||
62: {0x0066, 12}, // "000001100110"
|
||||
63: {0x0067, 12}, // "000001100111"
|
||||
}
|
||||
|
||||
// blackEncodeTable3 represents Table 3 for a black run.
|
||||
var blackEncodeTable3 = [...]bitString{
|
||||
0: {0x000f, 10}, // "0000001111"
|
||||
1: {0x00c8, 12}, // "000011001000"
|
||||
2: {0x00c9, 12}, // "000011001001"
|
||||
3: {0x005b, 12}, // "000001011011"
|
||||
4: {0x0033, 12}, // "000000110011"
|
||||
5: {0x0034, 12}, // "000000110100"
|
||||
6: {0x0035, 12}, // "000000110101"
|
||||
7: {0x006c, 13}, // "0000001101100"
|
||||
8: {0x006d, 13}, // "0000001101101"
|
||||
9: {0x004a, 13}, // "0000001001010"
|
||||
10: {0x004b, 13}, // "0000001001011"
|
||||
11: {0x004c, 13}, // "0000001001100"
|
||||
12: {0x004d, 13}, // "0000001001101"
|
||||
13: {0x0072, 13}, // "0000001110010"
|
||||
14: {0x0073, 13}, // "0000001110011"
|
||||
15: {0x0074, 13}, // "0000001110100"
|
||||
16: {0x0075, 13}, // "0000001110101"
|
||||
17: {0x0076, 13}, // "0000001110110"
|
||||
18: {0x0077, 13}, // "0000001110111"
|
||||
19: {0x0052, 13}, // "0000001010010"
|
||||
20: {0x0053, 13}, // "0000001010011"
|
||||
21: {0x0054, 13}, // "0000001010100"
|
||||
22: {0x0055, 13}, // "0000001010101"
|
||||
23: {0x005a, 13}, // "0000001011010"
|
||||
24: {0x005b, 13}, // "0000001011011"
|
||||
25: {0x0064, 13}, // "0000001100100"
|
||||
26: {0x0065, 13}, // "0000001100101"
|
||||
27: {0x0008, 11}, // "00000001000"
|
||||
28: {0x000c, 11}, // "00000001100"
|
||||
29: {0x000d, 11}, // "00000001101"
|
||||
30: {0x0012, 12}, // "000000010010"
|
||||
31: {0x0013, 12}, // "000000010011"
|
||||
32: {0x0014, 12}, // "000000010100"
|
||||
33: {0x0015, 12}, // "000000010101"
|
||||
34: {0x0016, 12}, // "000000010110"
|
||||
35: {0x0017, 12}, // "000000010111"
|
||||
36: {0x001c, 12}, // "000000011100"
|
||||
37: {0x001d, 12}, // "000000011101"
|
||||
38: {0x001e, 12}, // "000000011110"
|
||||
39: {0x001f, 12}, // "000000011111"
|
||||
}
|
||||
|
||||
// COPY PASTE table.go BEGIN
|
||||
|
||||
const (
|
||||
modePass = iota // Pass
|
||||
modeH // Horizontal
|
||||
modeV0 // Vertical-0
|
||||
modeVR1 // Vertical-Right-1
|
||||
modeVR2 // Vertical-Right-2
|
||||
modeVR3 // Vertical-Right-3
|
||||
modeVL1 // Vertical-Left-1
|
||||
modeVL2 // Vertical-Left-2
|
||||
modeVL3 // Vertical-Left-3
|
||||
modeExt // Extension
|
||||
)
|
||||
|
||||
// COPY PASTE table.go END
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ccitt
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type bitWriter struct {
|
||||
w io.Writer
|
||||
|
||||
// order is whether to process w's bytes LSB first or MSB first.
|
||||
order Order
|
||||
|
||||
// The high nBits bits of the bits field hold encoded bits to be written to w.
|
||||
bits uint64
|
||||
nBits uint32
|
||||
|
||||
// bytes[:bw] holds encoded bytes not yet written to w.
|
||||
// Overflow protection is ensured by using a multiple of 8 as bytes length.
|
||||
bw uint32
|
||||
bytes [1024]uint8
|
||||
}
|
||||
|
||||
// flushBits copies 64 bits from b.bits to b.bytes. If b.bytes is then full, it
|
||||
// is written to b.w.
|
||||
func (b *bitWriter) flushBits() error {
|
||||
binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits)
|
||||
b.bits = 0
|
||||
b.nBits = 0
|
||||
b.bw += 8
|
||||
if b.bw < uint32(len(b.bytes)) {
|
||||
return nil
|
||||
}
|
||||
b.bw = 0
|
||||
if b.order != MSB {
|
||||
reverseBitsWithinBytes(b.bytes[:])
|
||||
}
|
||||
_, err := b.w.Write(b.bytes[:])
|
||||
return err
|
||||
}
|
||||
|
||||
// close finalizes a bitcode stream by writing any
|
||||
// pending bits to bitWriter's underlying io.Writer.
|
||||
func (b *bitWriter) close() error {
|
||||
// Write any encoded bits to bytes.
|
||||
if b.nBits > 0 {
|
||||
binary.BigEndian.PutUint64(b.bytes[b.bw:], b.bits)
|
||||
b.bw += (b.nBits + 7) >> 3
|
||||
}
|
||||
|
||||
if b.order != MSB {
|
||||
reverseBitsWithinBytes(b.bytes[:b.bw])
|
||||
}
|
||||
|
||||
// Write b.bw bytes to b.w.
|
||||
_, err := b.w.Write(b.bytes[:b.bw])
|
||||
return err
|
||||
}
|
||||
|
||||
// alignToByteBoundary rounds b.nBits up to a multiple of 8.
|
||||
// If all 64 bits are used, flush them to bitWriter's bytes.
|
||||
func (b *bitWriter) alignToByteBoundary() error {
|
||||
if b.nBits = (b.nBits + 7) &^ 7; b.nBits == 64 {
|
||||
return b.flushBits()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeCode writes a variable length bitcode to b's underlying io.Writer.
|
||||
func (b *bitWriter) writeCode(bs bitString) error {
|
||||
bits := bs.bits
|
||||
nBits := bs.nBits
|
||||
if 64-b.nBits >= nBits {
|
||||
// b.bits has sufficient room for storing nBits bits.
|
||||
b.bits |= uint64(bits) << (64 - nBits - b.nBits)
|
||||
b.nBits += nBits
|
||||
if b.nBits == 64 {
|
||||
return b.flushBits()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Number of leading bits that fill b.bits.
|
||||
i := 64 - b.nBits
|
||||
|
||||
// Fill b.bits then flush and write remaining bits.
|
||||
b.bits |= uint64(bits) >> (nBits - i)
|
||||
b.nBits = 64
|
||||
|
||||
if err := b.flushBits(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nBits -= i
|
||||
b.bits = uint64(bits) << (64 - nBits)
|
||||
b.nBits = nBits
|
||||
return nil
|
||||
}
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package font defines an interface for font faces, for drawing text on an
|
||||
// image.
|
||||
//
|
||||
// Other packages provide font face implementations. For example, a truetype
|
||||
// package would provide one based on .ttf font files.
|
||||
package font // import "golang.org/x/image/font"
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
"io"
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
// TODO: who is responsible for caches (glyph images, glyph indices, kerns)?
|
||||
// The Drawer or the Face?
|
||||
|
||||
// Face is a font face. Its glyphs are often derived from a font file, such as
|
||||
// "Comic_Sans_MS.ttf", but a face has a specific size, style, weight and
|
||||
// hinting. For example, the 12pt and 18pt versions of Comic Sans are two
|
||||
// different faces, even if derived from the same font file.
|
||||
//
|
||||
// A Face is not safe for concurrent use by multiple goroutines, as its methods
|
||||
// may re-use implementation-specific caches and mask image buffers.
|
||||
//
|
||||
// To create a Face, look to other packages that implement specific font file
|
||||
// formats.
|
||||
type Face interface {
|
||||
io.Closer
|
||||
|
||||
// Glyph returns the draw.DrawMask parameters (dr, mask, maskp) to draw r's
|
||||
// glyph at the sub-pixel destination location dot, and that glyph's
|
||||
// advance width.
|
||||
//
|
||||
// It returns !ok if the face does not contain a glyph for r. This includes
|
||||
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
|
||||
// or OpenType's .notdef glyph), in which case the other return values may
|
||||
// still be non-zero.
|
||||
//
|
||||
// The contents of the mask image returned by one Glyph call may change
|
||||
// after the next Glyph call. Callers that want to cache the mask must make
|
||||
// a copy.
|
||||
Glyph(dot fixed.Point26_6, r rune) (
|
||||
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool)
|
||||
|
||||
// GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal
|
||||
// to the origin, and that glyph's advance width.
|
||||
//
|
||||
// It returns !ok if the face does not contain a glyph for r. This includes
|
||||
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
|
||||
// or OpenType's .notdef glyph), in which case the other return values may
|
||||
// still be non-zero.
|
||||
//
|
||||
// The glyph's ascent and descent are equal to -bounds.Min.Y and
|
||||
// +bounds.Max.Y. The glyph's left-side and right-side bearings are equal
|
||||
// to bounds.Min.X and advance-bounds.Max.X. A visual depiction of what
|
||||
// these metrics are is at
|
||||
// https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyphterms_2x.png
|
||||
GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool)
|
||||
|
||||
// GlyphAdvance returns the advance width of r's glyph.
|
||||
//
|
||||
// It returns !ok if the face does not contain a glyph for r. This includes
|
||||
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
|
||||
// or OpenType's .notdef glyph), in which case the other return values may
|
||||
// still be non-zero.
|
||||
GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool)
|
||||
|
||||
// Kern returns the horizontal adjustment for the kerning pair (r0, r1). A
|
||||
// positive kern means to move the glyphs further apart.
|
||||
Kern(r0, r1 rune) fixed.Int26_6
|
||||
|
||||
// Metrics returns the metrics for this Face.
|
||||
Metrics() Metrics
|
||||
|
||||
// TODO: ColoredGlyph for various emoji?
|
||||
// TODO: Ligatures? Shaping?
|
||||
}
|
||||
|
||||
// Metrics holds the metrics for a Face. A visual depiction is at
|
||||
// https://developer.apple.com/library/mac/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
|
||||
type Metrics struct {
|
||||
// Height is the recommended amount of vertical space between two lines of
|
||||
// text.
|
||||
Height fixed.Int26_6
|
||||
|
||||
// Ascent is the distance from the top of a line to its baseline.
|
||||
Ascent fixed.Int26_6
|
||||
|
||||
// Descent is the distance from the bottom of a line to its baseline. The
|
||||
// value is typically positive, even though a descender goes below the
|
||||
// baseline.
|
||||
Descent fixed.Int26_6
|
||||
|
||||
// XHeight is the distance from the top of non-ascending lowercase letters
|
||||
// to the baseline.
|
||||
XHeight fixed.Int26_6
|
||||
|
||||
// CapHeight is the distance from the top of uppercase letters to the
|
||||
// baseline.
|
||||
CapHeight fixed.Int26_6
|
||||
|
||||
// CaretSlope is the slope of a caret as a vector with the Y axis pointing up.
|
||||
// The slope {0, 1} is the vertical caret.
|
||||
CaretSlope image.Point
|
||||
}
|
||||
|
||||
// Drawer draws text on a destination image.
|
||||
//
|
||||
// A Drawer is not safe for concurrent use by multiple goroutines, since its
|
||||
// Face is not.
|
||||
type Drawer struct {
|
||||
// Dst is the destination image.
|
||||
Dst draw.Image
|
||||
// Src is the source image.
|
||||
Src image.Image
|
||||
// Face provides the glyph mask images.
|
||||
Face Face
|
||||
// Dot is the baseline location to draw the next glyph. The majority of the
|
||||
// affected pixels will be above and to the right of the dot, but some may
|
||||
// be below or to the left. For example, drawing a 'j' in an italic face
|
||||
// may affect pixels below and to the left of the dot.
|
||||
Dot fixed.Point26_6
|
||||
|
||||
// TODO: Clip image.Image?
|
||||
// TODO: SrcP image.Point for Src images other than *image.Uniform? How
|
||||
// does it get updated during DrawString?
|
||||
}
|
||||
|
||||
// TODO: should DrawString return the last rune drawn, so the next DrawString
|
||||
// call can kern beforehand? Or should that be the responsibility of the caller
|
||||
// if they really want to do that, since they have to explicitly shift d.Dot
|
||||
// anyway? What if ligatures span more than two runes? What if grapheme
|
||||
// clusters span multiple runes?
|
||||
//
|
||||
// TODO: do we assume that the input is in any particular Unicode Normalization
|
||||
// Form?
|
||||
//
|
||||
// TODO: have DrawRunes(s []rune)? DrawRuneReader(io.RuneReader)?? If we take
|
||||
// io.RuneReader, we can't assume that we can rewind the stream.
|
||||
//
|
||||
// TODO: how does this work with line breaking: drawing text up until a
|
||||
// vertical line? Should DrawString return the number of runes drawn?
|
||||
|
||||
// DrawBytes draws s at the dot and advances the dot's location.
|
||||
//
|
||||
// It is equivalent to DrawString(string(s)) but may be more efficient.
|
||||
func (d *Drawer) DrawBytes(s []byte) {
|
||||
prevC := rune(-1)
|
||||
for len(s) > 0 {
|
||||
c, size := utf8.DecodeRune(s)
|
||||
s = s[size:]
|
||||
if prevC >= 0 {
|
||||
d.Dot.X += d.Face.Kern(prevC, c)
|
||||
}
|
||||
dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c)
|
||||
if !dr.Empty() {
|
||||
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
|
||||
}
|
||||
d.Dot.X += advance
|
||||
prevC = c
|
||||
}
|
||||
}
|
||||
|
||||
// DrawString draws s at the dot and advances the dot's location.
|
||||
func (d *Drawer) DrawString(s string) {
|
||||
prevC := rune(-1)
|
||||
for _, c := range s {
|
||||
if prevC >= 0 {
|
||||
d.Dot.X += d.Face.Kern(prevC, c)
|
||||
}
|
||||
dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c)
|
||||
if !dr.Empty() {
|
||||
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
|
||||
}
|
||||
d.Dot.X += advance
|
||||
prevC = c
|
||||
}
|
||||
}
|
||||
|
||||
// BoundBytes returns the bounding box of s, drawn at the drawer dot, as well as
|
||||
// the advance.
|
||||
//
|
||||
// It is equivalent to BoundBytes(string(s)) but may be more efficient.
|
||||
func (d *Drawer) BoundBytes(s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
|
||||
bounds, advance = BoundBytes(d.Face, s)
|
||||
bounds.Min = bounds.Min.Add(d.Dot)
|
||||
bounds.Max = bounds.Max.Add(d.Dot)
|
||||
return
|
||||
}
|
||||
|
||||
// BoundString returns the bounding box of s, drawn at the drawer dot, as well
|
||||
// as the advance.
|
||||
func (d *Drawer) BoundString(s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
|
||||
bounds, advance = BoundString(d.Face, s)
|
||||
bounds.Min = bounds.Min.Add(d.Dot)
|
||||
bounds.Max = bounds.Max.Add(d.Dot)
|
||||
return
|
||||
}
|
||||
|
||||
// MeasureBytes returns how far dot would advance by drawing s.
|
||||
//
|
||||
// It is equivalent to MeasureString(string(s)) but may be more efficient.
|
||||
func (d *Drawer) MeasureBytes(s []byte) (advance fixed.Int26_6) {
|
||||
return MeasureBytes(d.Face, s)
|
||||
}
|
||||
|
||||
// MeasureString returns how far dot would advance by drawing s.
|
||||
func (d *Drawer) MeasureString(s string) (advance fixed.Int26_6) {
|
||||
return MeasureString(d.Face, s)
|
||||
}
|
||||
|
||||
// BoundBytes returns the bounding box of s with f, drawn at a dot equal to the
|
||||
// origin, as well as the advance.
|
||||
//
|
||||
// It is equivalent to BoundString(string(s)) but may be more efficient.
|
||||
func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
|
||||
prevC := rune(-1)
|
||||
for len(s) > 0 {
|
||||
c, size := utf8.DecodeRune(s)
|
||||
s = s[size:]
|
||||
if prevC >= 0 {
|
||||
advance += f.Kern(prevC, c)
|
||||
}
|
||||
b, a, _ := f.GlyphBounds(c)
|
||||
if !b.Empty() {
|
||||
b.Min.X += advance
|
||||
b.Max.X += advance
|
||||
bounds = bounds.Union(b)
|
||||
}
|
||||
advance += a
|
||||
prevC = c
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// BoundString returns the bounding box of s with f, drawn at a dot equal to the
|
||||
// origin, as well as the advance.
|
||||
func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.Int26_6) {
|
||||
prevC := rune(-1)
|
||||
for _, c := range s {
|
||||
if prevC >= 0 {
|
||||
advance += f.Kern(prevC, c)
|
||||
}
|
||||
b, a, _ := f.GlyphBounds(c)
|
||||
if !b.Empty() {
|
||||
b.Min.X += advance
|
||||
b.Max.X += advance
|
||||
bounds = bounds.Union(b)
|
||||
}
|
||||
advance += a
|
||||
prevC = c
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MeasureBytes returns how far dot would advance by drawing s with f.
|
||||
//
|
||||
// It is equivalent to MeasureString(string(s)) but may be more efficient.
|
||||
func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
|
||||
prevC := rune(-1)
|
||||
for len(s) > 0 {
|
||||
c, size := utf8.DecodeRune(s)
|
||||
s = s[size:]
|
||||
if prevC >= 0 {
|
||||
advance += f.Kern(prevC, c)
|
||||
}
|
||||
a, _ := f.GlyphAdvance(c)
|
||||
advance += a
|
||||
prevC = c
|
||||
}
|
||||
return advance
|
||||
}
|
||||
|
||||
// MeasureString returns how far dot would advance by drawing s with f.
|
||||
func MeasureString(f Face, s string) (advance fixed.Int26_6) {
|
||||
prevC := rune(-1)
|
||||
for _, c := range s {
|
||||
if prevC >= 0 {
|
||||
advance += f.Kern(prevC, c)
|
||||
}
|
||||
a, _ := f.GlyphAdvance(c)
|
||||
advance += a
|
||||
prevC = c
|
||||
}
|
||||
return advance
|
||||
}
|
||||
|
||||
// Hinting selects how to quantize a vector font's glyph nodes.
|
||||
//
|
||||
// Not all fonts support hinting.
|
||||
type Hinting int
|
||||
|
||||
const (
|
||||
HintingNone Hinting = iota
|
||||
HintingVertical
|
||||
HintingFull
|
||||
)
|
||||
|
||||
// Stretch selects a normal, condensed, or expanded face.
|
||||
//
|
||||
// Not all fonts support stretches.
|
||||
type Stretch int
|
||||
|
||||
const (
|
||||
StretchUltraCondensed Stretch = -4
|
||||
StretchExtraCondensed Stretch = -3
|
||||
StretchCondensed Stretch = -2
|
||||
StretchSemiCondensed Stretch = -1
|
||||
StretchNormal Stretch = +0
|
||||
StretchSemiExpanded Stretch = +1
|
||||
StretchExpanded Stretch = +2
|
||||
StretchExtraExpanded Stretch = +3
|
||||
StretchUltraExpanded Stretch = +4
|
||||
)
|
||||
|
||||
// Style selects a normal, italic, or oblique face.
|
||||
//
|
||||
// Not all fonts support styles.
|
||||
type Style int
|
||||
|
||||
const (
|
||||
StyleNormal Style = iota
|
||||
StyleItalic
|
||||
StyleOblique
|
||||
)
|
||||
|
||||
// Weight selects a normal, light or bold face.
|
||||
//
|
||||
// Not all fonts support weights.
|
||||
//
|
||||
// The named Weight constants (e.g. WeightBold) correspond to CSS' common
|
||||
// weight names (e.g. "Bold"), but the numerical values differ, so that in Go,
|
||||
// the zero value means to use a normal weight. For the CSS names and values,
|
||||
// see https://developer.mozilla.org/en/docs/Web/CSS/font-weight
|
||||
type Weight int
|
||||
|
||||
const (
|
||||
WeightThin Weight = -3 // CSS font-weight value 100.
|
||||
WeightExtraLight Weight = -2 // CSS font-weight value 200.
|
||||
WeightLight Weight = -1 // CSS font-weight value 300.
|
||||
WeightNormal Weight = +0 // CSS font-weight value 400.
|
||||
WeightMedium Weight = +1 // CSS font-weight value 500.
|
||||
WeightSemiBold Weight = +2 // CSS font-weight value 600.
|
||||
WeightBold Weight = +3 // CSS font-weight value 700.
|
||||
WeightExtraBold Weight = +4 // CSS font-weight value 800.
|
||||
WeightBlack Weight = +5 // CSS font-weight value 900.
|
||||
)
|
||||
+9303
File diff suppressed because it is too large
Load Diff
+269
@@ -0,0 +1,269 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package opentype implements a glyph rasterizer for TTF (TrueType Fonts) and
|
||||
// OTF (OpenType Fonts).
|
||||
//
|
||||
// This package provides a high-level API, centered on the NewFace function,
|
||||
// implementing the golang.org/x/image/font.Face interface.
|
||||
//
|
||||
// The sibling golang.org/x/image/font/sfnt package provides a low-level API.
|
||||
package opentype // import "golang.org/x/image/font/opentype"
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
"io"
|
||||
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/font/sfnt"
|
||||
"golang.org/x/image/math/fixed"
|
||||
"golang.org/x/image/vector"
|
||||
)
|
||||
|
||||
// ParseCollection parses an OpenType font collection, such as TTC or OTC data,
|
||||
// from a []byte data source.
|
||||
//
|
||||
// If passed data for a single font, a TTF or OTF instead of a TTC or OTC, it
|
||||
// will return a collection containing 1 font.
|
||||
func ParseCollection(src []byte) (*Collection, error) {
|
||||
return sfnt.ParseCollection(src)
|
||||
}
|
||||
|
||||
// ParseCollectionReaderAt parses an OpenType collection, such as TTC or OTC
|
||||
// data, from an io.ReaderAt data source.
|
||||
//
|
||||
// If passed data for a single font, a TTF or OTF instead of a TTC or OTC, it
|
||||
// will return a collection containing 1 font.
|
||||
func ParseCollectionReaderAt(src io.ReaderAt) (*Collection, error) {
|
||||
return sfnt.ParseCollectionReaderAt(src)
|
||||
}
|
||||
|
||||
// Collection is a collection of one or more fonts.
|
||||
//
|
||||
// All of the Collection methods are safe to call concurrently.
|
||||
type Collection = sfnt.Collection
|
||||
|
||||
// Parse parses an OpenType font, such as TTF or OTF data, from a []byte data
|
||||
// source.
|
||||
func Parse(src []byte) (*Font, error) {
|
||||
return sfnt.Parse(src)
|
||||
}
|
||||
|
||||
// ParseReaderAt parses an OpenType font, such as TTF or OTF data, from an
|
||||
// io.ReaderAt data source.
|
||||
func ParseReaderAt(src io.ReaderAt) (*Font, error) {
|
||||
return sfnt.ParseReaderAt(src)
|
||||
}
|
||||
|
||||
// Font is an OpenType font, also known as an SFNT font.
|
||||
//
|
||||
// All of the Font methods are safe to call concurrently, as long as each call
|
||||
// has a different *sfnt.Buffer (or nil).
|
||||
//
|
||||
// The Font methods that don't take a *sfnt.Buffer argument are always safe to
|
||||
// call concurrently.
|
||||
type Font = sfnt.Font
|
||||
|
||||
// FaceOptions describes the possible options given to NewFace when
|
||||
// creating a new font.Face from a Font.
|
||||
type FaceOptions struct {
|
||||
Size float64 // Size is the font size in points
|
||||
DPI float64 // DPI is the dots per inch resolution
|
||||
Hinting font.Hinting // Hinting selects how to quantize a vector font's glyph nodes
|
||||
}
|
||||
|
||||
func defaultFaceOptions() *FaceOptions {
|
||||
return &FaceOptions{
|
||||
Size: 12,
|
||||
DPI: 72,
|
||||
Hinting: font.HintingNone,
|
||||
}
|
||||
}
|
||||
|
||||
// Face implements the font.Face interface for Font values.
|
||||
//
|
||||
// A Face is not safe to use concurrently.
|
||||
type Face struct {
|
||||
f *Font
|
||||
hinting font.Hinting
|
||||
scale fixed.Int26_6
|
||||
|
||||
metrics font.Metrics
|
||||
metricsSet bool
|
||||
|
||||
buf sfnt.Buffer
|
||||
rast vector.Rasterizer
|
||||
mask image.Alpha
|
||||
}
|
||||
|
||||
// NewFace returns a new font.Face for the given Font.
|
||||
//
|
||||
// If opts is nil, sensible defaults will be used.
|
||||
func NewFace(f *Font, opts *FaceOptions) (font.Face, error) {
|
||||
if opts == nil {
|
||||
opts = defaultFaceOptions()
|
||||
}
|
||||
face := &Face{
|
||||
f: f,
|
||||
hinting: opts.Hinting,
|
||||
scale: fixed.Int26_6(0.5 + (opts.Size * opts.DPI * 64 / 72)),
|
||||
}
|
||||
return face, nil
|
||||
}
|
||||
|
||||
// Close satisfies the font.Face interface.
|
||||
func (f *Face) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Metrics satisfies the font.Face interface.
|
||||
func (f *Face) Metrics() font.Metrics {
|
||||
if !f.metricsSet {
|
||||
var err error
|
||||
f.metrics, err = f.f.Metrics(&f.buf, f.scale, f.hinting)
|
||||
if err != nil {
|
||||
f.metrics = font.Metrics{}
|
||||
}
|
||||
f.metricsSet = true
|
||||
}
|
||||
return f.metrics
|
||||
}
|
||||
|
||||
// Kern satisfies the font.Face interface.
|
||||
func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 {
|
||||
x0, _ := f.f.GlyphIndex(&f.buf, r0)
|
||||
x1, _ := f.f.GlyphIndex(&f.buf, r1)
|
||||
k, err := f.f.Kern(&f.buf, x0, x1, fixed.Int26_6(f.f.UnitsPerEm()), f.hinting)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// Glyph satisfies the font.Face interface.
|
||||
func (f *Face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
|
||||
x, err := f.f.GlyphIndex(&f.buf, r)
|
||||
if err != nil {
|
||||
return image.Rectangle{}, nil, image.Point{}, 0, false
|
||||
}
|
||||
|
||||
// Call f.f.GlyphAdvance before f.f.LoadGlyph because the LoadGlyph docs
|
||||
// say this about the &f.buf argument: the segments become invalid to use
|
||||
// once [the buffer] is re-used.
|
||||
|
||||
advance, err = f.f.GlyphAdvance(&f.buf, x, f.scale, f.hinting)
|
||||
if err != nil {
|
||||
return image.Rectangle{}, nil, image.Point{}, 0, false
|
||||
}
|
||||
|
||||
segments, err := f.f.LoadGlyph(&f.buf, x, f.scale, nil)
|
||||
if err != nil {
|
||||
return image.Rectangle{}, nil, image.Point{}, 0, false
|
||||
}
|
||||
|
||||
// Numerical notation used below:
|
||||
// - 2 is an integer, "two"
|
||||
// - 2:16 is a 26.6 fixed point number, "two and a quarter"
|
||||
// - 2.5 is a float32 number, "two and a half"
|
||||
// Using 26.6 fixed point numbers means that there are 64 sub-pixel units
|
||||
// in 1 integer pixel unit.
|
||||
|
||||
// Translate the sub-pixel bounding box from glyph space (where the glyph
|
||||
// origin is at (0:00, 0:00)) to dst space (where the glyph origin is at
|
||||
// the dot). dst space is the coordinate space that contains both the dot
|
||||
// (a sub-pixel position) and dr (an integer-pixel rectangle).
|
||||
dBounds := segments.Bounds().Add(dot)
|
||||
|
||||
// Quantize the sub-pixel bounds (dBounds) to integer-pixel bounds (dr).
|
||||
dr.Min.X = dBounds.Min.X.Floor()
|
||||
dr.Min.Y = dBounds.Min.Y.Floor()
|
||||
dr.Max.X = dBounds.Max.X.Ceil()
|
||||
dr.Max.Y = dBounds.Max.Y.Ceil()
|
||||
width := dr.Dx()
|
||||
height := dr.Dy()
|
||||
if width < 0 || height < 0 {
|
||||
return image.Rectangle{}, nil, image.Point{}, 0, false
|
||||
}
|
||||
|
||||
// Calculate the sub-pixel bias to convert from glyph space to rasterizer
|
||||
// space. In glyph space, the segments may be to the left or right and
|
||||
// above or below the glyph origin. In rasterizer space, the segments
|
||||
// should only be right and below (or equal to) the top-left corner (0.0,
|
||||
// 0.0). They should also be left and above (or equal to) the bottom-right
|
||||
// corner (width, height), as the rasterizer should enclose the glyph
|
||||
// bounding box.
|
||||
//
|
||||
// For example, suppose that dot.X was at the sub-pixel position 25:48,
|
||||
// three quarters of the way into the 26th pixel, and that bounds.Min.X was
|
||||
// 1:20. We then have dBounds.Min.X = 1:20 + 25:48 = 27:04, dr.Min.X = 27
|
||||
// and biasX = 25:48 - 27:00 = -1:16. A vertical stroke at 1:20 in glyph
|
||||
// space becomes (1:20 + -1:16) = 0:04 in rasterizer space. 0:04 as a
|
||||
// fixed.Int26_6 value is float32(4)/64.0 = 0.0625 as a float32 value.
|
||||
biasX := dot.X - fixed.Int26_6(dr.Min.X<<6)
|
||||
biasY := dot.Y - fixed.Int26_6(dr.Min.Y<<6)
|
||||
|
||||
// Configure the mask image, re-allocating its buffer if necessary.
|
||||
nPixels := width * height
|
||||
if cap(f.mask.Pix) < nPixels {
|
||||
f.mask.Pix = make([]uint8, 2*nPixels)
|
||||
}
|
||||
f.mask.Pix = f.mask.Pix[:nPixels]
|
||||
f.mask.Stride = width
|
||||
f.mask.Rect.Min.X = 0
|
||||
f.mask.Rect.Min.Y = 0
|
||||
f.mask.Rect.Max.X = width
|
||||
f.mask.Rect.Max.Y = height
|
||||
|
||||
// Rasterize the biased segments, converting from fixed.Int26_6 to float32.
|
||||
f.rast.Reset(width, height)
|
||||
f.rast.DrawOp = draw.Src
|
||||
for _, seg := range segments {
|
||||
switch seg.Op {
|
||||
case sfnt.SegmentOpMoveTo:
|
||||
f.rast.MoveTo(
|
||||
float32(seg.Args[0].X+biasX)/64,
|
||||
float32(seg.Args[0].Y+biasY)/64,
|
||||
)
|
||||
case sfnt.SegmentOpLineTo:
|
||||
f.rast.LineTo(
|
||||
float32(seg.Args[0].X+biasX)/64,
|
||||
float32(seg.Args[0].Y+biasY)/64,
|
||||
)
|
||||
case sfnt.SegmentOpQuadTo:
|
||||
f.rast.QuadTo(
|
||||
float32(seg.Args[0].X+biasX)/64,
|
||||
float32(seg.Args[0].Y+biasY)/64,
|
||||
float32(seg.Args[1].X+biasX)/64,
|
||||
float32(seg.Args[1].Y+biasY)/64,
|
||||
)
|
||||
case sfnt.SegmentOpCubeTo:
|
||||
f.rast.CubeTo(
|
||||
float32(seg.Args[0].X+biasX)/64,
|
||||
float32(seg.Args[0].Y+biasY)/64,
|
||||
float32(seg.Args[1].X+biasX)/64,
|
||||
float32(seg.Args[1].Y+biasY)/64,
|
||||
float32(seg.Args[2].X+biasX)/64,
|
||||
float32(seg.Args[2].Y+biasY)/64,
|
||||
)
|
||||
}
|
||||
}
|
||||
f.rast.Draw(&f.mask, f.mask.Bounds(), image.Opaque, image.Point{})
|
||||
|
||||
return dr, &f.mask, f.mask.Rect.Min, advance, x != 0
|
||||
}
|
||||
|
||||
// GlyphBounds satisfies the font.Face interface.
|
||||
func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
|
||||
x, _ := f.f.GlyphIndex(&f.buf, r)
|
||||
bounds, advance, err := f.f.GlyphBounds(&f.buf, x, f.scale, f.hinting)
|
||||
return bounds, advance, (err == nil) && (x != 0)
|
||||
}
|
||||
|
||||
// GlyphAdvance satisfies the font.Face interface.
|
||||
func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
|
||||
x, _ := f.f.GlyphIndex(&f.buf, r)
|
||||
advance, err := f.f.GlyphAdvance(&f.buf, x, f.scale, f.hinting)
|
||||
return advance, (err == nil) && (x != 0)
|
||||
}
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sfnt
|
||||
|
||||
import (
|
||||
"golang.org/x/text/encoding/charmap"
|
||||
)
|
||||
|
||||
// Platform IDs and Platform Specific IDs as per
|
||||
// https://www.microsoft.com/typography/otspec/name.htm
|
||||
const (
|
||||
pidUnicode = 0
|
||||
pidMacintosh = 1
|
||||
pidWindows = 3
|
||||
|
||||
psidUnicode2BMPOnly = 3
|
||||
psidUnicode2FullRepertoire = 4
|
||||
// Note that FontForge may generate a bogus Platform Specific ID (value 10)
|
||||
// for the Unicode Platform ID (value 0). See
|
||||
// https://github.com/fontforge/fontforge/issues/2728
|
||||
|
||||
psidMacintoshRoman = 0
|
||||
|
||||
psidWindowsSymbol = 0
|
||||
psidWindowsUCS2 = 1
|
||||
psidWindowsUCS4 = 10
|
||||
)
|
||||
|
||||
// platformEncodingWidth returns the number of bytes per character assumed by
|
||||
// the given Platform ID and Platform Specific ID.
|
||||
//
|
||||
// Very old fonts, from before Unicode was widely adopted, assume only 1 byte
|
||||
// per character: a character map.
|
||||
//
|
||||
// Old fonts, from when Unicode meant the Basic Multilingual Plane (BMP),
|
||||
// assume that 2 bytes per character is sufficient.
|
||||
//
|
||||
// Recent fonts naturally support the full range of Unicode code points, which
|
||||
// can take up to 4 bytes per character. Such fonts might still choose one of
|
||||
// the legacy encodings if e.g. their repertoire is limited to the BMP, for
|
||||
// greater compatibility with older software, or because the resultant file
|
||||
// size can be smaller.
|
||||
func platformEncodingWidth(pid, psid uint16) int {
|
||||
switch pid {
|
||||
case pidUnicode:
|
||||
switch psid {
|
||||
case psidUnicode2BMPOnly:
|
||||
return 2
|
||||
case psidUnicode2FullRepertoire:
|
||||
return 4
|
||||
}
|
||||
|
||||
case pidMacintosh:
|
||||
switch psid {
|
||||
case psidMacintoshRoman:
|
||||
return 1
|
||||
}
|
||||
|
||||
case pidWindows:
|
||||
switch psid {
|
||||
case psidWindowsSymbol:
|
||||
return 2
|
||||
case psidWindowsUCS2:
|
||||
return 2
|
||||
case psidWindowsUCS4:
|
||||
return 4
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// The various cmap formats are described at
|
||||
// https://www.microsoft.com/typography/otspec/cmap.htm
|
||||
|
||||
var supportedCmapFormat = func(format, pid, psid uint16) bool {
|
||||
switch format {
|
||||
case 0:
|
||||
return pid == pidMacintosh && psid == psidMacintoshRoman
|
||||
case 4:
|
||||
return true
|
||||
case 6:
|
||||
return true
|
||||
case 12:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndex(buf []byte, offset, length uint32, format uint16) ([]byte, glyphIndexFunc, error) {
|
||||
switch format {
|
||||
case 0:
|
||||
return f.makeCachedGlyphIndexFormat0(buf, offset, length)
|
||||
case 4:
|
||||
return f.makeCachedGlyphIndexFormat4(buf, offset, length)
|
||||
case 6:
|
||||
return f.makeCachedGlyphIndexFormat6(buf, offset, length)
|
||||
case 12:
|
||||
return f.makeCachedGlyphIndexFormat12(buf, offset, length)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndexFormat0(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
|
||||
if length != 6+256 || offset+length > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
var err error
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(length))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var table [256]byte
|
||||
copy(table[:], buf[6:])
|
||||
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
|
||||
x, ok := charmap.Macintosh.EncodeRune(r)
|
||||
if !ok {
|
||||
// The source rune r is not representable in the Macintosh-Roman encoding.
|
||||
return 0, nil
|
||||
}
|
||||
return GlyphIndex(table[x]), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndexFormat4(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
|
||||
const headerSize = 14
|
||||
if offset+headerSize > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
var err error
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
offset += headerSize
|
||||
|
||||
segCount := u16(buf[6:])
|
||||
if segCount&1 != 0 {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
segCount /= 2
|
||||
if segCount > maxCmapSegments {
|
||||
return nil, nil, errUnsupportedNumberOfCmapSegments
|
||||
}
|
||||
|
||||
eLength := 8*uint32(segCount) + 2
|
||||
if offset+eLength > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
offset += eLength
|
||||
|
||||
entries := make([]cmapEntry16, segCount)
|
||||
for i := range entries {
|
||||
entries[i] = cmapEntry16{
|
||||
end: u16(buf[0*len(entries)+0+2*i:]),
|
||||
start: u16(buf[2*len(entries)+2+2*i:]),
|
||||
delta: u16(buf[4*len(entries)+2+2*i:]),
|
||||
offset: u16(buf[6*len(entries)+2+2*i:]),
|
||||
}
|
||||
}
|
||||
indexesBase := f.cmap.offset + offset
|
||||
indexesLength := f.cmap.length - offset
|
||||
|
||||
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
|
||||
if uint32(r) > 0xffff {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
c := uint16(r)
|
||||
for i, j := 0, len(entries); i < j; {
|
||||
h := i + (j-i)/2
|
||||
entry := &entries[h]
|
||||
if c < entry.start {
|
||||
j = h
|
||||
} else if entry.end < c {
|
||||
i = h + 1
|
||||
} else if entry.offset == 0 {
|
||||
return GlyphIndex(c + entry.delta), nil
|
||||
} else {
|
||||
offset := uint32(entry.offset) + 2*uint32(h-len(entries)+int(c-entry.start))
|
||||
if offset > indexesLength || offset+2 > indexesLength {
|
||||
return 0, errInvalidCmapTable
|
||||
}
|
||||
if b == nil {
|
||||
b = &Buffer{}
|
||||
}
|
||||
x, err := b.view(&f.src, int(indexesBase+offset), 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return GlyphIndex(u16(x)), nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndexFormat6(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
|
||||
const headerSize = 10
|
||||
if offset+headerSize > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
var err error
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
offset += headerSize
|
||||
|
||||
firstCode := u16(buf[6:])
|
||||
entryCount := u16(buf[8:])
|
||||
|
||||
eLength := 2 * uint32(entryCount)
|
||||
if offset+eLength > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
|
||||
if entryCount != 0 {
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
offset += eLength
|
||||
}
|
||||
|
||||
entries := make([]uint16, entryCount)
|
||||
for i := range entries {
|
||||
entries[i] = u16(buf[2*i:])
|
||||
}
|
||||
|
||||
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
|
||||
if uint16(r) < firstCode {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
c := int(uint16(r) - firstCode)
|
||||
if c >= len(entries) {
|
||||
return 0, nil
|
||||
}
|
||||
return GlyphIndex(entries[c]), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndexFormat12(buf []byte, offset, _ uint32) ([]byte, glyphIndexFunc, error) {
|
||||
const headerSize = 16
|
||||
if offset+headerSize > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
var err error
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
length := u32(buf[4:])
|
||||
if f.cmap.length < offset || length > f.cmap.length-offset {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
offset += headerSize
|
||||
|
||||
numGroups := u32(buf[12:])
|
||||
if numGroups > maxCmapSegments {
|
||||
return nil, nil, errUnsupportedNumberOfCmapSegments
|
||||
}
|
||||
|
||||
eLength := 12 * numGroups
|
||||
if headerSize+eLength != length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
offset += eLength
|
||||
|
||||
entries := make([]cmapEntry32, numGroups)
|
||||
for i := range entries {
|
||||
entries[i] = cmapEntry32{
|
||||
start: u32(buf[0+12*i:]),
|
||||
end: u32(buf[4+12*i:]),
|
||||
delta: u32(buf[8+12*i:]),
|
||||
}
|
||||
}
|
||||
|
||||
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
|
||||
c := uint32(r)
|
||||
for i, j := 0, len(entries); i < j; {
|
||||
h := i + (j-i)/2
|
||||
entry := &entries[h]
|
||||
if c < entry.start {
|
||||
j = h
|
||||
} else if entry.end < c {
|
||||
i = h + 1
|
||||
} else {
|
||||
return GlyphIndex(c - entry.start + entry.delta), nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
type cmapEntry16 struct {
|
||||
end, start, delta, offset uint16
|
||||
}
|
||||
|
||||
type cmapEntry32 struct {
|
||||
start, end, delta uint32
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// generated by go run gen.go; DO NOT EDIT
|
||||
|
||||
package sfnt
|
||||
|
||||
const numBuiltInPostNames = 258
|
||||
|
||||
const builtInPostNamesData = "" +
|
||||
".notdef.nullnonmarkingreturnspaceexclamquotedblnumbersigndollarp" +
|
||||
"ercentampersandquotesingleparenleftparenrightasteriskpluscommahy" +
|
||||
"phenperiodslashzeroonetwothreefourfivesixseveneightninecolonsemi" +
|
||||
"colonlessequalgreaterquestionatABCDEFGHIJKLMNOPQRSTUVWXYZbracket" +
|
||||
"leftbackslashbracketrightasciicircumunderscoregraveabcdefghijklm" +
|
||||
"nopqrstuvwxyzbraceleftbarbracerightasciitildeAdieresisAringCcedi" +
|
||||
"llaEacuteNtildeOdieresisUdieresisaacuteagraveacircumflexadieresi" +
|
||||
"satildearingccedillaeacuteegraveecircumflexedieresisiacuteigrave" +
|
||||
"icircumflexidieresisntildeoacuteograveocircumflexodieresisotilde" +
|
||||
"uacuteugraveucircumflexudieresisdaggerdegreecentsterlingsectionb" +
|
||||
"ulletparagraphgermandblsregisteredcopyrighttrademarkacutedieresi" +
|
||||
"snotequalAEOslashinfinityplusminuslessequalgreaterequalyenmupart" +
|
||||
"ialdiffsummationproductpiintegralordfeminineordmasculineOmegaaeo" +
|
||||
"slashquestiondownexclamdownlogicalnotradicalflorinapproxequalDel" +
|
||||
"taguillemotleftguillemotrightellipsisnonbreakingspaceAgraveAtild" +
|
||||
"eOtildeOEoeendashemdashquotedblleftquotedblrightquoteleftquoteri" +
|
||||
"ghtdividelozengeydieresisYdieresisfractioncurrencyguilsinglleftg" +
|
||||
"uilsinglrightfifldaggerdblperiodcenteredquotesinglbasequotedblba" +
|
||||
"seperthousandAcircumflexEcircumflexAacuteEdieresisEgraveIacuteIc" +
|
||||
"ircumflexIdieresisIgraveOacuteOcircumflexappleOgraveUacuteUcircu" +
|
||||
"mflexUgravedotlessicircumflextildemacronbrevedotaccentringcedill" +
|
||||
"ahungarumlautogonekcaronLslashlslashScaronscaronZcaronzcaronbrok" +
|
||||
"enbarEthethYacuteyacuteThornthornminusmultiplyonesuperiortwosupe" +
|
||||
"riorthreesuperioronehalfonequarterthreequartersfrancGbrevegbreve" +
|
||||
"IdotaccentScedillascedillaCacutecacuteCcaronccarondcroat"
|
||||
|
||||
var builtInPostNamesOffsets = [...]uint16{
|
||||
0x0000, 0x0007, 0x000c, 0x001c, 0x0021, 0x0027, 0x002f, 0x0039,
|
||||
0x003f, 0x0046, 0x004f, 0x005a, 0x0063, 0x006d, 0x0075, 0x0079,
|
||||
0x007e, 0x0084, 0x008a, 0x008f, 0x0093, 0x0096, 0x0099, 0x009e,
|
||||
0x00a2, 0x00a6, 0x00a9, 0x00ae, 0x00b3, 0x00b7, 0x00bc, 0x00c5,
|
||||
0x00c9, 0x00ce, 0x00d5, 0x00dd, 0x00df, 0x00e0, 0x00e1, 0x00e2,
|
||||
0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea,
|
||||
0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2,
|
||||
0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x0104,
|
||||
0x010d, 0x0119, 0x0124, 0x012e, 0x0133, 0x0134, 0x0135, 0x0136,
|
||||
0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
|
||||
0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146,
|
||||
0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d, 0x0156,
|
||||
0x0159, 0x0163, 0x016d, 0x0176, 0x017b, 0x0183, 0x0189, 0x018f,
|
||||
0x0198, 0x01a1, 0x01a7, 0x01ad, 0x01b8, 0x01c1, 0x01c7, 0x01cc,
|
||||
0x01d4, 0x01da, 0x01e0, 0x01eb, 0x01f4, 0x01fa, 0x0200, 0x020b,
|
||||
0x0214, 0x021a, 0x0220, 0x0226, 0x0231, 0x023a, 0x0240, 0x0246,
|
||||
0x024c, 0x0257, 0x0260, 0x0266, 0x026c, 0x0270, 0x0278, 0x027f,
|
||||
0x0285, 0x028e, 0x0298, 0x02a2, 0x02ab, 0x02b4, 0x02b9, 0x02c1,
|
||||
0x02c9, 0x02cb, 0x02d1, 0x02d9, 0x02e2, 0x02eb, 0x02f7, 0x02fa,
|
||||
0x02fc, 0x0307, 0x0310, 0x0317, 0x0319, 0x0321, 0x032c, 0x0338,
|
||||
0x033d, 0x033f, 0x0345, 0x0351, 0x035b, 0x0365, 0x036c, 0x0372,
|
||||
0x037d, 0x0382, 0x038f, 0x039d, 0x03a5, 0x03b5, 0x03bb, 0x03c1,
|
||||
0x03c7, 0x03c9, 0x03cb, 0x03d1, 0x03d7, 0x03e3, 0x03f0, 0x03f9,
|
||||
0x0403, 0x0409, 0x0410, 0x0419, 0x0422, 0x042a, 0x0432, 0x043f,
|
||||
0x044d, 0x044f, 0x0451, 0x045a, 0x0468, 0x0476, 0x0482, 0x048d,
|
||||
0x0498, 0x04a3, 0x04a9, 0x04b2, 0x04b8, 0x04be, 0x04c9, 0x04d2,
|
||||
0x04d8, 0x04de, 0x04e9, 0x04ee, 0x04f4, 0x04fa, 0x0505, 0x050b,
|
||||
0x0513, 0x051d, 0x0522, 0x0528, 0x052d, 0x0536, 0x053a, 0x0541,
|
||||
0x054d, 0x0553, 0x0558, 0x055e, 0x0564, 0x056a, 0x0570, 0x0576,
|
||||
0x057c, 0x0585, 0x0588, 0x058b, 0x0591, 0x0597, 0x059c, 0x05a1,
|
||||
0x05a6, 0x05ae, 0x05b9, 0x05c4, 0x05d1, 0x05d8, 0x05e2, 0x05ef,
|
||||
0x05f4, 0x05fa, 0x0600, 0x060a, 0x0612, 0x061a, 0x0620, 0x0626,
|
||||
0x062c, 0x0632, 0x0638,
|
||||
}
|
||||
+550
@@ -0,0 +1,550 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sfnt
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
hexScriptLatn = uint32(0x6c61746e) // latn
|
||||
hexScriptDFLT = uint32(0x44464c54) // DFLT
|
||||
hexFeatureKern = uint32(0x6b65726e) // kern
|
||||
)
|
||||
|
||||
// kernFunc returns the unscaled kerning value for kerning pair a+b.
|
||||
// Returns ErrNotFound if no kerning is specified for this pair.
|
||||
type kernFunc func(a, b GlyphIndex) (int16, error)
|
||||
|
||||
func (f *Font) parseGPOSKern(buf []byte) ([]byte, []kernFunc, error) {
|
||||
// https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
|
||||
|
||||
if f.gpos.length == 0 {
|
||||
return buf, nil, nil
|
||||
}
|
||||
const headerSize = 10 // GPOS header v1.1 is 14 bytes, but we don't support FeatureVariations
|
||||
if f.gpos.length < headerSize {
|
||||
return buf, nil, errInvalidGPOSTable
|
||||
}
|
||||
|
||||
buf, err := f.src.view(buf, int(f.gpos.offset), headerSize)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
// check for version 1.0/1.1
|
||||
if u16(buf) != 1 || u16(buf[2:]) > 1 {
|
||||
return buf, nil, errUnsupportedGPOSTable
|
||||
}
|
||||
scriptListOffset := u16(buf[4:])
|
||||
featureListOffset := u16(buf[6:])
|
||||
lookupListOffset := u16(buf[8:])
|
||||
|
||||
// get all feature indices for latn script
|
||||
buf, featureIdxs, err := f.parseGPOSScriptFeatures(buf, int(f.gpos.offset)+int(scriptListOffset), hexScriptLatn)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
if len(featureIdxs) == 0 {
|
||||
// get all feature indices for DFLT script
|
||||
buf, featureIdxs, err = f.parseGPOSScriptFeatures(buf, int(f.gpos.offset)+int(scriptListOffset), hexScriptDFLT)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
if len(featureIdxs) == 0 {
|
||||
return buf, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// get all lookup indices for kern features
|
||||
buf, lookupIdx, err := f.parseGPOSFeaturesLookup(buf, int(f.gpos.offset)+int(featureListOffset), featureIdxs, hexFeatureKern)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
// LookupTableList: lookupCount,[]lookups
|
||||
buf, numLookupTables, err := f.src.varLenView(buf, int(f.gpos.offset)+int(lookupListOffset), 2, 0, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
var kernFuncs []kernFunc
|
||||
|
||||
lookupTables:
|
||||
for _, n := range lookupIdx {
|
||||
if n > numLookupTables {
|
||||
return buf, nil, errInvalidGPOSTable
|
||||
}
|
||||
tableOffset := int(f.gpos.offset) + int(lookupListOffset) + int(u16(buf[2+n*2:]))
|
||||
|
||||
// LookupTable: lookupType, lookupFlag, subTableCount, []subtableOffsets, markFilteringSet
|
||||
buf, numSubTables, err := f.src.varLenView(buf, tableOffset, 8, 4, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
flags := u16(buf[2:])
|
||||
|
||||
subTableOffsets := make([]int, numSubTables)
|
||||
for i := 0; i < int(numSubTables); i++ {
|
||||
subTableOffsets[i] = int(tableOffset) + int(u16(buf[6+i*2:]))
|
||||
}
|
||||
|
||||
switch lookupType := u16(buf); lookupType {
|
||||
case 2: // PairPos table
|
||||
case 9:
|
||||
// Extension Positioning table defines an additional u32 offset
|
||||
// to allow subtables to exceed the 16-bit limit.
|
||||
for i := range subTableOffsets {
|
||||
buf, err = f.src.view(buf, subTableOffsets[i], 8)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
if format := u16(buf); format != 1 {
|
||||
return buf, nil, errUnsupportedExtensionPosFormat
|
||||
}
|
||||
if lookupType := u16(buf[2:]); lookupType != 2 {
|
||||
continue lookupTables
|
||||
}
|
||||
subTableOffsets[i] += int(u32(buf[4:]))
|
||||
}
|
||||
default: // other types are not supported
|
||||
continue
|
||||
}
|
||||
|
||||
if flags&0x0010 > 0 {
|
||||
// useMarkFilteringSet enabled, skip as it is not supported
|
||||
continue
|
||||
}
|
||||
|
||||
for _, subTableOffset := range subTableOffsets {
|
||||
buf, err = f.src.view(buf, int(subTableOffset), 4)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
format := u16(buf)
|
||||
|
||||
var lookupIndex indexLookupFunc
|
||||
buf, lookupIndex, err = f.makeCachedCoverageLookup(buf, subTableOffset+int(u16(buf[2:])))
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
switch format {
|
||||
case 1: // Adjustments for Glyph Pairs
|
||||
buf, kern, err := f.parsePairPosFormat1(buf, subTableOffset, lookupIndex)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
if kern != nil {
|
||||
kernFuncs = append(kernFuncs, kern)
|
||||
}
|
||||
case 2: // Class Pair Adjustment
|
||||
buf, kern, err := f.parsePairPosFormat2(buf, subTableOffset, lookupIndex)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
if kern != nil {
|
||||
kernFuncs = append(kernFuncs, kern)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf, kernFuncs, nil
|
||||
}
|
||||
|
||||
func (f *Font) parsePairPosFormat1(buf []byte, offset int, lookupIndex indexLookupFunc) ([]byte, kernFunc, error) {
|
||||
// PairPos Format 1: posFormat, coverageOffset, valueFormat1,
|
||||
// valueFormat2, pairSetCount, []pairSetOffsets
|
||||
var err error
|
||||
var nPairs int
|
||||
buf, nPairs, err = f.src.varLenView(buf, offset, 10, 8, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
// check valueFormat1 and valueFormat2 flags
|
||||
if u16(buf[4:]) != 0x04 || u16(buf[6:]) != 0x00 {
|
||||
// we only support kerning with X_ADVANCE for first glyph
|
||||
return buf, nil, nil
|
||||
}
|
||||
|
||||
// PairPos table contains an array of offsets to PairSet
|
||||
// tables, which contains an array of PairValueRecords.
|
||||
// Calculate length of complete PairPos table by jumping to
|
||||
// last PairSet.
|
||||
// We need to iterate all offsets to find the last pair as
|
||||
// offsets are not sorted and can be repeated.
|
||||
var lastPairSetOffset int
|
||||
for n := 0; n < nPairs; n++ {
|
||||
pairOffset := int(u16(buf[10+n*2:]))
|
||||
if pairOffset > lastPairSetOffset {
|
||||
lastPairSetOffset = pairOffset
|
||||
}
|
||||
}
|
||||
buf, err = f.src.view(buf, offset+lastPairSetOffset, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
pairValueCount := int(u16(buf))
|
||||
// Each PairSet contains the secondGlyph (u16) and one or more value records (all u16).
|
||||
// We only support lookup tables with one value record (X_ADVANCE, see valueFormat1/2 above).
|
||||
lastPairSetLength := 2 + pairValueCount*4
|
||||
|
||||
length := lastPairSetOffset + lastPairSetLength
|
||||
buf, err = f.src.view(buf, offset, length)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
kern := makeCachedPairPosGlyph(lookupIndex, nPairs, buf)
|
||||
return buf, kern, nil
|
||||
}
|
||||
|
||||
func (f *Font) parsePairPosFormat2(buf []byte, offset int, lookupIndex indexLookupFunc) ([]byte, kernFunc, error) {
|
||||
// PairPos Format 2:
|
||||
// posFormat, coverageOffset, valueFormat1, valueFormat2,
|
||||
// classDef1Offset, classDef2Offset, class1Count, class2Count,
|
||||
// []class1Records
|
||||
var err error
|
||||
buf, err = f.src.view(buf, offset, 16)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
// check valueFormat1 and valueFormat2 flags
|
||||
if u16(buf[4:]) != 0x04 || u16(buf[6:]) != 0x00 {
|
||||
// we only support kerning with X_ADVANCE for first glyph
|
||||
return buf, nil, nil
|
||||
}
|
||||
numClass1 := int(u16(buf[12:]))
|
||||
numClass2 := int(u16(buf[14:]))
|
||||
cdef1Offset := offset + int(u16(buf[8:]))
|
||||
cdef2Offset := offset + int(u16(buf[10:]))
|
||||
var cdef1, cdef2 classLookupFunc
|
||||
buf, cdef1, err = f.makeCachedClassLookup(buf, cdef1Offset)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
buf, cdef2, err = f.makeCachedClassLookup(buf, cdef2Offset)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
buf, err = f.src.view(buf, offset+16, numClass1*numClass2*2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
kern := makeCachedPairPosClass(
|
||||
lookupIndex,
|
||||
numClass1,
|
||||
numClass2,
|
||||
cdef1,
|
||||
cdef2,
|
||||
buf,
|
||||
)
|
||||
|
||||
return buf, kern, nil
|
||||
}
|
||||
|
||||
// parseGPOSScriptFeatures returns all indices of features in FeatureTable that
|
||||
// are valid for the given script.
|
||||
// Returns features from DefaultLangSys, different languages are not supported.
|
||||
// However, all observed fonts either do not use different languages or use the
|
||||
// same features as DefaultLangSys.
|
||||
func (f *Font) parseGPOSScriptFeatures(buf []byte, offset int, script uint32) ([]byte, []int, error) {
|
||||
// ScriptList table: scriptCount, []scriptRecords{scriptTag, scriptOffset}
|
||||
buf, numScriptTables, err := f.src.varLenView(buf, offset, 2, 0, 6)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
// Search ScriptTables for script
|
||||
var scriptTableOffset uint16
|
||||
for i := 0; i < numScriptTables; i++ {
|
||||
scriptTag := u32(buf[2+i*6:])
|
||||
if scriptTag == script {
|
||||
scriptTableOffset = u16(buf[2+i*6+4:])
|
||||
break
|
||||
}
|
||||
}
|
||||
if scriptTableOffset == 0 {
|
||||
return buf, nil, nil
|
||||
}
|
||||
|
||||
// Script table: defaultLangSys, langSysCount, []langSysRecords{langSysTag, langSysOffset}
|
||||
buf, err = f.src.view(buf, offset+int(scriptTableOffset), 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
defaultLangSysOffset := u16(buf)
|
||||
|
||||
if defaultLangSysOffset == 0 {
|
||||
return buf, nil, nil
|
||||
}
|
||||
|
||||
// LangSys table: lookupOrder (reserved), requiredFeatureIndex, featureIndexCount, []featureIndices
|
||||
buf, numFeatures, err := f.src.varLenView(buf, offset+int(scriptTableOffset)+int(defaultLangSysOffset), 6, 4, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
featureIdxs := make([]int, numFeatures)
|
||||
for i := range featureIdxs {
|
||||
featureIdxs[i] = int(u16(buf[6+i*2:]))
|
||||
}
|
||||
return buf, featureIdxs, nil
|
||||
}
|
||||
|
||||
func (f *Font) parseGPOSFeaturesLookup(buf []byte, offset int, featureIdxs []int, feature uint32) ([]byte, []int, error) {
|
||||
// FeatureList table: featureCount, []featureRecords{featureTag, featureOffset}
|
||||
buf, numFeatureTables, err := f.src.varLenView(buf, offset, 2, 0, 6)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
lookupIdx := make([]int, 0, 4)
|
||||
|
||||
for _, fidx := range featureIdxs {
|
||||
if fidx > numFeatureTables {
|
||||
return buf, nil, errInvalidGPOSTable
|
||||
}
|
||||
featureTag := u32(buf[2+fidx*6:])
|
||||
if featureTag != feature {
|
||||
continue
|
||||
}
|
||||
featureOffset := u16(buf[2+fidx*6+4:])
|
||||
|
||||
buf, numLookups, err := f.src.varLenView(nil, offset+int(featureOffset), 4, 2, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < numLookups; i++ {
|
||||
lookupIdx = append(lookupIdx, int(u16(buf[4+i*2:])))
|
||||
}
|
||||
}
|
||||
|
||||
return buf, lookupIdx, nil
|
||||
}
|
||||
|
||||
func makeCachedPairPosGlyph(cov indexLookupFunc, num int, buf []byte) kernFunc {
|
||||
glyphs := make([]byte, len(buf))
|
||||
copy(glyphs, buf)
|
||||
return func(a, b GlyphIndex) (int16, error) {
|
||||
idx, found := cov(a)
|
||||
if !found {
|
||||
return 0, ErrNotFound
|
||||
}
|
||||
if idx >= num {
|
||||
return 0, ErrNotFound
|
||||
}
|
||||
offset := int(u16(glyphs[10+idx*2:]))
|
||||
if offset+1 >= len(glyphs) {
|
||||
return 0, errInvalidGPOSTable
|
||||
}
|
||||
|
||||
count := int(u16(glyphs[offset:]))
|
||||
for i := 0; i < count; i++ {
|
||||
secondGlyphIndex := GlyphIndex(int(u16(glyphs[offset+2+i*4:])))
|
||||
if secondGlyphIndex == b {
|
||||
return int16(u16(glyphs[offset+2+i*4+2:])), nil
|
||||
}
|
||||
if secondGlyphIndex > b {
|
||||
return 0, ErrNotFound
|
||||
}
|
||||
}
|
||||
|
||||
return 0, ErrNotFound
|
||||
}
|
||||
}
|
||||
|
||||
func makeCachedPairPosClass(cov indexLookupFunc, num1, num2 int, cdef1, cdef2 classLookupFunc, buf []byte) kernFunc {
|
||||
glyphs := make([]byte, len(buf))
|
||||
copy(glyphs, buf)
|
||||
return func(a, b GlyphIndex) (int16, error) {
|
||||
// check coverage to avoid selection of default class 0
|
||||
_, found := cov(a)
|
||||
if !found {
|
||||
return 0, ErrNotFound
|
||||
}
|
||||
idxa := cdef1(a)
|
||||
idxb := cdef2(b)
|
||||
return int16(u16(glyphs[(idxb+idxa*num2)*2:])), nil
|
||||
}
|
||||
}
|
||||
|
||||
// indexLookupFunc returns the index into a PairPos table for the provided glyph.
|
||||
// Returns false if the glyph is not covered by this lookup.
|
||||
type indexLookupFunc func(GlyphIndex) (int, bool)
|
||||
|
||||
func (f *Font) makeCachedCoverageLookup(buf []byte, offset int) ([]byte, indexLookupFunc, error) {
|
||||
var err error
|
||||
buf, err = f.src.view(buf, offset, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
switch u16(buf) {
|
||||
case 1:
|
||||
// Coverage Format 1: coverageFormat, glyphCount, []glyphArray
|
||||
buf, _, err = f.src.varLenView(buf, offset, 4, 2, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
return buf, makeCachedCoverageList(buf[2:]), nil
|
||||
case 2:
|
||||
// Coverage Format 2: coverageFormat, rangeCount, []rangeRecords{startGlyphID, endGlyphID, startCoverageIndex}
|
||||
buf, _, err = f.src.varLenView(buf, offset, 4, 2, 6)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
return buf, makeCachedCoverageRange(buf[2:]), nil
|
||||
default:
|
||||
return buf, nil, errUnsupportedCoverageFormat
|
||||
}
|
||||
}
|
||||
|
||||
func makeCachedCoverageList(buf []byte) indexLookupFunc {
|
||||
num := int(u16(buf))
|
||||
list := make([]byte, len(buf)-2)
|
||||
copy(list, buf[2:])
|
||||
return func(gi GlyphIndex) (int, bool) {
|
||||
idx := sort.Search(num, func(i int) bool {
|
||||
return gi <= GlyphIndex(u16(list[i*2:]))
|
||||
})
|
||||
if idx < num && GlyphIndex(u16(list[idx*2:])) == gi {
|
||||
return idx, true
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
func makeCachedCoverageRange(buf []byte) indexLookupFunc {
|
||||
num := int(u16(buf))
|
||||
ranges := make([]byte, len(buf)-2)
|
||||
copy(ranges, buf[2:])
|
||||
return func(gi GlyphIndex) (int, bool) {
|
||||
if num == 0 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// ranges is an array of startGlyphID, endGlyphID and startCoverageIndex
|
||||
// Ranges are non-overlapping.
|
||||
// The following GlyphIDs/index pairs are stored as follows:
|
||||
// pairs: 130=0, 131=1, 132=2, 133=3, 134=4, 135=5, 137=6
|
||||
// ranges: 130, 135, 0 137, 137, 6
|
||||
// startCoverageIndex is used to calculate the index without counting
|
||||
// the length of the preceding ranges
|
||||
|
||||
idx := sort.Search(num, func(i int) bool {
|
||||
return gi <= GlyphIndex(u16(ranges[i*6:]))
|
||||
})
|
||||
// idx either points to a matching start, or to the next range (or idx==num)
|
||||
// e.g. with the range example from above: 130 points to 130-135 range, 133 points to 137-137 range
|
||||
|
||||
// check if gi is the start of a range, but only if sort.Search returned a valid result
|
||||
if idx < num {
|
||||
if start := u16(ranges[idx*6:]); gi == GlyphIndex(start) {
|
||||
return int(u16(ranges[idx*6+4:])), true
|
||||
}
|
||||
}
|
||||
// check if gi is in previous range
|
||||
if idx > 0 {
|
||||
idx--
|
||||
start, end := u16(ranges[idx*6:]), u16(ranges[idx*6+2:])
|
||||
if gi >= GlyphIndex(start) && gi <= GlyphIndex(end) {
|
||||
return int(u16(ranges[idx*6+4:]) + uint16(gi) - start), true
|
||||
}
|
||||
}
|
||||
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
|
||||
// classLookupFunc returns the class ID for the provided glyph. Returns 0
|
||||
// (default class) for glyphs not covered by this lookup.
|
||||
type classLookupFunc func(GlyphIndex) int
|
||||
|
||||
func (f *Font) makeCachedClassLookup(buf []byte, offset int) ([]byte, classLookupFunc, error) {
|
||||
var err error
|
||||
buf, err = f.src.view(buf, offset, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
switch u16(buf) {
|
||||
case 1:
|
||||
// ClassDefFormat 1: classFormat, startGlyphID, glyphCount, []classValueArray
|
||||
buf, _, err = f.src.varLenView(buf, offset, 6, 4, 2)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
return buf, makeCachedClassLookupFormat1(buf), nil
|
||||
case 2:
|
||||
// ClassDefFormat 2: classFormat, classRangeCount, []classRangeRecords
|
||||
buf, _, err = f.src.varLenView(buf, offset, 4, 2, 6)
|
||||
if err != nil {
|
||||
return buf, nil, err
|
||||
}
|
||||
return buf, makeCachedClassLookupFormat2(buf), nil
|
||||
default:
|
||||
return buf, nil, errUnsupportedClassDefFormat
|
||||
}
|
||||
}
|
||||
|
||||
func makeCachedClassLookupFormat1(buf []byte) classLookupFunc {
|
||||
startGI := u16(buf[2:])
|
||||
num := u16(buf[4:])
|
||||
classIDs := make([]byte, len(buf)-4)
|
||||
copy(classIDs, buf[6:])
|
||||
|
||||
return func(gi GlyphIndex) int {
|
||||
// classIDs is an array of target class IDs. gi is the index into that array (minus startGI).
|
||||
if gi < GlyphIndex(startGI) || gi >= GlyphIndex(startGI+num) {
|
||||
// default to class 0
|
||||
return 0
|
||||
}
|
||||
return int(u16(classIDs[(int(gi)-int(startGI))*2:]))
|
||||
}
|
||||
}
|
||||
|
||||
func makeCachedClassLookupFormat2(buf []byte) classLookupFunc {
|
||||
num := int(u16(buf[2:]))
|
||||
classRanges := make([]byte, len(buf)-2)
|
||||
copy(classRanges, buf[4:])
|
||||
|
||||
return func(gi GlyphIndex) int {
|
||||
if num == 0 {
|
||||
return 0 // default to class 0
|
||||
}
|
||||
|
||||
// classRange is an array of startGlyphID, endGlyphID and target class ID.
|
||||
// Ranges are non-overlapping.
|
||||
// E.g. 130, 135, 1 137, 137, 5 etc
|
||||
|
||||
idx := sort.Search(num, func(i int) bool {
|
||||
return gi <= GlyphIndex(u16(classRanges[i*6:]))
|
||||
})
|
||||
// idx either points to a matching start, or to the next range (or idx==num)
|
||||
// e.g. with the range example from above: 130 points to 130-135 range, 133 points to 137-137 range
|
||||
|
||||
// check if gi is the start of a range, but only if sort.Search returned a valid result
|
||||
if idx < num {
|
||||
if start := u16(classRanges[idx*6:]); gi == GlyphIndex(start) {
|
||||
return int(u16(classRanges[idx*6+4:]))
|
||||
}
|
||||
}
|
||||
// check if gi is in previous range
|
||||
if idx > 0 {
|
||||
idx--
|
||||
start, end := u16(classRanges[idx*6:]), u16(classRanges[idx*6+2:])
|
||||
if gi >= GlyphIndex(start) && gi <= GlyphIndex(end) {
|
||||
return int(u16(classRanges[idx*6+4:]))
|
||||
}
|
||||
}
|
||||
// default to class 0
|
||||
return 0
|
||||
}
|
||||
}
|
||||
+1426
File diff suppressed because it is too large
Load Diff
+2014
File diff suppressed because it is too large
Load Diff
+578
@@ -0,0 +1,578 @@
|
||||
// Copyright 2017 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sfnt
|
||||
|
||||
import (
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
// Flags for simple (non-compound) glyphs.
|
||||
//
|
||||
// See https://www.microsoft.com/typography/OTSPEC/glyf.htm
|
||||
const (
|
||||
flagOnCurve = 1 << 0 // 0x0001
|
||||
flagXShortVector = 1 << 1 // 0x0002
|
||||
flagYShortVector = 1 << 2 // 0x0004
|
||||
flagRepeat = 1 << 3 // 0x0008
|
||||
|
||||
// The same flag bits are overloaded to have two meanings, dependent on the
|
||||
// value of the flag{X,Y}ShortVector bits.
|
||||
flagPositiveXShortVector = 1 << 4 // 0x0010
|
||||
flagThisXIsSame = 1 << 4 // 0x0010
|
||||
flagPositiveYShortVector = 1 << 5 // 0x0020
|
||||
flagThisYIsSame = 1 << 5 // 0x0020
|
||||
)
|
||||
|
||||
// Flags for compound glyphs.
|
||||
//
|
||||
// See https://www.microsoft.com/typography/OTSPEC/glyf.htm
|
||||
const (
|
||||
flagArg1And2AreWords = 1 << 0 // 0x0001
|
||||
flagArgsAreXYValues = 1 << 1 // 0x0002
|
||||
flagRoundXYToGrid = 1 << 2 // 0x0004
|
||||
flagWeHaveAScale = 1 << 3 // 0x0008
|
||||
flagReserved4 = 1 << 4 // 0x0010
|
||||
flagMoreComponents = 1 << 5 // 0x0020
|
||||
flagWeHaveAnXAndYScale = 1 << 6 // 0x0040
|
||||
flagWeHaveATwoByTwo = 1 << 7 // 0x0080
|
||||
flagWeHaveInstructions = 1 << 8 // 0x0100
|
||||
flagUseMyMetrics = 1 << 9 // 0x0200
|
||||
flagOverlapCompound = 1 << 10 // 0x0400
|
||||
flagScaledComponentOffset = 1 << 11 // 0x0800
|
||||
flagUnscaledComponentOffset = 1 << 12 // 0x1000
|
||||
)
|
||||
|
||||
func midPoint(p, q fixed.Point26_6) fixed.Point26_6 {
|
||||
return fixed.Point26_6{
|
||||
X: (p.X + q.X) / 2,
|
||||
Y: (p.Y + q.Y) / 2,
|
||||
}
|
||||
}
|
||||
|
||||
func parseLoca(src *source, loca table, glyfOffset uint32, indexToLocFormat bool, numGlyphs int32) (locations []uint32, err error) {
|
||||
if indexToLocFormat {
|
||||
if loca.length != 4*uint32(numGlyphs+1) {
|
||||
return nil, errInvalidLocaTable
|
||||
}
|
||||
} else {
|
||||
if loca.length != 2*uint32(numGlyphs+1) {
|
||||
return nil, errInvalidLocaTable
|
||||
}
|
||||
}
|
||||
|
||||
locations = make([]uint32, numGlyphs+1)
|
||||
buf, err := src.view(nil, int(loca.offset), int(loca.length))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if indexToLocFormat {
|
||||
for i := range locations {
|
||||
locations[i] = 1*uint32(u32(buf[4*i:])) + glyfOffset
|
||||
}
|
||||
} else {
|
||||
for i := range locations {
|
||||
locations[i] = 2*uint32(u16(buf[2*i:])) + glyfOffset
|
||||
}
|
||||
}
|
||||
return locations, nil
|
||||
}
|
||||
|
||||
// https://www.microsoft.com/typography/OTSPEC/glyf.htm says that "Each
|
||||
// glyph begins with the following [10 byte] header".
|
||||
const glyfHeaderLen = 10
|
||||
|
||||
func loadGlyf(f *Font, b *Buffer, x GlyphIndex, stackBottom, recursionDepth uint32) error {
|
||||
data, _, _, err := f.viewGlyphData(b, x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(data) < glyfHeaderLen {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
index := glyfHeaderLen
|
||||
|
||||
numContours, numPoints := int16(u16(data)), 0
|
||||
switch {
|
||||
case numContours == -1:
|
||||
// We have a compound glyph. No-op.
|
||||
case numContours == 0:
|
||||
return nil
|
||||
case numContours > 0:
|
||||
// We have a simple (non-compound) glyph.
|
||||
index += 2 * int(numContours)
|
||||
if index > len(data) {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
// The +1 for numPoints is because the value in the file format is
|
||||
// inclusive, but Go's slice[:index] semantics are exclusive.
|
||||
numPoints = 1 + int(u16(data[index-2:]))
|
||||
default:
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
|
||||
if numContours < 0 {
|
||||
return loadCompoundGlyf(f, b, data[glyfHeaderLen:], stackBottom, recursionDepth)
|
||||
}
|
||||
|
||||
// Skip the hinting instructions.
|
||||
index += 2
|
||||
if index > len(data) {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
hintsLength := int(u16(data[index-2:]))
|
||||
index += hintsLength
|
||||
if index > len(data) {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
|
||||
// For simple (non-compound) glyphs, the remainder of the glyf data
|
||||
// consists of (flags, x, y) points: the Bézier curve segments. These are
|
||||
// stored in columns (all the flags first, then all the x coordinates, then
|
||||
// all the y coordinates), not rows, as it compresses better.
|
||||
//
|
||||
// Decoding those points in row order involves two passes. The first pass
|
||||
// determines the indexes (relative to the data slice) of where the flags,
|
||||
// the x coordinates and the y coordinates each start.
|
||||
flagIndex := int32(index)
|
||||
xIndex, yIndex, ok := findXYIndexes(data, index, numPoints)
|
||||
if !ok {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
|
||||
// The second pass decodes each (flags, x, y) tuple in row order.
|
||||
g := glyfIter{
|
||||
data: data,
|
||||
flagIndex: flagIndex,
|
||||
xIndex: xIndex,
|
||||
yIndex: yIndex,
|
||||
endIndex: glyfHeaderLen,
|
||||
// The -1 on prevEnd and finalEnd are because the contour-end index in
|
||||
// the file format is inclusive, but Go's slice[:index] is exclusive.
|
||||
prevEnd: -1,
|
||||
finalEnd: int32(numPoints - 1),
|
||||
numContours: int32(numContours),
|
||||
}
|
||||
for g.nextContour() {
|
||||
for g.nextSegment() {
|
||||
b.segments = append(b.segments, g.seg)
|
||||
}
|
||||
}
|
||||
return g.err
|
||||
}
|
||||
|
||||
func findXYIndexes(data []byte, index, numPoints int) (xIndex, yIndex int32, ok bool) {
|
||||
xDataLen := 0
|
||||
yDataLen := 0
|
||||
for i := 0; ; {
|
||||
if i > numPoints {
|
||||
return 0, 0, false
|
||||
}
|
||||
if i == numPoints {
|
||||
break
|
||||
}
|
||||
|
||||
repeatCount := 1
|
||||
if index >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
flag := data[index]
|
||||
index++
|
||||
if flag&flagRepeat != 0 {
|
||||
if index >= len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
repeatCount += int(data[index])
|
||||
index++
|
||||
}
|
||||
|
||||
xSize := 0
|
||||
if flag&flagXShortVector != 0 {
|
||||
xSize = 1
|
||||
} else if flag&flagThisXIsSame == 0 {
|
||||
xSize = 2
|
||||
}
|
||||
xDataLen += xSize * repeatCount
|
||||
|
||||
ySize := 0
|
||||
if flag&flagYShortVector != 0 {
|
||||
ySize = 1
|
||||
} else if flag&flagThisYIsSame == 0 {
|
||||
ySize = 2
|
||||
}
|
||||
yDataLen += ySize * repeatCount
|
||||
|
||||
i += repeatCount
|
||||
}
|
||||
if index+xDataLen+yDataLen > len(data) {
|
||||
return 0, 0, false
|
||||
}
|
||||
return int32(index), int32(index + xDataLen), true
|
||||
}
|
||||
|
||||
func loadCompoundGlyf(f *Font, b *Buffer, data []byte, stackBottom, recursionDepth uint32) error {
|
||||
if recursionDepth++; recursionDepth == maxCompoundRecursionDepth {
|
||||
return errUnsupportedCompoundGlyph
|
||||
}
|
||||
|
||||
// Read and process the compound glyph's components. They are two separate
|
||||
// for loops, since reading parses the elements of the data slice, and
|
||||
// processing can overwrite the backing array.
|
||||
|
||||
stackTop := stackBottom
|
||||
for {
|
||||
if stackTop >= maxCompoundStackSize {
|
||||
return errUnsupportedCompoundGlyph
|
||||
}
|
||||
elem := &b.compoundStack[stackTop]
|
||||
stackTop++
|
||||
|
||||
if len(data) < 4 {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
flags := u16(data)
|
||||
elem.glyphIndex = GlyphIndex(u16(data[2:]))
|
||||
if flags&flagArg1And2AreWords == 0 {
|
||||
if len(data) < 6 {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
elem.dx = int16(int8(data[4]))
|
||||
elem.dy = int16(int8(data[5]))
|
||||
data = data[6:]
|
||||
} else {
|
||||
if len(data) < 8 {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
elem.dx = int16(u16(data[4:]))
|
||||
elem.dy = int16(u16(data[6:]))
|
||||
data = data[8:]
|
||||
}
|
||||
|
||||
if flags&flagArgsAreXYValues == 0 {
|
||||
return errUnsupportedCompoundGlyph
|
||||
}
|
||||
elem.hasTransform = flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0
|
||||
if elem.hasTransform {
|
||||
switch {
|
||||
case flags&flagWeHaveAScale != 0:
|
||||
if len(data) < 2 {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
elem.transformXX = int16(u16(data))
|
||||
elem.transformXY = 0
|
||||
elem.transformYX = 0
|
||||
elem.transformYY = elem.transformXX
|
||||
data = data[2:]
|
||||
case flags&flagWeHaveAnXAndYScale != 0:
|
||||
if len(data) < 4 {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
elem.transformXX = int16(u16(data[0:]))
|
||||
elem.transformXY = 0
|
||||
elem.transformYX = 0
|
||||
elem.transformYY = int16(u16(data[2:]))
|
||||
data = data[4:]
|
||||
case flags&flagWeHaveATwoByTwo != 0:
|
||||
if len(data) < 8 {
|
||||
return errInvalidGlyphData
|
||||
}
|
||||
elem.transformXX = int16(u16(data[0:]))
|
||||
elem.transformXY = int16(u16(data[2:]))
|
||||
elem.transformYX = int16(u16(data[4:]))
|
||||
elem.transformYY = int16(u16(data[6:]))
|
||||
data = data[8:]
|
||||
}
|
||||
}
|
||||
|
||||
if flags&flagMoreComponents == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// To support hinting, we'd have to save the remaining bytes in data here
|
||||
// and interpret them after the for loop below, since that for loop's
|
||||
// loadGlyf calls can overwrite the backing array.
|
||||
|
||||
for i := stackBottom; i < stackTop; i++ {
|
||||
elem := &b.compoundStack[i]
|
||||
base := len(b.segments)
|
||||
if err := loadGlyf(f, b, elem.glyphIndex, stackTop, recursionDepth); err != nil {
|
||||
return err
|
||||
}
|
||||
dx, dy := fixed.Int26_6(elem.dx), fixed.Int26_6(elem.dy)
|
||||
segments := b.segments[base:]
|
||||
if elem.hasTransform {
|
||||
txx := elem.transformXX
|
||||
txy := elem.transformXY
|
||||
tyx := elem.transformYX
|
||||
tyy := elem.transformYY
|
||||
for j := range segments {
|
||||
transformArgs(&segments[j].Args, txx, txy, tyx, tyy, dx, dy)
|
||||
}
|
||||
} else {
|
||||
for j := range segments {
|
||||
translateArgs(&segments[j].Args, dx, dy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type glyfIter struct {
|
||||
data []byte
|
||||
err error
|
||||
|
||||
// Various indices into the data slice. See the "Decoding those points in
|
||||
// row order" comment above.
|
||||
flagIndex int32
|
||||
xIndex int32
|
||||
yIndex int32
|
||||
|
||||
// endIndex points to the uint16 that is the inclusive point index of the
|
||||
// current contour's end. prevEnd is the previous contour's end. finalEnd
|
||||
// should match the final contour's end.
|
||||
endIndex int32
|
||||
prevEnd int32
|
||||
finalEnd int32
|
||||
|
||||
// c and p count the current contour and point, up to numContours and
|
||||
// numPoints.
|
||||
c, numContours int32
|
||||
p, nPoints int32
|
||||
|
||||
// The next two groups of fields track points and segments. Points are what
|
||||
// the underlying file format provides. Bézier curve segments are what the
|
||||
// rasterizer consumes.
|
||||
//
|
||||
// Points are either on-curve or off-curve. Two consecutive on-curve points
|
||||
// define a linear curve segment between them. N off-curve points between
|
||||
// on-curve points define N quadratic curve segments. The TrueType glyf
|
||||
// format does not use cubic curves. If N is greater than 1, some of these
|
||||
// segment end points are implicit, the midpoint of two off-curve points.
|
||||
// Given the points A, B1, B2, ..., BN, C, where A and C are on-curve and
|
||||
// all the Bs are off-curve, the segments are:
|
||||
//
|
||||
// - A, B1, midpoint(B1, B2)
|
||||
// - midpoint(B1, B2), B2, midpoint(B2, B3)
|
||||
// - midpoint(B2, B3), B3, midpoint(B3, B4)
|
||||
// - ...
|
||||
// - midpoint(BN-1, BN), BN, C
|
||||
//
|
||||
// Note that the sequence of Bs may wrap around from the last point in the
|
||||
// glyf data to the first. A and C may also be the same point (the only
|
||||
// explicit on-curve point), or there may be no explicit on-curve points at
|
||||
// all (but still implicit ones between explicit off-curve points).
|
||||
|
||||
// Points.
|
||||
x, y int16
|
||||
on bool
|
||||
flag uint8
|
||||
repeats uint8
|
||||
|
||||
// Segments.
|
||||
closing bool
|
||||
closed bool
|
||||
firstOnCurveValid bool
|
||||
firstOffCurveValid bool
|
||||
lastOffCurveValid bool
|
||||
firstOnCurve fixed.Point26_6
|
||||
firstOffCurve fixed.Point26_6
|
||||
lastOffCurve fixed.Point26_6
|
||||
seg Segment
|
||||
}
|
||||
|
||||
func (g *glyfIter) nextContour() (ok bool) {
|
||||
if g.c == g.numContours {
|
||||
if g.prevEnd != g.finalEnd {
|
||||
g.err = errInvalidGlyphData
|
||||
}
|
||||
return false
|
||||
}
|
||||
g.c++
|
||||
|
||||
end := int32(u16(g.data[g.endIndex:]))
|
||||
g.endIndex += 2
|
||||
if (end <= g.prevEnd) || (g.finalEnd < end) {
|
||||
g.err = errInvalidGlyphData
|
||||
return false
|
||||
}
|
||||
g.nPoints = end - g.prevEnd
|
||||
g.p = 0
|
||||
g.prevEnd = end
|
||||
|
||||
g.closing = false
|
||||
g.closed = false
|
||||
g.firstOnCurveValid = false
|
||||
g.firstOffCurveValid = false
|
||||
g.lastOffCurveValid = false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *glyfIter) close() {
|
||||
switch {
|
||||
case !g.firstOffCurveValid && !g.lastOffCurveValid:
|
||||
g.closed = true
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpLineTo,
|
||||
Args: [3]fixed.Point26_6{g.firstOnCurve},
|
||||
}
|
||||
case !g.firstOffCurveValid && g.lastOffCurveValid:
|
||||
g.closed = true
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpQuadTo,
|
||||
Args: [3]fixed.Point26_6{g.lastOffCurve, g.firstOnCurve},
|
||||
}
|
||||
case g.firstOffCurveValid && !g.lastOffCurveValid:
|
||||
g.closed = true
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpQuadTo,
|
||||
Args: [3]fixed.Point26_6{g.firstOffCurve, g.firstOnCurve},
|
||||
}
|
||||
case g.firstOffCurveValid && g.lastOffCurveValid:
|
||||
g.lastOffCurveValid = false
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpQuadTo,
|
||||
Args: [3]fixed.Point26_6{
|
||||
g.lastOffCurve,
|
||||
midPoint(g.lastOffCurve, g.firstOffCurve),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *glyfIter) nextSegment() (ok bool) {
|
||||
for !g.closed {
|
||||
if g.closing || !g.nextPoint() {
|
||||
g.closing = true
|
||||
g.close()
|
||||
return true
|
||||
}
|
||||
|
||||
// Convert the tuple (g.x, g.y) to a fixed.Point26_6, since the latter
|
||||
// is what's held in a Segment. The input (g.x, g.y) is a pair of int16
|
||||
// values, measured in font units, since that is what the underlying
|
||||
// format provides. The output is a pair of fixed.Int26_6 values. A
|
||||
// fixed.Int26_6 usually represents a 26.6 fixed number of pixels, but
|
||||
// this here is just a straight numerical conversion, with no scaling
|
||||
// factor. A later step scales the Segment.Args values by such a factor
|
||||
// to convert e.g. 1792 font units to 10.5 pixels at 2048 font units
|
||||
// per em and 12 ppem (pixels per em).
|
||||
p := fixed.Point26_6{
|
||||
X: fixed.Int26_6(g.x),
|
||||
Y: fixed.Int26_6(g.y),
|
||||
}
|
||||
|
||||
if !g.firstOnCurveValid {
|
||||
if g.on {
|
||||
g.firstOnCurve = p
|
||||
g.firstOnCurveValid = true
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpMoveTo,
|
||||
Args: [3]fixed.Point26_6{p},
|
||||
}
|
||||
return true
|
||||
} else if !g.firstOffCurveValid {
|
||||
g.firstOffCurve = p
|
||||
g.firstOffCurveValid = true
|
||||
continue
|
||||
} else {
|
||||
g.firstOnCurve = midPoint(g.firstOffCurve, p)
|
||||
g.firstOnCurveValid = true
|
||||
g.lastOffCurve = p
|
||||
g.lastOffCurveValid = true
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpMoveTo,
|
||||
Args: [3]fixed.Point26_6{g.firstOnCurve},
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
} else if !g.lastOffCurveValid {
|
||||
if !g.on {
|
||||
g.lastOffCurve = p
|
||||
g.lastOffCurveValid = true
|
||||
continue
|
||||
} else {
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpLineTo,
|
||||
Args: [3]fixed.Point26_6{p},
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
} else {
|
||||
if !g.on {
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpQuadTo,
|
||||
Args: [3]fixed.Point26_6{
|
||||
g.lastOffCurve,
|
||||
midPoint(g.lastOffCurve, p),
|
||||
},
|
||||
}
|
||||
g.lastOffCurve = p
|
||||
g.lastOffCurveValid = true
|
||||
return true
|
||||
} else {
|
||||
g.seg = Segment{
|
||||
Op: SegmentOpQuadTo,
|
||||
Args: [3]fixed.Point26_6{g.lastOffCurve, p},
|
||||
}
|
||||
g.lastOffCurveValid = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *glyfIter) nextPoint() (ok bool) {
|
||||
if g.p == g.nPoints {
|
||||
return false
|
||||
}
|
||||
g.p++
|
||||
|
||||
if g.repeats > 0 {
|
||||
g.repeats--
|
||||
} else {
|
||||
g.flag = g.data[g.flagIndex]
|
||||
g.flagIndex++
|
||||
if g.flag&flagRepeat != 0 {
|
||||
g.repeats = g.data[g.flagIndex]
|
||||
g.flagIndex++
|
||||
}
|
||||
}
|
||||
|
||||
if g.flag&flagXShortVector != 0 {
|
||||
if g.flag&flagPositiveXShortVector != 0 {
|
||||
g.x += int16(g.data[g.xIndex])
|
||||
} else {
|
||||
g.x -= int16(g.data[g.xIndex])
|
||||
}
|
||||
g.xIndex += 1
|
||||
} else if g.flag&flagThisXIsSame == 0 {
|
||||
g.x += int16(u16(g.data[g.xIndex:]))
|
||||
g.xIndex += 2
|
||||
}
|
||||
|
||||
if g.flag&flagYShortVector != 0 {
|
||||
if g.flag&flagPositiveYShortVector != 0 {
|
||||
g.y += int16(g.data[g.yIndex])
|
||||
} else {
|
||||
g.y -= int16(g.data[g.yIndex])
|
||||
}
|
||||
g.yIndex += 1
|
||||
} else if g.flag&flagThisYIsSame == 0 {
|
||||
g.y += int16(u16(g.data[g.yIndex:]))
|
||||
g.yIndex += 2
|
||||
}
|
||||
|
||||
g.on = g.flag&flagOnCurve != 0
|
||||
return true
|
||||
}
|
||||
+410
@@ -0,0 +1,410 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package fixed implements fixed-point integer types.
|
||||
package fixed // import "golang.org/x/image/math/fixed"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TODO: implement fmt.Formatter for %f and %g.
|
||||
|
||||
// I returns the integer value i as an Int26_6.
|
||||
//
|
||||
// For example, passing the integer value 2 yields Int26_6(128).
|
||||
func I(i int) Int26_6 {
|
||||
return Int26_6(i << 6)
|
||||
}
|
||||
|
||||
// Int26_6 is a signed 26.6 fixed-point number.
|
||||
//
|
||||
// The integer part ranges from -33554432 to 33554431, inclusive. The
|
||||
// fractional part has 6 bits of precision.
|
||||
//
|
||||
// For example, the number one-and-a-quarter is Int26_6(1<<6 + 1<<4).
|
||||
type Int26_6 int32
|
||||
|
||||
// String returns a human-readable representation of a 26.6 fixed-point number.
|
||||
//
|
||||
// For example, the number one-and-a-quarter becomes "1:16".
|
||||
func (x Int26_6) String() string {
|
||||
const shift, mask = 6, 1<<6 - 1
|
||||
if x >= 0 {
|
||||
return fmt.Sprintf("%d:%02d", int32(x>>shift), int32(x&mask))
|
||||
}
|
||||
x = -x
|
||||
if x >= 0 {
|
||||
return fmt.Sprintf("-%d:%02d", int32(x>>shift), int32(x&mask))
|
||||
}
|
||||
return "-33554432:00" // The minimum value is -(1<<25).
|
||||
}
|
||||
|
||||
// Floor returns the greatest integer value less than or equal to x.
|
||||
//
|
||||
// Its return type is int, not Int26_6.
|
||||
func (x Int26_6) Floor() int { return int((x + 0x00) >> 6) }
|
||||
|
||||
// Round returns the nearest integer value to x. Ties are rounded up.
|
||||
//
|
||||
// Its return type is int, not Int26_6.
|
||||
func (x Int26_6) Round() int { return int((x + 0x20) >> 6) }
|
||||
|
||||
// Ceil returns the least integer value greater than or equal to x.
|
||||
//
|
||||
// Its return type is int, not Int26_6.
|
||||
func (x Int26_6) Ceil() int { return int((x + 0x3f) >> 6) }
|
||||
|
||||
// Mul returns x*y in 26.6 fixed-point arithmetic.
|
||||
func (x Int26_6) Mul(y Int26_6) Int26_6 {
|
||||
return Int26_6((int64(x)*int64(y) + 1<<5) >> 6)
|
||||
}
|
||||
|
||||
// Int52_12 is a signed 52.12 fixed-point number.
|
||||
//
|
||||
// The integer part ranges from -2251799813685248 to 2251799813685247,
|
||||
// inclusive. The fractional part has 12 bits of precision.
|
||||
//
|
||||
// For example, the number one-and-a-quarter is Int52_12(1<<12 + 1<<10).
|
||||
type Int52_12 int64
|
||||
|
||||
// String returns a human-readable representation of a 52.12 fixed-point
|
||||
// number.
|
||||
//
|
||||
// For example, the number one-and-a-quarter becomes "1:1024".
|
||||
func (x Int52_12) String() string {
|
||||
const shift, mask = 12, 1<<12 - 1
|
||||
if x >= 0 {
|
||||
return fmt.Sprintf("%d:%04d", int64(x>>shift), int64(x&mask))
|
||||
}
|
||||
x = -x
|
||||
if x >= 0 {
|
||||
return fmt.Sprintf("-%d:%04d", int64(x>>shift), int64(x&mask))
|
||||
}
|
||||
return "-2251799813685248:0000" // The minimum value is -(1<<51).
|
||||
}
|
||||
|
||||
// Floor returns the greatest integer value less than or equal to x.
|
||||
//
|
||||
// Its return type is int, not Int52_12.
|
||||
func (x Int52_12) Floor() int { return int((x + 0x000) >> 12) }
|
||||
|
||||
// Round returns the nearest integer value to x. Ties are rounded up.
|
||||
//
|
||||
// Its return type is int, not Int52_12.
|
||||
func (x Int52_12) Round() int { return int((x + 0x800) >> 12) }
|
||||
|
||||
// Ceil returns the least integer value greater than or equal to x.
|
||||
//
|
||||
// Its return type is int, not Int52_12.
|
||||
func (x Int52_12) Ceil() int { return int((x + 0xfff) >> 12) }
|
||||
|
||||
// Mul returns x*y in 52.12 fixed-point arithmetic.
|
||||
func (x Int52_12) Mul(y Int52_12) Int52_12 {
|
||||
const M, N = 52, 12
|
||||
lo, hi := muli64(int64(x), int64(y))
|
||||
ret := Int52_12(hi<<M | lo>>N)
|
||||
ret += Int52_12((lo >> (N - 1)) & 1) // Round to nearest, instead of rounding down.
|
||||
return ret
|
||||
}
|
||||
|
||||
// muli64 multiplies two int64 values, returning the 128-bit signed integer
|
||||
// result as two uint64 values.
|
||||
//
|
||||
// This implementation is similar to $GOROOT/src/runtime/softfloat64.go's mullu
|
||||
// function, which is in turn adapted from Hacker's Delight.
|
||||
func muli64(u, v int64) (lo, hi uint64) {
|
||||
const (
|
||||
s = 32
|
||||
mask = 1<<s - 1
|
||||
)
|
||||
|
||||
u1 := uint64(u >> s)
|
||||
u0 := uint64(u & mask)
|
||||
v1 := uint64(v >> s)
|
||||
v0 := uint64(v & mask)
|
||||
|
||||
w0 := u0 * v0
|
||||
t := u1*v0 + w0>>s
|
||||
w1 := t & mask
|
||||
w2 := uint64(int64(t) >> s)
|
||||
w1 += u0 * v1
|
||||
return uint64(u) * uint64(v), u1*v1 + w2 + uint64(int64(w1)>>s)
|
||||
}
|
||||
|
||||
// P returns the integer values x and y as a Point26_6.
|
||||
//
|
||||
// For example, passing the integer values (2, -3) yields Point26_6{128, -192}.
|
||||
func P(x, y int) Point26_6 {
|
||||
return Point26_6{Int26_6(x << 6), Int26_6(y << 6)}
|
||||
}
|
||||
|
||||
// Point26_6 is a 26.6 fixed-point coordinate pair.
|
||||
//
|
||||
// It is analogous to the image.Point type in the standard library.
|
||||
type Point26_6 struct {
|
||||
X, Y Int26_6
|
||||
}
|
||||
|
||||
// Add returns the vector p+q.
|
||||
func (p Point26_6) Add(q Point26_6) Point26_6 {
|
||||
return Point26_6{p.X + q.X, p.Y + q.Y}
|
||||
}
|
||||
|
||||
// Sub returns the vector p-q.
|
||||
func (p Point26_6) Sub(q Point26_6) Point26_6 {
|
||||
return Point26_6{p.X - q.X, p.Y - q.Y}
|
||||
}
|
||||
|
||||
// Mul returns the vector p*k.
|
||||
func (p Point26_6) Mul(k Int26_6) Point26_6 {
|
||||
return Point26_6{p.X * k / 64, p.Y * k / 64}
|
||||
}
|
||||
|
||||
// Div returns the vector p/k.
|
||||
func (p Point26_6) Div(k Int26_6) Point26_6 {
|
||||
return Point26_6{p.X * 64 / k, p.Y * 64 / k}
|
||||
}
|
||||
|
||||
// In returns whether p is in r.
|
||||
func (p Point26_6) In(r Rectangle26_6) bool {
|
||||
return r.Min.X <= p.X && p.X < r.Max.X && r.Min.Y <= p.Y && p.Y < r.Max.Y
|
||||
}
|
||||
|
||||
// Point52_12 is a 52.12 fixed-point coordinate pair.
|
||||
//
|
||||
// It is analogous to the image.Point type in the standard library.
|
||||
type Point52_12 struct {
|
||||
X, Y Int52_12
|
||||
}
|
||||
|
||||
// Add returns the vector p+q.
|
||||
func (p Point52_12) Add(q Point52_12) Point52_12 {
|
||||
return Point52_12{p.X + q.X, p.Y + q.Y}
|
||||
}
|
||||
|
||||
// Sub returns the vector p-q.
|
||||
func (p Point52_12) Sub(q Point52_12) Point52_12 {
|
||||
return Point52_12{p.X - q.X, p.Y - q.Y}
|
||||
}
|
||||
|
||||
// Mul returns the vector p*k.
|
||||
func (p Point52_12) Mul(k Int52_12) Point52_12 {
|
||||
return Point52_12{p.X * k / 4096, p.Y * k / 4096}
|
||||
}
|
||||
|
||||
// Div returns the vector p/k.
|
||||
func (p Point52_12) Div(k Int52_12) Point52_12 {
|
||||
return Point52_12{p.X * 4096 / k, p.Y * 4096 / k}
|
||||
}
|
||||
|
||||
// In returns whether p is in r.
|
||||
func (p Point52_12) In(r Rectangle52_12) bool {
|
||||
return r.Min.X <= p.X && p.X < r.Max.X && r.Min.Y <= p.Y && p.Y < r.Max.Y
|
||||
}
|
||||
|
||||
// R returns the integer values minX, minY, maxX, maxY as a Rectangle26_6.
|
||||
//
|
||||
// For example, passing the integer values (0, 1, 2, 3) yields
|
||||
// Rectangle26_6{Point26_6{0, 64}, Point26_6{128, 192}}.
|
||||
//
|
||||
// Like the image.Rect function in the standard library, the returned rectangle
|
||||
// has minimum and maximum coordinates swapped if necessary so that it is
|
||||
// well-formed.
|
||||
func R(minX, minY, maxX, maxY int) Rectangle26_6 {
|
||||
if minX > maxX {
|
||||
minX, maxX = maxX, minX
|
||||
}
|
||||
if minY > maxY {
|
||||
minY, maxY = maxY, minY
|
||||
}
|
||||
return Rectangle26_6{
|
||||
Point26_6{
|
||||
Int26_6(minX << 6),
|
||||
Int26_6(minY << 6),
|
||||
},
|
||||
Point26_6{
|
||||
Int26_6(maxX << 6),
|
||||
Int26_6(maxY << 6),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Rectangle26_6 is a 26.6 fixed-point coordinate rectangle. The Min bound is
|
||||
// inclusive and the Max bound is exclusive. It is well-formed if Min.X <=
|
||||
// Max.X and likewise for Y.
|
||||
//
|
||||
// It is analogous to the image.Rectangle type in the standard library.
|
||||
type Rectangle26_6 struct {
|
||||
Min, Max Point26_6
|
||||
}
|
||||
|
||||
// Add returns the rectangle r translated by p.
|
||||
func (r Rectangle26_6) Add(p Point26_6) Rectangle26_6 {
|
||||
return Rectangle26_6{
|
||||
Point26_6{r.Min.X + p.X, r.Min.Y + p.Y},
|
||||
Point26_6{r.Max.X + p.X, r.Max.Y + p.Y},
|
||||
}
|
||||
}
|
||||
|
||||
// Sub returns the rectangle r translated by -p.
|
||||
func (r Rectangle26_6) Sub(p Point26_6) Rectangle26_6 {
|
||||
return Rectangle26_6{
|
||||
Point26_6{r.Min.X - p.X, r.Min.Y - p.Y},
|
||||
Point26_6{r.Max.X - p.X, r.Max.Y - p.Y},
|
||||
}
|
||||
}
|
||||
|
||||
// Intersect returns the largest rectangle contained by both r and s. If the
|
||||
// two rectangles do not overlap then the zero rectangle will be returned.
|
||||
func (r Rectangle26_6) Intersect(s Rectangle26_6) Rectangle26_6 {
|
||||
if r.Min.X < s.Min.X {
|
||||
r.Min.X = s.Min.X
|
||||
}
|
||||
if r.Min.Y < s.Min.Y {
|
||||
r.Min.Y = s.Min.Y
|
||||
}
|
||||
if r.Max.X > s.Max.X {
|
||||
r.Max.X = s.Max.X
|
||||
}
|
||||
if r.Max.Y > s.Max.Y {
|
||||
r.Max.Y = s.Max.Y
|
||||
}
|
||||
// Letting r0 and s0 be the values of r and s at the time that the method
|
||||
// is called, this next line is equivalent to:
|
||||
//
|
||||
// if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc }
|
||||
if r.Empty() {
|
||||
return Rectangle26_6{}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Union returns the smallest rectangle that contains both r and s.
|
||||
func (r Rectangle26_6) Union(s Rectangle26_6) Rectangle26_6 {
|
||||
if r.Empty() {
|
||||
return s
|
||||
}
|
||||
if s.Empty() {
|
||||
return r
|
||||
}
|
||||
if r.Min.X > s.Min.X {
|
||||
r.Min.X = s.Min.X
|
||||
}
|
||||
if r.Min.Y > s.Min.Y {
|
||||
r.Min.Y = s.Min.Y
|
||||
}
|
||||
if r.Max.X < s.Max.X {
|
||||
r.Max.X = s.Max.X
|
||||
}
|
||||
if r.Max.Y < s.Max.Y {
|
||||
r.Max.Y = s.Max.Y
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Empty returns whether the rectangle contains no points.
|
||||
func (r Rectangle26_6) Empty() bool {
|
||||
return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
|
||||
}
|
||||
|
||||
// In returns whether every point in r is in s.
|
||||
func (r Rectangle26_6) In(s Rectangle26_6) bool {
|
||||
if r.Empty() {
|
||||
return true
|
||||
}
|
||||
// Note that r.Max is an exclusive bound for r, so that r.In(s)
|
||||
// does not require that r.Max.In(s).
|
||||
return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
|
||||
s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
|
||||
}
|
||||
|
||||
// Rectangle52_12 is a 52.12 fixed-point coordinate rectangle. The Min bound is
|
||||
// inclusive and the Max bound is exclusive. It is well-formed if Min.X <=
|
||||
// Max.X and likewise for Y.
|
||||
//
|
||||
// It is analogous to the image.Rectangle type in the standard library.
|
||||
type Rectangle52_12 struct {
|
||||
Min, Max Point52_12
|
||||
}
|
||||
|
||||
// Add returns the rectangle r translated by p.
|
||||
func (r Rectangle52_12) Add(p Point52_12) Rectangle52_12 {
|
||||
return Rectangle52_12{
|
||||
Point52_12{r.Min.X + p.X, r.Min.Y + p.Y},
|
||||
Point52_12{r.Max.X + p.X, r.Max.Y + p.Y},
|
||||
}
|
||||
}
|
||||
|
||||
// Sub returns the rectangle r translated by -p.
|
||||
func (r Rectangle52_12) Sub(p Point52_12) Rectangle52_12 {
|
||||
return Rectangle52_12{
|
||||
Point52_12{r.Min.X - p.X, r.Min.Y - p.Y},
|
||||
Point52_12{r.Max.X - p.X, r.Max.Y - p.Y},
|
||||
}
|
||||
}
|
||||
|
||||
// Intersect returns the largest rectangle contained by both r and s. If the
|
||||
// two rectangles do not overlap then the zero rectangle will be returned.
|
||||
func (r Rectangle52_12) Intersect(s Rectangle52_12) Rectangle52_12 {
|
||||
if r.Min.X < s.Min.X {
|
||||
r.Min.X = s.Min.X
|
||||
}
|
||||
if r.Min.Y < s.Min.Y {
|
||||
r.Min.Y = s.Min.Y
|
||||
}
|
||||
if r.Max.X > s.Max.X {
|
||||
r.Max.X = s.Max.X
|
||||
}
|
||||
if r.Max.Y > s.Max.Y {
|
||||
r.Max.Y = s.Max.Y
|
||||
}
|
||||
// Letting r0 and s0 be the values of r and s at the time that the method
|
||||
// is called, this next line is equivalent to:
|
||||
//
|
||||
// if max(r0.Min.X, s0.Min.X) >= min(r0.Max.X, s0.Max.X) || likewiseForY { etc }
|
||||
if r.Empty() {
|
||||
return Rectangle52_12{}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Union returns the smallest rectangle that contains both r and s.
|
||||
func (r Rectangle52_12) Union(s Rectangle52_12) Rectangle52_12 {
|
||||
if r.Empty() {
|
||||
return s
|
||||
}
|
||||
if s.Empty() {
|
||||
return r
|
||||
}
|
||||
if r.Min.X > s.Min.X {
|
||||
r.Min.X = s.Min.X
|
||||
}
|
||||
if r.Min.Y > s.Min.Y {
|
||||
r.Min.Y = s.Min.Y
|
||||
}
|
||||
if r.Max.X < s.Max.X {
|
||||
r.Max.X = s.Max.X
|
||||
}
|
||||
if r.Max.Y < s.Max.Y {
|
||||
r.Max.Y = s.Max.Y
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// Empty returns whether the rectangle contains no points.
|
||||
func (r Rectangle52_12) Empty() bool {
|
||||
return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
|
||||
}
|
||||
|
||||
// In returns whether every point in r is in s.
|
||||
func (r Rectangle52_12) In(s Rectangle52_12) bool {
|
||||
if r.Empty() {
|
||||
return true
|
||||
}
|
||||
// Note that r.Max is an exclusive bound for r, so that r.In(s)
|
||||
// does not require that r.Max.In(s).
|
||||
return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
|
||||
s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
|
||||
}
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package riff implements the Resource Interchange File Format, used by media
|
||||
// formats such as AVI, WAVE and WEBP.
|
||||
//
|
||||
// A RIFF stream contains a sequence of chunks. Each chunk consists of an 8-byte
|
||||
// header (containing a 4-byte chunk type and a 4-byte chunk length), the chunk
|
||||
// data (presented as an io.Reader), and some padding bytes.
|
||||
//
|
||||
// A detailed description of the format is at
|
||||
// http://www.tactilemedia.com/info/MCI_Control_Info.html
|
||||
package riff // import "golang.org/x/image/riff"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
)
|
||||
|
||||
var (
|
||||
errMissingPaddingByte = errors.New("riff: missing padding byte")
|
||||
errMissingRIFFChunkHeader = errors.New("riff: missing RIFF chunk header")
|
||||
errListSubchunkTooLong = errors.New("riff: list subchunk too long")
|
||||
errShortChunkData = errors.New("riff: short chunk data")
|
||||
errShortChunkHeader = errors.New("riff: short chunk header")
|
||||
errStaleReader = errors.New("riff: stale reader")
|
||||
)
|
||||
|
||||
// u32 decodes the first four bytes of b as a little-endian integer.
|
||||
func u32(b []byte) uint32 {
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
const chunkHeaderSize = 8
|
||||
|
||||
// FourCC is a four character code.
|
||||
type FourCC [4]byte
|
||||
|
||||
// LIST is the "LIST" FourCC.
|
||||
var LIST = FourCC{'L', 'I', 'S', 'T'}
|
||||
|
||||
// NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and
|
||||
// its chunks as a *Reader.
|
||||
func NewReader(r io.Reader) (formType FourCC, data *Reader, err error) {
|
||||
var buf [chunkHeaderSize]byte
|
||||
if _, err := io.ReadFull(r, buf[:]); err != nil {
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
err = errMissingRIFFChunkHeader
|
||||
}
|
||||
return FourCC{}, nil, err
|
||||
}
|
||||
if buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' {
|
||||
return FourCC{}, nil, errMissingRIFFChunkHeader
|
||||
}
|
||||
return NewListReader(u32(buf[4:]), r)
|
||||
}
|
||||
|
||||
// NewListReader returns a LIST chunk's list type, such as "movi" or "wavl",
|
||||
// and its chunks as a *Reader.
|
||||
func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error) {
|
||||
if chunkLen < 4 {
|
||||
return FourCC{}, nil, errShortChunkData
|
||||
}
|
||||
z := &Reader{r: chunkData}
|
||||
if _, err := io.ReadFull(chunkData, z.buf[:4]); err != nil {
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||
err = errShortChunkData
|
||||
}
|
||||
return FourCC{}, nil, err
|
||||
}
|
||||
z.totalLen = chunkLen - 4
|
||||
return FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}, z, nil
|
||||
}
|
||||
|
||||
// Reader reads chunks from an underlying io.Reader.
|
||||
type Reader struct {
|
||||
r io.Reader
|
||||
err error
|
||||
|
||||
totalLen uint32
|
||||
chunkLen uint32
|
||||
|
||||
chunkReader *chunkReader
|
||||
buf [chunkHeaderSize]byte
|
||||
padded bool
|
||||
}
|
||||
|
||||
// Next returns the next chunk's ID, length and data. It returns io.EOF if there
|
||||
// are no more chunks. The io.Reader returned becomes stale after the next Next
|
||||
// call, and should no longer be used.
|
||||
//
|
||||
// It is valid to call Next even if all of the previous chunk's data has not
|
||||
// been read.
|
||||
func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error) {
|
||||
if z.err != nil {
|
||||
return FourCC{}, 0, nil, z.err
|
||||
}
|
||||
|
||||
// Drain the rest of the previous chunk.
|
||||
if z.chunkLen != 0 {
|
||||
want := z.chunkLen
|
||||
var got int64
|
||||
got, z.err = io.Copy(ioutil.Discard, z.chunkReader)
|
||||
if z.err == nil && uint32(got) != want {
|
||||
z.err = errShortChunkData
|
||||
}
|
||||
if z.err != nil {
|
||||
return FourCC{}, 0, nil, z.err
|
||||
}
|
||||
}
|
||||
z.chunkReader = nil
|
||||
if z.padded {
|
||||
if z.totalLen == 0 {
|
||||
z.err = errListSubchunkTooLong
|
||||
return FourCC{}, 0, nil, z.err
|
||||
}
|
||||
z.totalLen--
|
||||
_, z.err = io.ReadFull(z.r, z.buf[:1])
|
||||
if z.err != nil {
|
||||
if z.err == io.EOF {
|
||||
z.err = errMissingPaddingByte
|
||||
}
|
||||
return FourCC{}, 0, nil, z.err
|
||||
}
|
||||
}
|
||||
|
||||
// We are done if we have no more data.
|
||||
if z.totalLen == 0 {
|
||||
z.err = io.EOF
|
||||
return FourCC{}, 0, nil, z.err
|
||||
}
|
||||
|
||||
// Read the next chunk header.
|
||||
if z.totalLen < chunkHeaderSize {
|
||||
z.err = errShortChunkHeader
|
||||
return FourCC{}, 0, nil, z.err
|
||||
}
|
||||
z.totalLen -= chunkHeaderSize
|
||||
if _, z.err = io.ReadFull(z.r, z.buf[:chunkHeaderSize]); z.err != nil {
|
||||
if z.err == io.EOF || z.err == io.ErrUnexpectedEOF {
|
||||
z.err = errShortChunkHeader
|
||||
}
|
||||
return FourCC{}, 0, nil, z.err
|
||||
}
|
||||
chunkID = FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}
|
||||
z.chunkLen = u32(z.buf[4:])
|
||||
if z.chunkLen > z.totalLen {
|
||||
z.err = errListSubchunkTooLong
|
||||
return FourCC{}, 0, nil, z.err
|
||||
}
|
||||
z.padded = z.chunkLen&1 == 1
|
||||
z.chunkReader = &chunkReader{z}
|
||||
return chunkID, z.chunkLen, z.chunkReader, nil
|
||||
}
|
||||
|
||||
type chunkReader struct {
|
||||
z *Reader
|
||||
}
|
||||
|
||||
func (c *chunkReader) Read(p []byte) (int, error) {
|
||||
if c != c.z.chunkReader {
|
||||
return 0, errStaleReader
|
||||
}
|
||||
z := c.z
|
||||
if z.err != nil {
|
||||
if z.err == io.EOF {
|
||||
return 0, errStaleReader
|
||||
}
|
||||
return 0, z.err
|
||||
}
|
||||
|
||||
n := int(z.chunkLen)
|
||||
if n == 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if n < 0 {
|
||||
// Converting uint32 to int overflowed.
|
||||
n = math.MaxInt32
|
||||
}
|
||||
if n > len(p) {
|
||||
n = len(p)
|
||||
}
|
||||
n, err := z.r.Read(p[:n])
|
||||
z.totalLen -= uint32(n)
|
||||
z.chunkLen -= uint32(n)
|
||||
if err != io.EOF {
|
||||
z.err = err
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package tiff
|
||||
|
||||
import (
|
||||
"io"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// buffer buffers an io.Reader to satisfy io.ReaderAt.
|
||||
type buffer struct {
|
||||
r io.Reader
|
||||
buf []byte
|
||||
}
|
||||
|
||||
const fillChunkSize = 10 << 20 // 10 MB
|
||||
|
||||
// fill reads data from b.r until the buffer contains at least end bytes.
|
||||
func (b *buffer) fill(end int) error {
|
||||
m := len(b.buf)
|
||||
for m < end {
|
||||
next := min(end-m, fillChunkSize)
|
||||
b.buf = slices.Grow(b.buf, next)
|
||||
b.buf = b.buf[:m+next]
|
||||
n, err := io.ReadFull(b.r, b.buf[m:m+next])
|
||||
m += n
|
||||
b.buf = b.buf[:m]
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *buffer) ReadAt(p []byte, off int64) (int, error) {
|
||||
o := int(off)
|
||||
end := o + len(p)
|
||||
if int64(end) != off+int64(len(p)) {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
err := b.fill(end)
|
||||
end = min(end, len(b.buf))
|
||||
return copy(p, b.buf[min(o, end):end]), err
|
||||
}
|
||||
|
||||
// Slice returns a slice of the underlying buffer. The slice contains
|
||||
// n bytes starting at offset off.
|
||||
func (b *buffer) Slice(off, n int) ([]byte, error) {
|
||||
end := off + n
|
||||
if err := b.fill(end); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b.buf[off:end], nil
|
||||
}
|
||||
|
||||
// newReaderAt converts an io.Reader into an io.ReaderAt.
|
||||
func newReaderAt(r io.Reader) io.ReaderAt {
|
||||
if ra, ok := r.(io.ReaderAt); ok {
|
||||
return ra
|
||||
}
|
||||
return &buffer{
|
||||
r: r,
|
||||
buf: make([]byte, 0, 1024),
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package tiff
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
)
|
||||
|
||||
type byteReader interface {
|
||||
io.Reader
|
||||
io.ByteReader
|
||||
}
|
||||
|
||||
// unpackBits decodes the PackBits-compressed data in src and returns the
|
||||
// uncompressed data.
|
||||
//
|
||||
// The PackBits compression format is described in section 9 (p. 42)
|
||||
// of the TIFF spec.
|
||||
func unpackBits(r io.Reader) ([]byte, error) {
|
||||
buf := make([]byte, 128)
|
||||
dst := make([]byte, 0, 1024)
|
||||
br, ok := r.(byteReader)
|
||||
if !ok {
|
||||
br = bufio.NewReader(r)
|
||||
}
|
||||
|
||||
for {
|
||||
b, err := br.ReadByte()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
return dst, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
code := int(int8(b))
|
||||
switch {
|
||||
case code >= 0:
|
||||
n, err := io.ReadFull(br, buf[:code+1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dst = append(dst, buf[:n]...)
|
||||
case code == -128:
|
||||
// No-op.
|
||||
default:
|
||||
if b, err = br.ReadByte(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for j := 0; j < 1-code; j++ {
|
||||
buf[j] = b
|
||||
}
|
||||
dst = append(dst, buf[:1-code]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package tiff
|
||||
|
||||
// A tiff image file contains one or more images. The metadata
|
||||
// of each image is contained in an Image File Directory (IFD),
|
||||
// which contains entries of 12 bytes each and is described
|
||||
// on page 14-16 of the specification. An IFD entry consists of
|
||||
//
|
||||
// - a tag, which describes the signification of the entry,
|
||||
// - the data type and length of the entry,
|
||||
// - the data itself or a pointer to it if it is more than 4 bytes.
|
||||
//
|
||||
// The presence of a length means that each IFD is effectively an array.
|
||||
|
||||
const (
|
||||
leHeader = "II\x2A\x00" // Header for little-endian files.
|
||||
beHeader = "MM\x00\x2A" // Header for big-endian files.
|
||||
|
||||
ifdLen = 12 // Length of an IFD entry in bytes.
|
||||
)
|
||||
|
||||
// Data types (p. 14-16 of the spec).
|
||||
const (
|
||||
dtByte = 1
|
||||
dtASCII = 2
|
||||
dtShort = 3
|
||||
dtLong = 4
|
||||
dtRational = 5
|
||||
)
|
||||
|
||||
// The length of one instance of each data type in bytes.
|
||||
var lengths = [...]uint32{0, 1, 1, 2, 4, 8}
|
||||
|
||||
// Tags (see p. 28-41 of the spec).
|
||||
const (
|
||||
tImageWidth = 256
|
||||
tImageLength = 257
|
||||
tBitsPerSample = 258
|
||||
tCompression = 259
|
||||
tPhotometricInterpretation = 262
|
||||
|
||||
tFillOrder = 266
|
||||
|
||||
tStripOffsets = 273
|
||||
tSamplesPerPixel = 277
|
||||
tRowsPerStrip = 278
|
||||
tStripByteCounts = 279
|
||||
|
||||
tT4Options = 292 // CCITT Group 3 options, a set of 32 flag bits.
|
||||
tT6Options = 293 // CCITT Group 4 options, a set of 32 flag bits.
|
||||
|
||||
tTileWidth = 322
|
||||
tTileLength = 323
|
||||
tTileOffsets = 324
|
||||
tTileByteCounts = 325
|
||||
|
||||
tXResolution = 282
|
||||
tYResolution = 283
|
||||
tResolutionUnit = 296
|
||||
|
||||
tPredictor = 317
|
||||
tColorMap = 320
|
||||
tExtraSamples = 338
|
||||
tSampleFormat = 339
|
||||
)
|
||||
|
||||
// Compression types (defined in various places in the spec and supplements).
|
||||
const (
|
||||
cNone = 1
|
||||
cCCITT = 2
|
||||
cG3 = 3 // Group 3 Fax.
|
||||
cG4 = 4 // Group 4 Fax.
|
||||
cLZW = 5
|
||||
cJPEGOld = 6 // Superseded by cJPEG.
|
||||
cJPEG = 7
|
||||
cDeflate = 8 // zlib compression.
|
||||
cPackBits = 32773
|
||||
cDeflateOld = 32946 // Superseded by cDeflate.
|
||||
)
|
||||
|
||||
// Photometric interpretation values (see p. 37 of the spec).
|
||||
const (
|
||||
pWhiteIsZero = 0
|
||||
pBlackIsZero = 1
|
||||
pRGB = 2
|
||||
pPaletted = 3
|
||||
pTransMask = 4 // transparency mask
|
||||
pCMYK = 5
|
||||
pYCbCr = 6
|
||||
pCIELab = 8
|
||||
)
|
||||
|
||||
// Values for the tPredictor tag (page 64-65 of the spec).
|
||||
const (
|
||||
prNone = 1
|
||||
prHorizontal = 2
|
||||
)
|
||||
|
||||
// Values for the tResolutionUnit tag (page 18).
|
||||
const (
|
||||
resNone = 1
|
||||
resPerInch = 2 // Dots per inch.
|
||||
resPerCM = 3 // Dots per centimeter.
|
||||
)
|
||||
|
||||
// imageMode represents the mode of the image.
|
||||
type imageMode int
|
||||
|
||||
const (
|
||||
mBilevel imageMode = iota
|
||||
mPaletted
|
||||
mGray
|
||||
mGrayInvert
|
||||
mRGB
|
||||
mRGBA
|
||||
mNRGBA
|
||||
mCMYK
|
||||
)
|
||||
|
||||
// CompressionType describes the type of compression used in Options.
|
||||
type CompressionType int
|
||||
|
||||
// Constants for supported compression types.
|
||||
const (
|
||||
Uncompressed CompressionType = iota
|
||||
Deflate
|
||||
LZW
|
||||
CCITTGroup3
|
||||
CCITTGroup4
|
||||
)
|
||||
|
||||
// specValue returns the compression type constant from the TIFF spec that
|
||||
// is equivalent to c.
|
||||
func (c CompressionType) specValue() uint32 {
|
||||
switch c {
|
||||
case LZW:
|
||||
return cLZW
|
||||
case Deflate:
|
||||
return cDeflate
|
||||
case CCITTGroup3:
|
||||
return cG3
|
||||
case CCITTGroup4:
|
||||
return cG4
|
||||
}
|
||||
return cNone
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build gofuzz
|
||||
|
||||
package tiff
|
||||
|
||||
import "bytes"
|
||||
|
||||
func Fuzz(data []byte) int {
|
||||
cfg, err := DecodeConfig(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
if cfg.Width*cfg.Height > 1e6 {
|
||||
return 0
|
||||
}
|
||||
img, err := Decode(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
var w bytes.Buffer
|
||||
err = Encode(&w, img, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return 1
|
||||
}
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package lzw implements the Lempel-Ziv-Welch compressed data format,
|
||||
// described in T. A. Welch, “A Technique for High-Performance Data
|
||||
// Compression”, Computer, 17(6) (June 1984), pp 8-19.
|
||||
//
|
||||
// In particular, it implements LZW as used by the TIFF file format, including
|
||||
// an "off by one" algorithmic difference when compared to standard LZW.
|
||||
package lzw // import "golang.org/x/image/tiff/lzw"
|
||||
|
||||
/*
|
||||
This file was branched from src/pkg/compress/lzw/reader.go in the
|
||||
standard library. Differences from the original are marked with "NOTE".
|
||||
|
||||
The tif_lzw.c file in the libtiff C library has this comment:
|
||||
|
||||
----
|
||||
The 5.0 spec describes a different algorithm than Aldus
|
||||
implements. Specifically, Aldus does code length transitions
|
||||
one code earlier than should be done (for real LZW).
|
||||
Earlier versions of this library implemented the correct
|
||||
LZW algorithm, but emitted codes in a bit order opposite
|
||||
to the TIFF spec. Thus, to maintain compatibility w/ Aldus
|
||||
we interpret MSB-LSB ordered codes to be images written w/
|
||||
old versions of this library, but otherwise adhere to the
|
||||
Aldus "off by one" algorithm.
|
||||
----
|
||||
|
||||
The Go code doesn't read (invalid) TIFF files written by old versions of
|
||||
libtiff, but the LZW algorithm in this package still differs from the one in
|
||||
Go's standard package library to accommodate this "off by one" in valid TIFFs.
|
||||
*/
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Order specifies the bit ordering in an LZW data stream.
|
||||
type Order int
|
||||
|
||||
const (
|
||||
// LSB means Least Significant Bits first, as used in the GIF file format.
|
||||
LSB Order = iota
|
||||
// MSB means Most Significant Bits first, as used in the TIFF and PDF
|
||||
// file formats.
|
||||
MSB
|
||||
)
|
||||
|
||||
const (
|
||||
maxWidth = 12
|
||||
decoderInvalidCode = 0xffff
|
||||
flushBuffer = 1 << maxWidth
|
||||
)
|
||||
|
||||
// decoder is the state from which the readXxx method converts a byte
|
||||
// stream into a code stream.
|
||||
type decoder struct {
|
||||
r io.ByteReader
|
||||
bits uint32
|
||||
nBits uint
|
||||
width uint
|
||||
read func(*decoder) (uint16, error) // readLSB or readMSB
|
||||
litWidth int // width in bits of literal codes
|
||||
err error
|
||||
|
||||
// The first 1<<litWidth codes are literal codes.
|
||||
// The next two codes mean clear and EOF.
|
||||
// Other valid codes are in the range [lo, hi] where lo := clear + 2,
|
||||
// with the upper bound incrementing on each code seen.
|
||||
// overflow is the code at which hi overflows the code width. NOTE: TIFF's LZW is "off by one".
|
||||
// last is the most recently seen code, or decoderInvalidCode.
|
||||
clear, eof, hi, overflow, last uint16
|
||||
|
||||
// Each code c in [lo, hi] expands to two or more bytes. For c != hi:
|
||||
// suffix[c] is the last of these bytes.
|
||||
// prefix[c] is the code for all but the last byte.
|
||||
// This code can either be a literal code or another code in [lo, c).
|
||||
// The c == hi case is a special case.
|
||||
suffix [1 << maxWidth]uint8
|
||||
prefix [1 << maxWidth]uint16
|
||||
|
||||
// output is the temporary output buffer.
|
||||
// Literal codes are accumulated from the start of the buffer.
|
||||
// Non-literal codes decode to a sequence of suffixes that are first
|
||||
// written right-to-left from the end of the buffer before being copied
|
||||
// to the start of the buffer.
|
||||
// It is flushed when it contains >= 1<<maxWidth bytes,
|
||||
// so that there is always room to decode an entire code.
|
||||
output [2 * 1 << maxWidth]byte
|
||||
o int // write index into output
|
||||
toRead []byte // bytes to return from Read
|
||||
}
|
||||
|
||||
// readLSB returns the next code for "Least Significant Bits first" data.
|
||||
func (d *decoder) readLSB() (uint16, error) {
|
||||
for d.nBits < d.width {
|
||||
x, err := d.r.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d.bits |= uint32(x) << d.nBits
|
||||
d.nBits += 8
|
||||
}
|
||||
code := uint16(d.bits & (1<<d.width - 1))
|
||||
d.bits >>= d.width
|
||||
d.nBits -= d.width
|
||||
return code, nil
|
||||
}
|
||||
|
||||
// readMSB returns the next code for "Most Significant Bits first" data.
|
||||
func (d *decoder) readMSB() (uint16, error) {
|
||||
for d.nBits < d.width {
|
||||
x, err := d.r.ReadByte()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d.bits |= uint32(x) << (24 - d.nBits)
|
||||
d.nBits += 8
|
||||
}
|
||||
code := uint16(d.bits >> (32 - d.width))
|
||||
d.bits <<= d.width
|
||||
d.nBits -= d.width
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (d *decoder) Read(b []byte) (int, error) {
|
||||
for {
|
||||
if len(d.toRead) > 0 {
|
||||
n := copy(b, d.toRead)
|
||||
d.toRead = d.toRead[n:]
|
||||
return n, nil
|
||||
}
|
||||
if d.err != nil {
|
||||
return 0, d.err
|
||||
}
|
||||
d.decode()
|
||||
}
|
||||
}
|
||||
|
||||
// decode decompresses bytes from r and leaves them in d.toRead.
|
||||
// read specifies how to decode bytes into codes.
|
||||
// litWidth is the width in bits of literal codes.
|
||||
func (d *decoder) decode() {
|
||||
// Loop over the code stream, converting codes into decompressed bytes.
|
||||
loop:
|
||||
for {
|
||||
code, err := d.read(d)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
d.err = err
|
||||
break
|
||||
}
|
||||
switch {
|
||||
case code < d.clear:
|
||||
// We have a literal code.
|
||||
d.output[d.o] = uint8(code)
|
||||
d.o++
|
||||
if d.last != decoderInvalidCode {
|
||||
// Save what the hi code expands to.
|
||||
d.suffix[d.hi] = uint8(code)
|
||||
d.prefix[d.hi] = d.last
|
||||
}
|
||||
case code == d.clear:
|
||||
d.width = 1 + uint(d.litWidth)
|
||||
d.hi = d.eof
|
||||
d.overflow = 1 << d.width
|
||||
d.last = decoderInvalidCode
|
||||
continue
|
||||
case code == d.eof:
|
||||
d.err = io.EOF
|
||||
break loop
|
||||
case code <= d.hi:
|
||||
c, i := code, len(d.output)-1
|
||||
if code == d.hi && d.last != decoderInvalidCode {
|
||||
// code == hi is a special case which expands to the last expansion
|
||||
// followed by the head of the last expansion. To find the head, we walk
|
||||
// the prefix chain until we find a literal code.
|
||||
c = d.last
|
||||
for c >= d.clear {
|
||||
c = d.prefix[c]
|
||||
}
|
||||
d.output[i] = uint8(c)
|
||||
i--
|
||||
c = d.last
|
||||
}
|
||||
// Copy the suffix chain into output and then write that to w.
|
||||
for c >= d.clear {
|
||||
d.output[i] = d.suffix[c]
|
||||
i--
|
||||
c = d.prefix[c]
|
||||
}
|
||||
d.output[i] = uint8(c)
|
||||
d.o += copy(d.output[d.o:], d.output[i:])
|
||||
if d.last != decoderInvalidCode {
|
||||
// Save what the hi code expands to.
|
||||
d.suffix[d.hi] = uint8(c)
|
||||
d.prefix[d.hi] = d.last
|
||||
}
|
||||
default:
|
||||
d.err = errors.New("lzw: invalid code")
|
||||
break loop
|
||||
}
|
||||
d.last, d.hi = code, d.hi+1
|
||||
if d.hi+1 >= d.overflow { // NOTE: the "+1" is where TIFF's LZW differs from the standard algorithm.
|
||||
if d.width == maxWidth {
|
||||
d.last = decoderInvalidCode
|
||||
} else {
|
||||
d.width++
|
||||
d.overflow <<= 1
|
||||
}
|
||||
}
|
||||
if d.o >= flushBuffer {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Flush pending output.
|
||||
d.toRead = d.output[:d.o]
|
||||
d.o = 0
|
||||
}
|
||||
|
||||
var errClosed = errors.New("lzw: reader/writer is closed")
|
||||
|
||||
func (d *decoder) Close() error {
|
||||
d.err = errClosed // in case any Reads come along
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewReader creates a new io.ReadCloser.
|
||||
// Reads from the returned io.ReadCloser read and decompress data from r.
|
||||
// If r does not also implement io.ByteReader,
|
||||
// the decompressor may read more data than necessary from r.
|
||||
// It is the caller's responsibility to call Close on the ReadCloser when
|
||||
// finished reading.
|
||||
// The number of bits to use for literal codes, litWidth, must be in the
|
||||
// range [2,8] and is typically 8. It must equal the litWidth
|
||||
// used during compression.
|
||||
func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
|
||||
d := new(decoder)
|
||||
switch order {
|
||||
case LSB:
|
||||
d.read = (*decoder).readLSB
|
||||
case MSB:
|
||||
d.read = (*decoder).readMSB
|
||||
default:
|
||||
d.err = errors.New("lzw: unknown order")
|
||||
return d
|
||||
}
|
||||
if litWidth < 2 || 8 < litWidth {
|
||||
d.err = fmt.Errorf("lzw: litWidth %d out of range", litWidth)
|
||||
return d
|
||||
}
|
||||
if br, ok := r.(io.ByteReader); ok {
|
||||
d.r = br
|
||||
} else {
|
||||
d.r = bufio.NewReader(r)
|
||||
}
|
||||
d.litWidth = litWidth
|
||||
d.width = 1 + uint(litWidth)
|
||||
d.clear = uint16(1) << uint(litWidth)
|
||||
d.eof, d.hi = d.clear+1, d.clear+1
|
||||
d.overflow = uint16(1) << d.width
|
||||
d.last = decoderInvalidCode
|
||||
|
||||
return d
|
||||
}
|
||||
+789
@@ -0,0 +1,789 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package tiff implements a TIFF image decoder and encoder.
|
||||
//
|
||||
// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
|
||||
package tiff // import "golang.org/x/image/tiff"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"golang.org/x/image/ccitt"
|
||||
"golang.org/x/image/tiff/lzw"
|
||||
)
|
||||
|
||||
// A FormatError reports that the input is not a valid TIFF image.
|
||||
type FormatError string
|
||||
|
||||
func (e FormatError) Error() string {
|
||||
return "tiff: invalid format: " + string(e)
|
||||
}
|
||||
|
||||
// An UnsupportedError reports that the input uses a valid but
|
||||
// unimplemented feature.
|
||||
type UnsupportedError string
|
||||
|
||||
func (e UnsupportedError) Error() string {
|
||||
return "tiff: unsupported feature: " + string(e)
|
||||
}
|
||||
|
||||
var (
|
||||
errNoPixels = FormatError("not enough pixel data")
|
||||
errInvalidColorIndex = FormatError("invalid color index")
|
||||
)
|
||||
|
||||
const maxChunkSize = 10 << 20 // 10M
|
||||
|
||||
// safeReadAt is a verbatim copy of internal/saferio.ReadDataAt from the
|
||||
// standard library, which is used to read data from a reader using a length
|
||||
// provided by untrusted data, without allocating the entire slice ahead of time
|
||||
// if it is large (>maxChunkSize). This allows us to avoid allocating giant
|
||||
// slices before learning that we can't actually read that much data from the
|
||||
// reader.
|
||||
func safeReadAt(r io.ReaderAt, n uint64, off int64) ([]byte, error) {
|
||||
if int64(n) < 0 || n != uint64(int(n)) {
|
||||
// n is too large to fit in int, so we can't allocate
|
||||
// a buffer large enough. Treat this as a read failure.
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
if n < maxChunkSize {
|
||||
buf := make([]byte, n)
|
||||
_, err := r.ReadAt(buf, off)
|
||||
if err != nil {
|
||||
// io.SectionReader can return EOF for n == 0,
|
||||
// but for our purposes that is a success.
|
||||
if err != io.EOF || n > 0 {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
buf1 := make([]byte, maxChunkSize)
|
||||
for n > 0 {
|
||||
next := n
|
||||
if next > maxChunkSize {
|
||||
next = maxChunkSize
|
||||
}
|
||||
_, err := r.ReadAt(buf1[:next], off)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = append(buf, buf1[:next]...)
|
||||
n -= next
|
||||
off += int64(next)
|
||||
}
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
type decoder struct {
|
||||
r io.ReaderAt
|
||||
byteOrder binary.ByteOrder
|
||||
config image.Config
|
||||
mode imageMode
|
||||
bpp uint
|
||||
features map[int][]uint
|
||||
palette []color.Color
|
||||
|
||||
buf []byte
|
||||
off int // Current offset in buf.
|
||||
v uint32 // Buffer value for reading with arbitrary bit depths.
|
||||
nbits uint // Remaining number of bits in v.
|
||||
}
|
||||
|
||||
// firstVal returns the first uint of the features entry with the given tag,
|
||||
// or 0 if the tag does not exist.
|
||||
func (d *decoder) firstVal(tag int) uint {
|
||||
f := d.features[tag]
|
||||
if len(f) == 0 {
|
||||
return 0
|
||||
}
|
||||
return f[0]
|
||||
}
|
||||
|
||||
// ifdUint decodes the IFD entry in p, which must be of the Byte, Short
|
||||
// or Long type, and returns the decoded uint values.
|
||||
func (d *decoder) ifdUint(p []byte) (u []uint, err error) {
|
||||
var raw []byte
|
||||
if len(p) < ifdLen {
|
||||
return nil, FormatError("bad IFD entry")
|
||||
}
|
||||
|
||||
datatype := d.byteOrder.Uint16(p[2:4])
|
||||
if dt := int(datatype); dt <= 0 || dt >= len(lengths) {
|
||||
return nil, UnsupportedError("IFD entry datatype")
|
||||
}
|
||||
|
||||
count := d.byteOrder.Uint32(p[4:8])
|
||||
if count > math.MaxInt32/lengths[datatype] {
|
||||
return nil, FormatError("IFD data too large")
|
||||
}
|
||||
if datalen := lengths[datatype] * count; datalen > 4 {
|
||||
// The IFD contains a pointer to the real value.
|
||||
raw, err = safeReadAt(d.r, uint64(datalen), int64(d.byteOrder.Uint32(p[8:12])))
|
||||
} else {
|
||||
raw = p[8 : 8+datalen]
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u = make([]uint, count)
|
||||
switch datatype {
|
||||
case dtByte:
|
||||
for i := uint32(0); i < count; i++ {
|
||||
u[i] = uint(raw[i])
|
||||
}
|
||||
case dtShort:
|
||||
for i := uint32(0); i < count; i++ {
|
||||
u[i] = uint(d.byteOrder.Uint16(raw[2*i : 2*(i+1)]))
|
||||
}
|
||||
case dtLong:
|
||||
for i := uint32(0); i < count; i++ {
|
||||
u[i] = uint(d.byteOrder.Uint32(raw[4*i : 4*(i+1)]))
|
||||
}
|
||||
default:
|
||||
return nil, UnsupportedError("data type")
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// parseIFD decides whether the IFD entry in p is "interesting" and
|
||||
// stows away the data in the decoder. It returns the tag number of the
|
||||
// entry and an error, if any.
|
||||
func (d *decoder) parseIFD(p []byte) (int, error) {
|
||||
tag := d.byteOrder.Uint16(p[0:2])
|
||||
switch tag {
|
||||
case tBitsPerSample,
|
||||
tExtraSamples,
|
||||
tPhotometricInterpretation,
|
||||
tCompression,
|
||||
tPredictor,
|
||||
tStripOffsets,
|
||||
tStripByteCounts,
|
||||
tRowsPerStrip,
|
||||
tTileWidth,
|
||||
tTileLength,
|
||||
tTileOffsets,
|
||||
tTileByteCounts,
|
||||
tImageLength,
|
||||
tImageWidth,
|
||||
tFillOrder,
|
||||
tT4Options,
|
||||
tT6Options:
|
||||
val, err := d.ifdUint(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
d.features[int(tag)] = val
|
||||
case tColorMap:
|
||||
val, err := d.ifdUint(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
numcolors := len(val) / 3
|
||||
if len(val)%3 != 0 || numcolors <= 0 || numcolors > 256 {
|
||||
return 0, FormatError("bad ColorMap length")
|
||||
}
|
||||
d.palette = make([]color.Color, numcolors)
|
||||
for i := 0; i < numcolors; i++ {
|
||||
d.palette[i] = color.RGBA64{
|
||||
uint16(val[i]),
|
||||
uint16(val[i+numcolors]),
|
||||
uint16(val[i+2*numcolors]),
|
||||
0xffff,
|
||||
}
|
||||
}
|
||||
case tSampleFormat:
|
||||
// Page 27 of the spec: If the SampleFormat is present and
|
||||
// the value is not 1 [= unsigned integer data], a Baseline
|
||||
// TIFF reader that cannot handle the SampleFormat value
|
||||
// must terminate the import process gracefully.
|
||||
val, err := d.ifdUint(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
for _, v := range val {
|
||||
if v != 1 {
|
||||
return 0, UnsupportedError("sample format")
|
||||
}
|
||||
}
|
||||
}
|
||||
return int(tag), nil
|
||||
}
|
||||
|
||||
// readBits reads n bits from the internal buffer starting at the current offset.
|
||||
func (d *decoder) readBits(n uint) (v uint32, ok bool) {
|
||||
for d.nbits < n {
|
||||
d.v <<= 8
|
||||
if d.off >= len(d.buf) {
|
||||
return 0, false
|
||||
}
|
||||
d.v |= uint32(d.buf[d.off])
|
||||
d.off++
|
||||
d.nbits += 8
|
||||
}
|
||||
d.nbits -= n
|
||||
rv := d.v >> d.nbits
|
||||
d.v &^= rv << d.nbits
|
||||
return rv, true
|
||||
}
|
||||
|
||||
// flushBits discards the unread bits in the buffer used by readBits.
|
||||
// It is used at the end of a line.
|
||||
func (d *decoder) flushBits() {
|
||||
d.v = 0
|
||||
d.nbits = 0
|
||||
}
|
||||
|
||||
// minInt returns the smaller of x or y.
|
||||
func minInt(a, b int) int {
|
||||
if a <= b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// decode decodes the raw data of an image.
|
||||
// It reads from d.buf and writes the strip or tile into dst.
|
||||
func (d *decoder) decode(dst image.Image, xmin, ymin, xmax, ymax int) error {
|
||||
d.off = 0
|
||||
|
||||
// Apply horizontal predictor if necessary.
|
||||
// In this case, p contains the color difference to the preceding pixel.
|
||||
// See page 64-65 of the spec.
|
||||
if d.firstVal(tPredictor) == prHorizontal {
|
||||
switch d.bpp {
|
||||
case 16:
|
||||
var off int
|
||||
n := 2 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
|
||||
for y := ymin; y < ymax; y++ {
|
||||
off += n
|
||||
for x := 0; x < (xmax-xmin-1)*n; x += 2 {
|
||||
if off+2 > len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
v0 := d.byteOrder.Uint16(d.buf[off-n : off-n+2])
|
||||
v1 := d.byteOrder.Uint16(d.buf[off : off+2])
|
||||
d.byteOrder.PutUint16(d.buf[off:off+2], v1+v0)
|
||||
off += 2
|
||||
}
|
||||
}
|
||||
case 8:
|
||||
var off int
|
||||
n := 1 * len(d.features[tBitsPerSample]) // bytes per sample times samples per pixel
|
||||
for y := ymin; y < ymax; y++ {
|
||||
off += n
|
||||
for x := 0; x < (xmax-xmin-1)*n; x++ {
|
||||
if off >= len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
d.buf[off] += d.buf[off-n]
|
||||
off++
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
return UnsupportedError("horizontal predictor with 1 BitsPerSample")
|
||||
}
|
||||
}
|
||||
|
||||
rMaxX := minInt(xmax, dst.Bounds().Max.X)
|
||||
rMaxY := minInt(ymax, dst.Bounds().Max.Y)
|
||||
switch d.mode {
|
||||
case mGray, mGrayInvert:
|
||||
if d.bpp == 16 {
|
||||
img := dst.(*image.Gray16)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
for x := xmin; x < rMaxX; x++ {
|
||||
if d.off+2 > len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
v := d.byteOrder.Uint16(d.buf[d.off : d.off+2])
|
||||
d.off += 2
|
||||
if d.mode == mGrayInvert {
|
||||
v = 0xffff - v
|
||||
}
|
||||
img.SetGray16(x, y, color.Gray16{v})
|
||||
}
|
||||
if rMaxX == img.Bounds().Max.X {
|
||||
d.off += 2 * (xmax - img.Bounds().Max.X)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
img := dst.(*image.Gray)
|
||||
max := uint32((1 << d.bpp) - 1)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
for x := xmin; x < rMaxX; x++ {
|
||||
v, ok := d.readBits(d.bpp)
|
||||
if !ok {
|
||||
return errNoPixels
|
||||
}
|
||||
v = v * 0xff / max
|
||||
if d.mode == mGrayInvert {
|
||||
v = 0xff - v
|
||||
}
|
||||
img.SetGray(x, y, color.Gray{uint8(v)})
|
||||
}
|
||||
d.flushBits()
|
||||
}
|
||||
}
|
||||
case mPaletted:
|
||||
img := dst.(*image.Paletted)
|
||||
pLen := len(d.palette)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
for x := xmin; x < rMaxX; x++ {
|
||||
v, ok := d.readBits(d.bpp)
|
||||
if !ok {
|
||||
return errNoPixels
|
||||
}
|
||||
idx := uint8(v)
|
||||
if int(idx) >= pLen {
|
||||
return errInvalidColorIndex
|
||||
}
|
||||
img.SetColorIndex(x, y, idx)
|
||||
}
|
||||
d.flushBits()
|
||||
}
|
||||
case mRGB:
|
||||
if d.bpp == 16 {
|
||||
img := dst.(*image.RGBA64)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
for x := xmin; x < rMaxX; x++ {
|
||||
if d.off+6 > len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
|
||||
g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
|
||||
b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
|
||||
d.off += 6
|
||||
img.SetRGBA64(x, y, color.RGBA64{r, g, b, 0xffff})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
img := dst.(*image.RGBA)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
min := img.PixOffset(xmin, y)
|
||||
max := img.PixOffset(rMaxX, y)
|
||||
off := (y - ymin) * (xmax - xmin) * 3
|
||||
for i := min; i < max; i += 4 {
|
||||
if off+3 > len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
img.Pix[i+0] = d.buf[off+0]
|
||||
img.Pix[i+1] = d.buf[off+1]
|
||||
img.Pix[i+2] = d.buf[off+2]
|
||||
img.Pix[i+3] = 0xff
|
||||
off += 3
|
||||
}
|
||||
}
|
||||
}
|
||||
case mNRGBA:
|
||||
if d.bpp == 16 {
|
||||
img := dst.(*image.NRGBA64)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
for x := xmin; x < rMaxX; x++ {
|
||||
if d.off+8 > len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
|
||||
g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
|
||||
b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
|
||||
a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8])
|
||||
d.off += 8
|
||||
img.SetNRGBA64(x, y, color.NRGBA64{r, g, b, a})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
img := dst.(*image.NRGBA)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
min := img.PixOffset(xmin, y)
|
||||
max := img.PixOffset(rMaxX, y)
|
||||
i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
|
||||
if i1 > len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
copy(img.Pix[min:max], d.buf[i0:i1])
|
||||
}
|
||||
}
|
||||
case mRGBA:
|
||||
if d.bpp == 16 {
|
||||
img := dst.(*image.RGBA64)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
for x := xmin; x < rMaxX; x++ {
|
||||
if d.off+8 > len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
r := d.byteOrder.Uint16(d.buf[d.off+0 : d.off+2])
|
||||
g := d.byteOrder.Uint16(d.buf[d.off+2 : d.off+4])
|
||||
b := d.byteOrder.Uint16(d.buf[d.off+4 : d.off+6])
|
||||
a := d.byteOrder.Uint16(d.buf[d.off+6 : d.off+8])
|
||||
d.off += 8
|
||||
img.SetRGBA64(x, y, color.RGBA64{r, g, b, a})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
img := dst.(*image.RGBA)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
min := img.PixOffset(xmin, y)
|
||||
max := img.PixOffset(rMaxX, y)
|
||||
i0, i1 := (y-ymin)*(xmax-xmin)*4, (y-ymin+1)*(xmax-xmin)*4
|
||||
if i1 > len(d.buf) {
|
||||
return errNoPixels
|
||||
}
|
||||
copy(img.Pix[min:max], d.buf[i0:i1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newDecoder(r io.Reader) (*decoder, error) {
|
||||
d := &decoder{
|
||||
r: newReaderAt(r),
|
||||
features: make(map[int][]uint),
|
||||
}
|
||||
|
||||
p := make([]byte, 8)
|
||||
if _, err := d.r.ReadAt(p, 0); err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
switch string(p[0:4]) {
|
||||
case leHeader:
|
||||
d.byteOrder = binary.LittleEndian
|
||||
case beHeader:
|
||||
d.byteOrder = binary.BigEndian
|
||||
default:
|
||||
return nil, FormatError("malformed header")
|
||||
}
|
||||
|
||||
ifdOffset := int64(d.byteOrder.Uint32(p[4:8]))
|
||||
|
||||
// The first two bytes contain the number of entries (12 bytes each).
|
||||
if _, err := d.r.ReadAt(p[0:2], ifdOffset); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
numItems := int(d.byteOrder.Uint16(p[0:2]))
|
||||
|
||||
// All IFD entries are read in one chunk.
|
||||
var err error
|
||||
p, err = safeReadAt(d.r, uint64(ifdLen*numItems), ifdOffset+2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prevTag := -1
|
||||
for i := 0; i < len(p); i += ifdLen {
|
||||
tag, err := d.parseIFD(p[i : i+ifdLen])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tag <= prevTag {
|
||||
return nil, FormatError("tags are not sorted in ascending order")
|
||||
}
|
||||
prevTag = tag
|
||||
}
|
||||
|
||||
d.config.Width = int(d.firstVal(tImageWidth))
|
||||
d.config.Height = int(d.firstVal(tImageLength))
|
||||
if d.config.Width == 0 || d.config.Height == 0 {
|
||||
return nil, errors.New("tiff: zero-size image")
|
||||
}
|
||||
|
||||
if _, ok := d.features[tBitsPerSample]; !ok {
|
||||
// Default is 1 per specification.
|
||||
d.features[tBitsPerSample] = []uint{1}
|
||||
}
|
||||
d.bpp = d.firstVal(tBitsPerSample)
|
||||
switch d.bpp {
|
||||
case 0:
|
||||
return nil, FormatError("BitsPerSample must not be 0")
|
||||
case 1, 8, 16:
|
||||
// Nothing to do, these are accepted by this implementation.
|
||||
default:
|
||||
return nil, UnsupportedError(fmt.Sprintf("BitsPerSample of %v", d.bpp))
|
||||
}
|
||||
|
||||
// Determine the image mode.
|
||||
switch d.firstVal(tPhotometricInterpretation) {
|
||||
case pRGB:
|
||||
if d.bpp == 16 {
|
||||
for _, b := range d.features[tBitsPerSample] {
|
||||
if b != 16 {
|
||||
return nil, FormatError("wrong number of samples for 16bit RGB")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, b := range d.features[tBitsPerSample] {
|
||||
if b != 8 {
|
||||
return nil, FormatError("wrong number of samples for 8bit RGB")
|
||||
}
|
||||
}
|
||||
}
|
||||
// RGB images normally have 3 samples per pixel.
|
||||
// If there are more, ExtraSamples (p. 31-32 of the spec)
|
||||
// gives their meaning (usually an alpha channel).
|
||||
//
|
||||
// This implementation does not support extra samples
|
||||
// of an unspecified type.
|
||||
switch len(d.features[tBitsPerSample]) {
|
||||
case 3:
|
||||
d.mode = mRGB
|
||||
if d.bpp == 16 {
|
||||
d.config.ColorModel = color.RGBA64Model
|
||||
} else {
|
||||
d.config.ColorModel = color.RGBAModel
|
||||
}
|
||||
case 4:
|
||||
switch d.firstVal(tExtraSamples) {
|
||||
case 1:
|
||||
d.mode = mRGBA
|
||||
if d.bpp == 16 {
|
||||
d.config.ColorModel = color.RGBA64Model
|
||||
} else {
|
||||
d.config.ColorModel = color.RGBAModel
|
||||
}
|
||||
case 2:
|
||||
d.mode = mNRGBA
|
||||
if d.bpp == 16 {
|
||||
d.config.ColorModel = color.NRGBA64Model
|
||||
} else {
|
||||
d.config.ColorModel = color.NRGBAModel
|
||||
}
|
||||
default:
|
||||
return nil, FormatError("wrong number of samples for RGB")
|
||||
}
|
||||
default:
|
||||
return nil, FormatError("wrong number of samples for RGB")
|
||||
}
|
||||
case pPaletted:
|
||||
d.mode = mPaletted
|
||||
d.config.ColorModel = color.Palette(d.palette)
|
||||
case pWhiteIsZero:
|
||||
d.mode = mGrayInvert
|
||||
if d.bpp == 16 {
|
||||
d.config.ColorModel = color.Gray16Model
|
||||
} else {
|
||||
d.config.ColorModel = color.GrayModel
|
||||
}
|
||||
case pBlackIsZero:
|
||||
d.mode = mGray
|
||||
if d.bpp == 16 {
|
||||
d.config.ColorModel = color.Gray16Model
|
||||
} else {
|
||||
d.config.ColorModel = color.GrayModel
|
||||
}
|
||||
default:
|
||||
return nil, UnsupportedError("color model")
|
||||
}
|
||||
if d.firstVal(tPhotometricInterpretation) != pRGB {
|
||||
if len(d.features[tBitsPerSample]) != 1 {
|
||||
return nil, UnsupportedError("extra samples")
|
||||
}
|
||||
}
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// DecodeConfig returns the color model and dimensions of a TIFF image without
|
||||
// decoding the entire image.
|
||||
func DecodeConfig(r io.Reader) (image.Config, error) {
|
||||
d, err := newDecoder(r)
|
||||
if err != nil {
|
||||
return image.Config{}, err
|
||||
}
|
||||
return d.config, nil
|
||||
}
|
||||
|
||||
func ccittFillOrder(tiffFillOrder uint) ccitt.Order {
|
||||
if tiffFillOrder == 2 {
|
||||
return ccitt.LSB
|
||||
}
|
||||
return ccitt.MSB
|
||||
}
|
||||
|
||||
// Decode reads a TIFF image from r and returns it as an image.Image.
|
||||
// The type of Image returned depends on the contents of the TIFF.
|
||||
func Decode(r io.Reader) (img image.Image, err error) {
|
||||
d, err := newDecoder(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
blockPadding := false
|
||||
blockWidth := d.config.Width
|
||||
blockHeight := d.config.Height
|
||||
blocksAcross := 1
|
||||
blocksDown := 1
|
||||
|
||||
if d.config.Width == 0 {
|
||||
blocksAcross = 0
|
||||
}
|
||||
if d.config.Height == 0 {
|
||||
blocksDown = 0
|
||||
}
|
||||
|
||||
var blockOffsets, blockCounts []uint
|
||||
|
||||
if int(d.firstVal(tTileWidth)) != 0 {
|
||||
blockPadding = true
|
||||
|
||||
blockWidth = int(d.firstVal(tTileWidth))
|
||||
blockHeight = int(d.firstVal(tTileLength))
|
||||
|
||||
// The specification says that tile widths and lengths must be a multiple of 16.
|
||||
// We currently permit invalid sizes, but reject anything too small to limit the
|
||||
// amount of work a malicious input can force us to perform.
|
||||
if blockWidth < 8 || blockHeight < 8 {
|
||||
return nil, FormatError("tile size is too small")
|
||||
}
|
||||
|
||||
if blockWidth != 0 {
|
||||
blocksAcross = (d.config.Width + blockWidth - 1) / blockWidth
|
||||
}
|
||||
if blockHeight != 0 {
|
||||
blocksDown = (d.config.Height + blockHeight - 1) / blockHeight
|
||||
}
|
||||
|
||||
blockCounts = d.features[tTileByteCounts]
|
||||
blockOffsets = d.features[tTileOffsets]
|
||||
|
||||
} else {
|
||||
if int(d.firstVal(tRowsPerStrip)) != 0 {
|
||||
blockHeight = int(d.firstVal(tRowsPerStrip))
|
||||
}
|
||||
|
||||
if blockHeight != 0 {
|
||||
blocksDown = (d.config.Height + blockHeight - 1) / blockHeight
|
||||
}
|
||||
|
||||
blockOffsets = d.features[tStripOffsets]
|
||||
blockCounts = d.features[tStripByteCounts]
|
||||
}
|
||||
|
||||
// Check if we have the right number of strips/tiles, offsets and counts.
|
||||
if n := blocksAcross * blocksDown; len(blockOffsets) < n || len(blockCounts) < n {
|
||||
return nil, FormatError("inconsistent header")
|
||||
}
|
||||
|
||||
imgRect := image.Rect(0, 0, d.config.Width, d.config.Height)
|
||||
switch d.mode {
|
||||
case mGray, mGrayInvert:
|
||||
if d.bpp == 16 {
|
||||
img = image.NewGray16(imgRect)
|
||||
} else {
|
||||
img = image.NewGray(imgRect)
|
||||
}
|
||||
case mPaletted:
|
||||
img = image.NewPaletted(imgRect, d.palette)
|
||||
case mNRGBA:
|
||||
if d.bpp == 16 {
|
||||
img = image.NewNRGBA64(imgRect)
|
||||
} else {
|
||||
img = image.NewNRGBA(imgRect)
|
||||
}
|
||||
case mRGB, mRGBA:
|
||||
if d.bpp == 16 {
|
||||
img = image.NewRGBA64(imgRect)
|
||||
} else {
|
||||
img = image.NewRGBA(imgRect)
|
||||
}
|
||||
}
|
||||
|
||||
if blocksAcross == 0 || blocksDown == 0 {
|
||||
return
|
||||
}
|
||||
// Maximum data per pixel is 8 bytes (RGBA64).
|
||||
blockMaxDataSize := int64(blockWidth) * int64(blockHeight) * 8
|
||||
for i := 0; i < blocksAcross; i++ {
|
||||
blkW := blockWidth
|
||||
if !blockPadding && i == blocksAcross-1 && d.config.Width%blockWidth != 0 {
|
||||
blkW = d.config.Width % blockWidth
|
||||
}
|
||||
for j := 0; j < blocksDown; j++ {
|
||||
blkH := blockHeight
|
||||
if !blockPadding && j == blocksDown-1 && d.config.Height%blockHeight != 0 {
|
||||
blkH = d.config.Height % blockHeight
|
||||
}
|
||||
offset := int64(blockOffsets[j*blocksAcross+i])
|
||||
n := int64(blockCounts[j*blocksAcross+i])
|
||||
switch d.firstVal(tCompression) {
|
||||
|
||||
// According to the spec, Compression does not have a default value,
|
||||
// but some tools interpret a missing Compression value as none, so we do
|
||||
// the same.
|
||||
case cNone, 0:
|
||||
if b, ok := d.r.(*buffer); ok {
|
||||
d.buf, err = b.Slice(int(offset), int(n))
|
||||
} else {
|
||||
d.buf, err = safeReadAt(d.r, uint64(n), offset)
|
||||
}
|
||||
case cG3:
|
||||
inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero
|
||||
order := ccittFillOrder(d.firstVal(tFillOrder))
|
||||
r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group3, blkW, blkH, &ccitt.Options{Invert: inv, Align: false})
|
||||
d.buf, err = readBuf(r, d.buf, blockMaxDataSize)
|
||||
case cG4:
|
||||
inv := d.firstVal(tPhotometricInterpretation) == pWhiteIsZero
|
||||
order := ccittFillOrder(d.firstVal(tFillOrder))
|
||||
r := ccitt.NewReader(io.NewSectionReader(d.r, offset, n), order, ccitt.Group4, blkW, blkH, &ccitt.Options{Invert: inv, Align: false})
|
||||
d.buf, err = readBuf(r, d.buf, blockMaxDataSize)
|
||||
case cLZW:
|
||||
r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
|
||||
d.buf, err = readBuf(r, d.buf, blockMaxDataSize)
|
||||
r.Close()
|
||||
case cDeflate, cDeflateOld:
|
||||
var r io.ReadCloser
|
||||
r, err = zlib.NewReader(io.NewSectionReader(d.r, offset, n))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.buf, err = readBuf(r, d.buf, blockMaxDataSize)
|
||||
r.Close()
|
||||
case cPackBits:
|
||||
d.buf, err = unpackBits(io.NewSectionReader(d.r, offset, n))
|
||||
default:
|
||||
err = UnsupportedError(fmt.Sprintf("compression value %d", d.firstVal(tCompression)))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
xmin := i * blockWidth
|
||||
ymin := j * blockHeight
|
||||
xmax := xmin + blkW
|
||||
ymax := ymin + blkH
|
||||
err = d.decode(img, xmin, ymin, xmax, ymax)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func readBuf(r io.Reader, buf []byte, lim int64) ([]byte, error) {
|
||||
b := bytes.NewBuffer(buf[:0])
|
||||
_, err := b.ReadFrom(io.LimitReader(r, lim))
|
||||
return b.Bytes(), err
|
||||
}
|
||||
|
||||
func init() {
|
||||
image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
|
||||
image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
|
||||
}
|
||||
+445
@@ -0,0 +1,445 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package tiff
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// The TIFF format allows to choose the order of the different elements freely.
|
||||
// The basic structure of a TIFF file written by this package is:
|
||||
//
|
||||
// 1. Header (8 bytes).
|
||||
// 2. Image data.
|
||||
// 3. Image File Directory (IFD).
|
||||
// 4. "Pointer area" for larger entries in the IFD.
|
||||
|
||||
// We only write little-endian TIFF files.
|
||||
var enc = binary.LittleEndian
|
||||
|
||||
// An ifdEntry is a single entry in an Image File Directory.
|
||||
// A value of type dtRational is composed of two 32-bit values,
|
||||
// thus data contains two uints (numerator and denominator) for a single number.
|
||||
type ifdEntry struct {
|
||||
tag int
|
||||
datatype int
|
||||
data []uint32
|
||||
}
|
||||
|
||||
func (e ifdEntry) putData(p []byte) {
|
||||
for _, d := range e.data {
|
||||
switch e.datatype {
|
||||
case dtByte, dtASCII:
|
||||
p[0] = byte(d)
|
||||
p = p[1:]
|
||||
case dtShort:
|
||||
enc.PutUint16(p, uint16(d))
|
||||
p = p[2:]
|
||||
case dtLong, dtRational:
|
||||
enc.PutUint32(p, uint32(d))
|
||||
p = p[4:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type byTag []ifdEntry
|
||||
|
||||
func (d byTag) Len() int { return len(d) }
|
||||
func (d byTag) Less(i, j int) bool { return d[i].tag < d[j].tag }
|
||||
func (d byTag) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||
|
||||
func encodeGray(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
|
||||
if !predictor {
|
||||
return writePix(w, pix, dy, dx, stride)
|
||||
}
|
||||
buf := make([]byte, dx)
|
||||
for y := 0; y < dy; y++ {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx
|
||||
off := 0
|
||||
var v0 uint8
|
||||
for i := min; i < max; i++ {
|
||||
v1 := pix[i]
|
||||
buf[off] = v1 - v0
|
||||
v0 = v1
|
||||
off++
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeGray16(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
|
||||
buf := make([]byte, dx*2)
|
||||
for y := 0; y < dy; y++ {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx*2
|
||||
off := 0
|
||||
var v0 uint16
|
||||
for i := min; i < max; i += 2 {
|
||||
// An image.Gray16's Pix is in big-endian order.
|
||||
v1 := uint16(pix[i])<<8 | uint16(pix[i+1])
|
||||
if predictor {
|
||||
v0, v1 = v1, v1-v0
|
||||
}
|
||||
// We only write little-endian TIFF files.
|
||||
buf[off+0] = byte(v1)
|
||||
buf[off+1] = byte(v1 >> 8)
|
||||
off += 2
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeRGBA(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
|
||||
if !predictor {
|
||||
return writePix(w, pix, dy, dx*4, stride)
|
||||
}
|
||||
buf := make([]byte, dx*4)
|
||||
for y := 0; y < dy; y++ {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx*4
|
||||
off := 0
|
||||
var r0, g0, b0, a0 uint8
|
||||
for i := min; i < max; i += 4 {
|
||||
r1, g1, b1, a1 := pix[i+0], pix[i+1], pix[i+2], pix[i+3]
|
||||
buf[off+0] = r1 - r0
|
||||
buf[off+1] = g1 - g0
|
||||
buf[off+2] = b1 - b0
|
||||
buf[off+3] = a1 - a0
|
||||
off += 4
|
||||
r0, g0, b0, a0 = r1, g1, b1, a1
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeRGBA64(w io.Writer, pix []uint8, dx, dy, stride int, predictor bool) error {
|
||||
buf := make([]byte, dx*8)
|
||||
for y := 0; y < dy; y++ {
|
||||
min := y*stride + 0
|
||||
max := y*stride + dx*8
|
||||
off := 0
|
||||
var r0, g0, b0, a0 uint16
|
||||
for i := min; i < max; i += 8 {
|
||||
// An image.RGBA64's Pix is in big-endian order.
|
||||
r1 := uint16(pix[i+0])<<8 | uint16(pix[i+1])
|
||||
g1 := uint16(pix[i+2])<<8 | uint16(pix[i+3])
|
||||
b1 := uint16(pix[i+4])<<8 | uint16(pix[i+5])
|
||||
a1 := uint16(pix[i+6])<<8 | uint16(pix[i+7])
|
||||
if predictor {
|
||||
r0, r1 = r1, r1-r0
|
||||
g0, g1 = g1, g1-g0
|
||||
b0, b1 = b1, b1-b0
|
||||
a0, a1 = a1, a1-a0
|
||||
}
|
||||
// We only write little-endian TIFF files.
|
||||
buf[off+0] = byte(r1)
|
||||
buf[off+1] = byte(r1 >> 8)
|
||||
buf[off+2] = byte(g1)
|
||||
buf[off+3] = byte(g1 >> 8)
|
||||
buf[off+4] = byte(b1)
|
||||
buf[off+5] = byte(b1 >> 8)
|
||||
buf[off+6] = byte(a1)
|
||||
buf[off+7] = byte(a1 >> 8)
|
||||
off += 8
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func encode(w io.Writer, m image.Image, predictor bool) error {
|
||||
bounds := m.Bounds()
|
||||
buf := make([]byte, 4*bounds.Dx())
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
off := 0
|
||||
if predictor {
|
||||
var r0, g0, b0, a0 uint8
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
r, g, b, a := m.At(x, y).RGBA()
|
||||
r1 := uint8(r >> 8)
|
||||
g1 := uint8(g >> 8)
|
||||
b1 := uint8(b >> 8)
|
||||
a1 := uint8(a >> 8)
|
||||
buf[off+0] = r1 - r0
|
||||
buf[off+1] = g1 - g0
|
||||
buf[off+2] = b1 - b0
|
||||
buf[off+3] = a1 - a0
|
||||
off += 4
|
||||
r0, g0, b0, a0 = r1, g1, b1, a1
|
||||
}
|
||||
} else {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
r, g, b, a := m.At(x, y).RGBA()
|
||||
buf[off+0] = uint8(r >> 8)
|
||||
buf[off+1] = uint8(g >> 8)
|
||||
buf[off+2] = uint8(b >> 8)
|
||||
buf[off+3] = uint8(a >> 8)
|
||||
off += 4
|
||||
}
|
||||
}
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// writePix writes the internal byte array of an image to w. It is less general
|
||||
// but much faster then encode. writePix is used when pix directly
|
||||
// corresponds to one of the TIFF image types.
|
||||
func writePix(w io.Writer, pix []byte, nrows, length, stride int) error {
|
||||
if length == stride {
|
||||
_, err := w.Write(pix[:nrows*length])
|
||||
return err
|
||||
}
|
||||
for ; nrows > 0; nrows-- {
|
||||
if _, err := w.Write(pix[:length]); err != nil {
|
||||
return err
|
||||
}
|
||||
pix = pix[stride:]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeIFD(w io.Writer, ifdOffset int, d []ifdEntry) error {
|
||||
var buf [ifdLen]byte
|
||||
// Make space for "pointer area" containing IFD entry data
|
||||
// longer than 4 bytes.
|
||||
parea := make([]byte, 1024)
|
||||
pstart := ifdOffset + ifdLen*len(d) + 6
|
||||
var o int // Current offset in parea.
|
||||
|
||||
// The IFD has to be written with the tags in ascending order.
|
||||
sort.Sort(byTag(d))
|
||||
|
||||
// Write the number of entries in this IFD.
|
||||
if err := binary.Write(w, enc, uint16(len(d))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ent := range d {
|
||||
enc.PutUint16(buf[0:2], uint16(ent.tag))
|
||||
enc.PutUint16(buf[2:4], uint16(ent.datatype))
|
||||
count := uint32(len(ent.data))
|
||||
if ent.datatype == dtRational {
|
||||
count /= 2
|
||||
}
|
||||
enc.PutUint32(buf[4:8], count)
|
||||
datalen := int(count * lengths[ent.datatype])
|
||||
if datalen <= 4 {
|
||||
ent.putData(buf[8:12])
|
||||
} else {
|
||||
if (o + datalen) > len(parea) {
|
||||
newlen := len(parea) + 1024
|
||||
for (o + datalen) > newlen {
|
||||
newlen += 1024
|
||||
}
|
||||
newarea := make([]byte, newlen)
|
||||
copy(newarea, parea)
|
||||
parea = newarea
|
||||
}
|
||||
ent.putData(parea[o : o+datalen])
|
||||
enc.PutUint32(buf[8:12], uint32(pstart+o))
|
||||
o += datalen
|
||||
}
|
||||
if _, err := w.Write(buf[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// The IFD ends with the offset of the next IFD in the file,
|
||||
// or zero if it is the last one (page 14).
|
||||
if err := binary.Write(w, enc, uint32(0)); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := w.Write(parea[:o])
|
||||
return err
|
||||
}
|
||||
|
||||
// Options are the encoding parameters.
|
||||
type Options struct {
|
||||
// Compression is the type of compression used.
|
||||
Compression CompressionType
|
||||
// Predictor determines whether a differencing predictor is used;
|
||||
// if true, instead of each pixel's color, the color difference to the
|
||||
// preceding one is saved. This improves the compression for certain
|
||||
// types of images and compressors. For example, it works well for
|
||||
// photos with Deflate compression.
|
||||
Predictor bool
|
||||
}
|
||||
|
||||
// Encode writes the image m to w. opt determines the options used for
|
||||
// encoding, such as the compression type. If opt is nil, an uncompressed
|
||||
// image is written.
|
||||
func Encode(w io.Writer, m image.Image, opt *Options) error {
|
||||
d := m.Bounds().Size()
|
||||
|
||||
if d.X == 0 || d.Y == 0 {
|
||||
return errors.New("tiff: zero-size image")
|
||||
}
|
||||
|
||||
compression := uint32(cNone)
|
||||
predictor := false
|
||||
if opt != nil {
|
||||
compression = opt.Compression.specValue()
|
||||
// The predictor field is only used with LZW. See page 64 of the spec.
|
||||
predictor = opt.Predictor && compression == cLZW
|
||||
}
|
||||
|
||||
_, err := io.WriteString(w, leHeader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Compressed data is written into a buffer first, so that we
|
||||
// know the compressed size.
|
||||
var buf bytes.Buffer
|
||||
// dst holds the destination for the pixel data of the image --
|
||||
// either w or a writer to buf.
|
||||
var dst io.Writer
|
||||
// imageLen is the length of the pixel data in bytes.
|
||||
// The offset of the IFD is imageLen + 8 header bytes.
|
||||
var imageLen int
|
||||
|
||||
switch compression {
|
||||
case cNone:
|
||||
dst = w
|
||||
// Write IFD offset before outputting pixel data.
|
||||
switch m.(type) {
|
||||
case *image.Paletted:
|
||||
imageLen = d.X * d.Y * 1
|
||||
case *image.Gray:
|
||||
imageLen = d.X * d.Y * 1
|
||||
case *image.Gray16:
|
||||
imageLen = d.X * d.Y * 2
|
||||
case *image.RGBA64:
|
||||
imageLen = d.X * d.Y * 8
|
||||
case *image.NRGBA64:
|
||||
imageLen = d.X * d.Y * 8
|
||||
default:
|
||||
imageLen = d.X * d.Y * 4
|
||||
}
|
||||
err = binary.Write(w, enc, uint32(imageLen+8))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case cDeflate:
|
||||
dst = zlib.NewWriter(&buf)
|
||||
default:
|
||||
return errors.New("tiff: unsupported compression")
|
||||
}
|
||||
|
||||
pr := uint32(prNone)
|
||||
photometricInterpretation := uint32(pRGB)
|
||||
samplesPerPixel := uint32(4)
|
||||
bitsPerSample := []uint32{8, 8, 8, 8}
|
||||
extraSamples := uint32(0)
|
||||
colorMap := []uint32{}
|
||||
|
||||
if predictor {
|
||||
pr = prHorizontal
|
||||
}
|
||||
switch m := m.(type) {
|
||||
case *image.Paletted:
|
||||
photometricInterpretation = pPaletted
|
||||
samplesPerPixel = 1
|
||||
bitsPerSample = []uint32{8}
|
||||
colorMap = make([]uint32, 256*3)
|
||||
for i := 0; i < 256 && i < len(m.Palette); i++ {
|
||||
r, g, b, _ := m.Palette[i].RGBA()
|
||||
colorMap[i+0*256] = uint32(r)
|
||||
colorMap[i+1*256] = uint32(g)
|
||||
colorMap[i+2*256] = uint32(b)
|
||||
}
|
||||
err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
|
||||
case *image.Gray:
|
||||
photometricInterpretation = pBlackIsZero
|
||||
samplesPerPixel = 1
|
||||
bitsPerSample = []uint32{8}
|
||||
err = encodeGray(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
|
||||
case *image.Gray16:
|
||||
photometricInterpretation = pBlackIsZero
|
||||
samplesPerPixel = 1
|
||||
bitsPerSample = []uint32{16}
|
||||
err = encodeGray16(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
|
||||
case *image.NRGBA:
|
||||
extraSamples = 2 // Unassociated alpha.
|
||||
err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
|
||||
case *image.NRGBA64:
|
||||
extraSamples = 2 // Unassociated alpha.
|
||||
bitsPerSample = []uint32{16, 16, 16, 16}
|
||||
err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
|
||||
case *image.RGBA:
|
||||
extraSamples = 1 // Associated alpha.
|
||||
err = encodeRGBA(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
|
||||
case *image.RGBA64:
|
||||
extraSamples = 1 // Associated alpha.
|
||||
bitsPerSample = []uint32{16, 16, 16, 16}
|
||||
err = encodeRGBA64(dst, m.Pix, d.X, d.Y, m.Stride, predictor)
|
||||
default:
|
||||
extraSamples = 1 // Associated alpha.
|
||||
err = encode(dst, m, predictor)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if compression != cNone {
|
||||
if err = dst.(io.Closer).Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
imageLen = buf.Len()
|
||||
if err = binary.Write(w, enc, uint32(imageLen+8)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = buf.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ifd := []ifdEntry{
|
||||
{tImageWidth, dtShort, []uint32{uint32(d.X)}},
|
||||
{tImageLength, dtShort, []uint32{uint32(d.Y)}},
|
||||
{tBitsPerSample, dtShort, bitsPerSample},
|
||||
{tCompression, dtShort, []uint32{compression}},
|
||||
{tPhotometricInterpretation, dtShort, []uint32{photometricInterpretation}},
|
||||
{tStripOffsets, dtLong, []uint32{8}},
|
||||
{tSamplesPerPixel, dtShort, []uint32{samplesPerPixel}},
|
||||
{tRowsPerStrip, dtShort, []uint32{uint32(d.Y)}},
|
||||
{tStripByteCounts, dtLong, []uint32{uint32(imageLen)}},
|
||||
// There is currently no support for storing the image
|
||||
// resolution, so give a bogus value of 72x72 dpi.
|
||||
{tXResolution, dtRational, []uint32{72, 1}},
|
||||
{tYResolution, dtRational, []uint32{72, 1}},
|
||||
{tResolutionUnit, dtShort, []uint32{resPerInch}},
|
||||
}
|
||||
if pr != prNone {
|
||||
ifd = append(ifd, ifdEntry{tPredictor, dtShort, []uint32{pr}})
|
||||
}
|
||||
if len(colorMap) != 0 {
|
||||
ifd = append(ifd, ifdEntry{tColorMap, dtShort, colorMap})
|
||||
}
|
||||
if extraSamples > 0 {
|
||||
ifd = append(ifd, ifdEntry{tExtraSamples, dtShort, []uint32{extraSamples}})
|
||||
}
|
||||
|
||||
return writeIFD(w, imageLen+8, ifd)
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !appengine && gc && !noasm
|
||||
|
||||
package vector
|
||||
|
||||
func haveSSE4_1() bool
|
||||
|
||||
var haveAccumulateSIMD = haveSSE4_1()
|
||||
|
||||
//go:noescape
|
||||
func fixedAccumulateOpOverSIMD(dst []uint8, src []uint32)
|
||||
|
||||
//go:noescape
|
||||
func fixedAccumulateOpSrcSIMD(dst []uint8, src []uint32)
|
||||
|
||||
//go:noescape
|
||||
func fixedAccumulateMaskSIMD(buf []uint32)
|
||||
|
||||
//go:noescape
|
||||
func floatingAccumulateOpOverSIMD(dst []uint8, src []float32)
|
||||
|
||||
//go:noescape
|
||||
func floatingAccumulateOpSrcSIMD(dst []uint8, src []float32)
|
||||
|
||||
//go:noescape
|
||||
func floatingAccumulateMaskSIMD(dst []uint32, src []float32)
|
||||
+1028
File diff suppressed because it is too large
Load Diff
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !amd64 || appengine || !gc || noasm
|
||||
|
||||
package vector
|
||||
|
||||
const haveAccumulateSIMD = false
|
||||
|
||||
func fixedAccumulateOpOverSIMD(dst []uint8, src []uint32) {}
|
||||
func fixedAccumulateOpSrcSIMD(dst []uint8, src []uint32) {}
|
||||
func fixedAccumulateMaskSIMD(buf []uint32) {}
|
||||
func floatingAccumulateOpOverSIMD(dst []uint8, src []float32) {}
|
||||
func floatingAccumulateOpSrcSIMD(dst []uint8, src []float32) {}
|
||||
func floatingAccumulateMaskSIMD(dst []uint32, src []float32) {}
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
// +build gc
|
||||
// +build !noasm
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// fl is short for floating point math. fx is short for fixed point math.
|
||||
|
||||
DATA flAlmost65536<>+0x00(SB)/8, $0x477fffff477fffff
|
||||
DATA flAlmost65536<>+0x08(SB)/8, $0x477fffff477fffff
|
||||
DATA flOne<>+0x00(SB)/8, $0x3f8000003f800000
|
||||
DATA flOne<>+0x08(SB)/8, $0x3f8000003f800000
|
||||
DATA flSignMask<>+0x00(SB)/8, $0x7fffffff7fffffff
|
||||
DATA flSignMask<>+0x08(SB)/8, $0x7fffffff7fffffff
|
||||
|
||||
// scatterAndMulBy0x101 is a PSHUFB mask that brings the low four bytes of an
|
||||
// XMM register to the low byte of that register's four uint32 values. It
|
||||
// duplicates those bytes, effectively multiplying each uint32 by 0x101.
|
||||
//
|
||||
// It transforms a little-endian 16-byte XMM value from
|
||||
// ijkl????????????
|
||||
// to
|
||||
// ii00jj00kk00ll00
|
||||
DATA scatterAndMulBy0x101<>+0x00(SB)/8, $0x8080010180800000
|
||||
DATA scatterAndMulBy0x101<>+0x08(SB)/8, $0x8080030380800202
|
||||
|
||||
// gather is a PSHUFB mask that brings the second-lowest byte of the XMM
|
||||
// register's four uint32 values to the low four bytes of that register.
|
||||
//
|
||||
// It transforms a little-endian 16-byte XMM value from
|
||||
// ?i???j???k???l??
|
||||
// to
|
||||
// ijkl000000000000
|
||||
DATA gather<>+0x00(SB)/8, $0x808080800d090501
|
||||
DATA gather<>+0x08(SB)/8, $0x8080808080808080
|
||||
|
||||
DATA fxAlmost65536<>+0x00(SB)/8, $0x0000ffff0000ffff
|
||||
DATA fxAlmost65536<>+0x08(SB)/8, $0x0000ffff0000ffff
|
||||
DATA inverseFFFF<>+0x00(SB)/8, $0x8000800180008001
|
||||
DATA inverseFFFF<>+0x08(SB)/8, $0x8000800180008001
|
||||
|
||||
GLOBL flAlmost65536<>(SB), (NOPTR+RODATA), $16
|
||||
GLOBL flOne<>(SB), (NOPTR+RODATA), $16
|
||||
GLOBL flSignMask<>(SB), (NOPTR+RODATA), $16
|
||||
GLOBL scatterAndMulBy0x101<>(SB), (NOPTR+RODATA), $16
|
||||
GLOBL gather<>(SB), (NOPTR+RODATA), $16
|
||||
GLOBL fxAlmost65536<>(SB), (NOPTR+RODATA), $16
|
||||
GLOBL inverseFFFF<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
// func haveSSE4_1() bool
|
||||
TEXT ·haveSSE4_1(SB), NOSPLIT, $0
|
||||
MOVQ $1, AX
|
||||
CPUID
|
||||
SHRQ $19, CX
|
||||
ANDQ $1, CX
|
||||
MOVB CX, ret+0(FP)
|
||||
RET
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// func {{.LongName}}SIMD({{.Args}})
|
||||
//
|
||||
// XMM registers. Variable names are per
|
||||
// https://github.com/google/font-rs/blob/master/src/accumulate.c
|
||||
//
|
||||
// xmm0 scratch
|
||||
// xmm1 x
|
||||
// xmm2 y, z
|
||||
// xmm3 {{.XMM3}}
|
||||
// xmm4 {{.XMM4}}
|
||||
// xmm5 {{.XMM5}}
|
||||
// xmm6 {{.XMM6}}
|
||||
// xmm7 offset
|
||||
// xmm8 {{.XMM8}}
|
||||
// xmm9 {{.XMM9}}
|
||||
// xmm10 {{.XMM10}}
|
||||
TEXT ·{{.LongName}}SIMD(SB), NOSPLIT, ${{.FrameSize}}-{{.ArgsSize}}
|
||||
{{.LoadArgs}}
|
||||
|
||||
// R10 = len(src) &^ 3
|
||||
// R11 = len(src)
|
||||
MOVQ R10, R11
|
||||
ANDQ $-4, R10
|
||||
|
||||
{{.Setup}}
|
||||
|
||||
{{.LoadXMMRegs}}
|
||||
|
||||
// offset := XMM(0x00000000 repeated four times) // Cumulative sum.
|
||||
XORPS X7, X7
|
||||
|
||||
// i := 0
|
||||
MOVQ $0, R9
|
||||
|
||||
{{.ShortName}}Loop4:
|
||||
// for i < (len(src) &^ 3)
|
||||
CMPQ R9, R10
|
||||
JAE {{.ShortName}}Loop1
|
||||
|
||||
// x = XMM(s0, s1, s2, s3)
|
||||
//
|
||||
// Where s0 is src[i+0], s1 is src[i+1], etc.
|
||||
MOVOU (SI), X1
|
||||
|
||||
// scratch = XMM(0, s0, s1, s2)
|
||||
// x += scratch // yields x == XMM(s0, s0+s1, s1+s2, s2+s3)
|
||||
MOVOU X1, X0
|
||||
PSLLO $4, X0
|
||||
{{.Add}} X0, X1
|
||||
|
||||
// scratch = XMM(0, 0, 0, 0)
|
||||
// scratch = XMM(scratch@0, scratch@0, x@0, x@1) // yields scratch == XMM(0, 0, s0, s0+s1)
|
||||
// x += scratch // yields x == XMM(s0, s0+s1, s0+s1+s2, s0+s1+s2+s3)
|
||||
XORPS X0, X0
|
||||
SHUFPS $0x40, X1, X0
|
||||
{{.Add}} X0, X1
|
||||
|
||||
// x += offset
|
||||
{{.Add}} X7, X1
|
||||
|
||||
{{.ClampAndScale}}
|
||||
|
||||
{{.ConvertToInt32}}
|
||||
|
||||
{{.Store4}}
|
||||
|
||||
// offset = XMM(x@3, x@3, x@3, x@3)
|
||||
MOVOU X1, X7
|
||||
SHUFPS $0xff, X1, X7
|
||||
|
||||
// i += 4
|
||||
// dst = dst[4:]
|
||||
// src = src[4:]
|
||||
ADDQ $4, R9
|
||||
ADDQ ${{.DstElemSize4}}, DI
|
||||
ADDQ $16, SI
|
||||
JMP {{.ShortName}}Loop4
|
||||
|
||||
{{.ShortName}}Loop1:
|
||||
// for i < len(src)
|
||||
CMPQ R9, R11
|
||||
JAE {{.ShortName}}End
|
||||
|
||||
// x = src[i] + offset
|
||||
MOVL (SI), X1
|
||||
{{.Add}} X7, X1
|
||||
|
||||
{{.ClampAndScale}}
|
||||
|
||||
{{.ConvertToInt32}}
|
||||
|
||||
{{.Store1}}
|
||||
|
||||
// offset = x
|
||||
MOVOU X1, X7
|
||||
|
||||
// i += 1
|
||||
// dst = dst[1:]
|
||||
// src = src[1:]
|
||||
ADDQ $1, R9
|
||||
ADDQ ${{.DstElemSize1}}, DI
|
||||
ADDQ $4, SI
|
||||
JMP {{.ShortName}}Loop1
|
||||
|
||||
{{.ShortName}}End:
|
||||
RET
|
||||
+316
@@ -0,0 +1,316 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vector
|
||||
|
||||
// This file contains a fixed point math implementation of the vector
|
||||
// graphics rasterizer.
|
||||
|
||||
const (
|
||||
// ϕ is the number of binary digits after the fixed point.
|
||||
//
|
||||
// For example, if ϕ == 10 (and int1ϕ is based on the int32 type) then we
|
||||
// are using 22.10 fixed point math.
|
||||
//
|
||||
// When changing this number, also change the assembly code (search for ϕ
|
||||
// in the .s files).
|
||||
ϕ = 9
|
||||
|
||||
fxOne int1ϕ = 1 << ϕ
|
||||
fxOneAndAHalf int1ϕ = 1<<ϕ + 1<<(ϕ-1)
|
||||
fxOneMinusIota int1ϕ = 1<<ϕ - 1 // Used for rounding up.
|
||||
)
|
||||
|
||||
// int1ϕ is a signed fixed-point number with 1*ϕ binary digits after the fixed
|
||||
// point.
|
||||
type int1ϕ int32
|
||||
|
||||
// int2ϕ is a signed fixed-point number with 2*ϕ binary digits after the fixed
|
||||
// point.
|
||||
//
|
||||
// The Rasterizer's bufU32 field, nominally of type []uint32 (since that slice
|
||||
// is also used by other code), can be thought of as a []int2ϕ during the
|
||||
// fixedLineTo method. Lines of code that are actually like:
|
||||
//
|
||||
// buf[i] += uint32(etc) // buf has type []uint32.
|
||||
//
|
||||
// can be thought of as
|
||||
//
|
||||
// buf[i] += int2ϕ(etc) // buf has type []int2ϕ.
|
||||
type int2ϕ int32
|
||||
|
||||
func fixedFloor(x int1ϕ) int32 { return int32(x >> ϕ) }
|
||||
func fixedCeil(x int1ϕ) int32 { return int32((x + fxOneMinusIota) >> ϕ) }
|
||||
|
||||
func (z *Rasterizer) fixedLineTo(bx, by float32) {
|
||||
ax, ay := z.penX, z.penY
|
||||
z.penX, z.penY = bx, by
|
||||
dir := int1ϕ(1)
|
||||
if ay > by {
|
||||
dir, ax, ay, bx, by = -1, bx, by, ax, ay
|
||||
}
|
||||
// Horizontal line segments yield no change in coverage. Almost horizontal
|
||||
// segments would yield some change, in ideal math, but the computation
|
||||
// further below, involving 1 / (by - ay), is unstable in fixed point math,
|
||||
// so we treat the segment as if it was perfectly horizontal.
|
||||
if by-ay <= 0.000001 {
|
||||
return
|
||||
}
|
||||
dxdy := (bx - ax) / (by - ay)
|
||||
|
||||
ayϕ := int1ϕ(ay * float32(fxOne))
|
||||
byϕ := int1ϕ(by * float32(fxOne))
|
||||
|
||||
x := int1ϕ(ax * float32(fxOne))
|
||||
y := fixedFloor(ayϕ)
|
||||
yMax := fixedCeil(byϕ)
|
||||
if yMax > int32(z.size.Y) {
|
||||
yMax = int32(z.size.Y)
|
||||
}
|
||||
width := int32(z.size.X)
|
||||
|
||||
for ; y < yMax; y++ {
|
||||
dy := min(int1ϕ(y+1)<<ϕ, byϕ) - max(int1ϕ(y)<<ϕ, ayϕ)
|
||||
xNext := x + int1ϕ(float32(dy)*dxdy)
|
||||
if y < 0 {
|
||||
x = xNext
|
||||
continue
|
||||
}
|
||||
buf := z.bufU32[y*width:]
|
||||
d := dy * dir // d ranges up to ±1<<(1*ϕ).
|
||||
x0, x1 := x, xNext
|
||||
if x > xNext {
|
||||
x0, x1 = x1, x0
|
||||
}
|
||||
x0i := fixedFloor(x0)
|
||||
x0Floor := int1ϕ(x0i) << ϕ
|
||||
x1i := fixedCeil(x1)
|
||||
x1Ceil := int1ϕ(x1i) << ϕ
|
||||
|
||||
if x1i <= x0i+1 {
|
||||
xmf := (x+xNext)>>1 - x0Floor
|
||||
if i := clamp(x0i+0, width); i < uint(len(buf)) {
|
||||
buf[i] += uint32(d * (fxOne - xmf))
|
||||
}
|
||||
if i := clamp(x0i+1, width); i < uint(len(buf)) {
|
||||
buf[i] += uint32(d * xmf)
|
||||
}
|
||||
} else {
|
||||
oneOverS := x1 - x0
|
||||
twoOverS := 2 * oneOverS
|
||||
x0f := x0 - x0Floor
|
||||
oneMinusX0f := fxOne - x0f
|
||||
oneMinusX0fSquared := oneMinusX0f * oneMinusX0f
|
||||
x1f := x1 - x1Ceil + fxOne
|
||||
x1fSquared := x1f * x1f
|
||||
|
||||
// These next two variables are unused, as rounding errors are
|
||||
// minimized when we delay the division by oneOverS for as long as
|
||||
// possible. These lines of code (and the "In ideal math" comments
|
||||
// below) are commented out instead of deleted in order to aid the
|
||||
// comparison with the floating point version of the rasterizer.
|
||||
//
|
||||
// a0 := ((oneMinusX0f * oneMinusX0f) >> 1) / oneOverS
|
||||
// am := ((x1f * x1f) >> 1) / oneOverS
|
||||
|
||||
if i := clamp(x0i, width); i < uint(len(buf)) {
|
||||
// In ideal math: buf[i] += uint32(d * a0)
|
||||
D := oneMinusX0fSquared // D ranges up to ±1<<(2*ϕ).
|
||||
D *= d // D ranges up to ±1<<(3*ϕ).
|
||||
D /= twoOverS
|
||||
buf[i] += uint32(D)
|
||||
}
|
||||
|
||||
if x1i == x0i+2 {
|
||||
if i := clamp(x0i+1, width); i < uint(len(buf)) {
|
||||
// In ideal math: buf[i] += uint32(d * (fxOne - a0 - am))
|
||||
//
|
||||
// (x1i == x0i+2) and (twoOverS == 2 * (x1 - x0)) implies
|
||||
// that twoOverS ranges up to +1<<(1*ϕ+2).
|
||||
D := twoOverS<<ϕ - oneMinusX0fSquared - x1fSquared // D ranges up to ±1<<(2*ϕ+2).
|
||||
D *= d // D ranges up to ±1<<(3*ϕ+2).
|
||||
D /= twoOverS
|
||||
buf[i] += uint32(D)
|
||||
}
|
||||
} else {
|
||||
// This is commented out for the same reason as a0 and am.
|
||||
//
|
||||
// a1 := ((fxOneAndAHalf - x0f) << ϕ) / oneOverS
|
||||
|
||||
if i := clamp(x0i+1, width); i < uint(len(buf)) {
|
||||
// In ideal math:
|
||||
// buf[i] += uint32(d * (a1 - a0))
|
||||
// or equivalently (but better in non-ideal, integer math,
|
||||
// with respect to rounding errors),
|
||||
// buf[i] += uint32(A * d / twoOverS)
|
||||
// where
|
||||
// A = (a1 - a0) * twoOverS
|
||||
// = a1*twoOverS - a0*twoOverS
|
||||
// Noting that twoOverS/oneOverS equals 2, substituting for
|
||||
// a0 and then a1, given above, yields:
|
||||
// A = a1*twoOverS - oneMinusX0fSquared
|
||||
// = (fxOneAndAHalf-x0f)<<(ϕ+1) - oneMinusX0fSquared
|
||||
// = fxOneAndAHalf<<(ϕ+1) - x0f<<(ϕ+1) - oneMinusX0fSquared
|
||||
//
|
||||
// This is a positive number minus two non-negative
|
||||
// numbers. For an upper bound on A, the positive number is
|
||||
// P = fxOneAndAHalf<<(ϕ+1)
|
||||
// < (2*fxOne)<<(ϕ+1)
|
||||
// = fxOne<<(ϕ+2)
|
||||
// = 1<<(2*ϕ+2)
|
||||
//
|
||||
// For a lower bound on A, the two non-negative numbers are
|
||||
// N = x0f<<(ϕ+1) + oneMinusX0fSquared
|
||||
// ≤ x0f<<(ϕ+1) + fxOne*fxOne
|
||||
// = x0f<<(ϕ+1) + 1<<(2*ϕ)
|
||||
// < x0f<<(ϕ+1) + 1<<(2*ϕ+1)
|
||||
// ≤ fxOne<<(ϕ+1) + 1<<(2*ϕ+1)
|
||||
// = 1<<(2*ϕ+1) + 1<<(2*ϕ+1)
|
||||
// = 1<<(2*ϕ+2)
|
||||
//
|
||||
// Thus, A ranges up to ±1<<(2*ϕ+2). It is possible to
|
||||
// derive a tighter bound, but this bound is sufficient to
|
||||
// reason about overflow.
|
||||
D := (fxOneAndAHalf-x0f)<<(ϕ+1) - oneMinusX0fSquared // D ranges up to ±1<<(2*ϕ+2).
|
||||
D *= d // D ranges up to ±1<<(3*ϕ+2).
|
||||
D /= twoOverS
|
||||
buf[i] += uint32(D)
|
||||
}
|
||||
dTimesS := uint32((d << (2 * ϕ)) / oneOverS)
|
||||
for xi := x0i + 2; xi < x1i-1; xi++ {
|
||||
if i := clamp(xi, width); i < uint(len(buf)) {
|
||||
buf[i] += dTimesS
|
||||
}
|
||||
}
|
||||
|
||||
// This is commented out for the same reason as a0 and am.
|
||||
//
|
||||
// a2 := a1 + (int1ϕ(x1i-x0i-3)<<(2*ϕ))/oneOverS
|
||||
|
||||
if i := clamp(x1i-1, width); i < uint(len(buf)) {
|
||||
// In ideal math:
|
||||
// buf[i] += uint32(d * (fxOne - a2 - am))
|
||||
// or equivalently (but better in non-ideal, integer math,
|
||||
// with respect to rounding errors),
|
||||
// buf[i] += uint32(A * d / twoOverS)
|
||||
// where
|
||||
// A = (fxOne - a2 - am) * twoOverS
|
||||
// = twoOverS<<ϕ - a2*twoOverS - am*twoOverS
|
||||
// Noting that twoOverS/oneOverS equals 2, substituting for
|
||||
// am and then a2, given above, yields:
|
||||
// A = twoOverS<<ϕ - a2*twoOverS - x1f*x1f
|
||||
// = twoOverS<<ϕ - a1*twoOverS - (int1ϕ(x1i-x0i-3)<<(2*ϕ))*2 - x1f*x1f
|
||||
// = twoOverS<<ϕ - a1*twoOverS - int1ϕ(x1i-x0i-3)<<(2*ϕ+1) - x1f*x1f
|
||||
// Substituting for a1, given above, yields:
|
||||
// A = twoOverS<<ϕ - ((fxOneAndAHalf-x0f)<<ϕ)*2 - int1ϕ(x1i-x0i-3)<<(2*ϕ+1) - x1f*x1f
|
||||
// = twoOverS<<ϕ - (fxOneAndAHalf-x0f)<<(ϕ+1) - int1ϕ(x1i-x0i-3)<<(2*ϕ+1) - x1f*x1f
|
||||
// = B<<ϕ - x1f*x1f
|
||||
// where
|
||||
// B = twoOverS - (fxOneAndAHalf-x0f)<<1 - int1ϕ(x1i-x0i-3)<<(ϕ+1)
|
||||
// = (x1-x0)<<1 - (fxOneAndAHalf-x0f)<<1 - int1ϕ(x1i-x0i-3)<<(ϕ+1)
|
||||
//
|
||||
// Re-arranging the defintions given above:
|
||||
// x0Floor := int1ϕ(x0i) << ϕ
|
||||
// x0f := x0 - x0Floor
|
||||
// x1Ceil := int1ϕ(x1i) << ϕ
|
||||
// x1f := x1 - x1Ceil + fxOne
|
||||
// combined with fxOne = 1<<ϕ yields:
|
||||
// x0 = x0f + int1ϕ(x0i)<<ϕ
|
||||
// x1 = x1f + int1ϕ(x1i-1)<<ϕ
|
||||
// so that expanding (x1-x0) yields:
|
||||
// B = (x1f-x0f + int1ϕ(x1i-x0i-1)<<ϕ)<<1 - (fxOneAndAHalf-x0f)<<1 - int1ϕ(x1i-x0i-3)<<(ϕ+1)
|
||||
// = (x1f-x0f)<<1 + int1ϕ(x1i-x0i-1)<<(ϕ+1) - (fxOneAndAHalf-x0f)<<1 - int1ϕ(x1i-x0i-3)<<(ϕ+1)
|
||||
// A large part of the second and fourth terms cancel:
|
||||
// B = (x1f-x0f)<<1 - (fxOneAndAHalf-x0f)<<1 - int1ϕ(-2)<<(ϕ+1)
|
||||
// = (x1f-x0f)<<1 - (fxOneAndAHalf-x0f)<<1 + 1<<(ϕ+2)
|
||||
// = (x1f - fxOneAndAHalf)<<1 + 1<<(ϕ+2)
|
||||
// The first term, (x1f - fxOneAndAHalf)<<1, is a negative
|
||||
// number, bounded below by -fxOneAndAHalf<<1, which is
|
||||
// greater than -fxOne<<2, or -1<<(ϕ+2). Thus, B ranges up
|
||||
// to ±1<<(ϕ+2). One final simplification:
|
||||
// B = x1f<<1 + (1<<(ϕ+2) - fxOneAndAHalf<<1)
|
||||
const C = 1<<(ϕ+2) - fxOneAndAHalf<<1
|
||||
D := x1f<<1 + C // D ranges up to ±1<<(1*ϕ+2).
|
||||
D <<= ϕ // D ranges up to ±1<<(2*ϕ+2).
|
||||
D -= x1fSquared // D ranges up to ±1<<(2*ϕ+3).
|
||||
D *= d // D ranges up to ±1<<(3*ϕ+3).
|
||||
D /= twoOverS
|
||||
buf[i] += uint32(D)
|
||||
}
|
||||
}
|
||||
|
||||
if i := clamp(x1i, width); i < uint(len(buf)) {
|
||||
// In ideal math: buf[i] += uint32(d * am)
|
||||
D := x1fSquared // D ranges up to ±1<<(2*ϕ).
|
||||
D *= d // D ranges up to ±1<<(3*ϕ).
|
||||
D /= twoOverS
|
||||
buf[i] += uint32(D)
|
||||
}
|
||||
}
|
||||
|
||||
x = xNext
|
||||
}
|
||||
}
|
||||
|
||||
func fixedAccumulateOpOver(dst []uint8, src []uint32) {
|
||||
// Sanity check that len(dst) >= len(src).
|
||||
if len(dst) < len(src) {
|
||||
return
|
||||
}
|
||||
|
||||
acc := int2ϕ(0)
|
||||
for i, v := range src {
|
||||
acc += int2ϕ(v)
|
||||
a := acc
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
a >>= 2*ϕ - 16
|
||||
if a > 0xffff {
|
||||
a = 0xffff
|
||||
}
|
||||
// This algorithm comes from the standard library's image/draw package.
|
||||
dstA := uint32(dst[i]) * 0x101
|
||||
maskA := uint32(a)
|
||||
outA := dstA*(0xffff-maskA)/0xffff + maskA
|
||||
dst[i] = uint8(outA >> 8)
|
||||
}
|
||||
}
|
||||
|
||||
func fixedAccumulateOpSrc(dst []uint8, src []uint32) {
|
||||
// Sanity check that len(dst) >= len(src).
|
||||
if len(dst) < len(src) {
|
||||
return
|
||||
}
|
||||
|
||||
acc := int2ϕ(0)
|
||||
for i, v := range src {
|
||||
acc += int2ϕ(v)
|
||||
a := acc
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
a >>= 2*ϕ - 8
|
||||
if a > 0xff {
|
||||
a = 0xff
|
||||
}
|
||||
dst[i] = uint8(a)
|
||||
}
|
||||
}
|
||||
|
||||
func fixedAccumulateMask(buf []uint32) {
|
||||
acc := int2ϕ(0)
|
||||
for i, v := range buf {
|
||||
acc += int2ϕ(v)
|
||||
a := acc
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
a >>= 2*ϕ - 16
|
||||
if a > 0xffff {
|
||||
a = 0xffff
|
||||
}
|
||||
buf[i] = uint32(a)
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vector
|
||||
|
||||
// This file contains a floating point math implementation of the vector
|
||||
// graphics rasterizer.
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
func floatingFloor(x float32) int32 { return int32(math.Floor(float64(x))) }
|
||||
func floatingCeil(x float32) int32 { return int32(math.Ceil(float64(x))) }
|
||||
|
||||
func (z *Rasterizer) floatingLineTo(bx, by float32) {
|
||||
ax, ay := z.penX, z.penY
|
||||
z.penX, z.penY = bx, by
|
||||
dir := float32(1)
|
||||
if ay > by {
|
||||
dir, ax, ay, bx, by = -1, bx, by, ax, ay
|
||||
}
|
||||
// Horizontal line segments yield no change in coverage. Almost horizontal
|
||||
// segments would yield some change, in ideal math, but the computation
|
||||
// further below, involving 1 / (by - ay), is unstable in floating point
|
||||
// math, so we treat the segment as if it was perfectly horizontal.
|
||||
if by-ay <= 0.000001 {
|
||||
return
|
||||
}
|
||||
dxdy := (bx - ax) / (by - ay)
|
||||
|
||||
x := ax
|
||||
y := floatingFloor(ay)
|
||||
yMax := floatingCeil(by)
|
||||
if yMax > int32(z.size.Y) {
|
||||
yMax = int32(z.size.Y)
|
||||
}
|
||||
width := int32(z.size.X)
|
||||
|
||||
for ; y < yMax; y++ {
|
||||
dy := min(float32(y+1), by) - max(float32(y), ay)
|
||||
|
||||
// The "float32" in expressions like "float32(foo*bar)" here and below
|
||||
// look redundant, since foo and bar already have type float32, but are
|
||||
// explicit in order to disable the compiler's Fused Multiply Add (FMA)
|
||||
// instruction selection, which can improve performance but can result
|
||||
// in different rounding errors in floating point computations.
|
||||
//
|
||||
// This package aims to have bit-exact identical results across all
|
||||
// GOARCHes, and across pure Go code and assembly, so it disables FMA.
|
||||
//
|
||||
// See the discussion at
|
||||
// https://groups.google.com/d/topic/golang-dev/Sti0bl2xUXQ/discussion
|
||||
xNext := x + float32(dy*dxdy)
|
||||
if y < 0 {
|
||||
x = xNext
|
||||
continue
|
||||
}
|
||||
buf := z.bufF32[y*width:]
|
||||
d := float32(dy * dir)
|
||||
x0, x1 := x, xNext
|
||||
if x > xNext {
|
||||
x0, x1 = x1, x0
|
||||
}
|
||||
x0i := floatingFloor(x0)
|
||||
x0Floor := float32(x0i)
|
||||
x1i := floatingCeil(x1)
|
||||
x1Ceil := float32(x1i)
|
||||
|
||||
if x1i <= x0i+1 {
|
||||
xmf := float32(0.5*(x+xNext)) - x0Floor
|
||||
if i := clamp(x0i+0, width); i < uint(len(buf)) {
|
||||
buf[i] += d - float32(d*xmf)
|
||||
}
|
||||
if i := clamp(x0i+1, width); i < uint(len(buf)) {
|
||||
buf[i] += float32(d * xmf)
|
||||
}
|
||||
} else {
|
||||
s := 1 / (x1 - x0)
|
||||
x0f := x0 - x0Floor
|
||||
oneMinusX0f := 1 - x0f
|
||||
a0 := float32(0.5 * s * oneMinusX0f * oneMinusX0f)
|
||||
x1f := x1 - x1Ceil + 1
|
||||
am := float32(0.5 * s * x1f * x1f)
|
||||
|
||||
if i := clamp(x0i, width); i < uint(len(buf)) {
|
||||
buf[i] += float32(d * a0)
|
||||
}
|
||||
|
||||
if x1i == x0i+2 {
|
||||
if i := clamp(x0i+1, width); i < uint(len(buf)) {
|
||||
buf[i] += float32(d * (1 - a0 - am))
|
||||
}
|
||||
} else {
|
||||
a1 := float32(s * (1.5 - x0f))
|
||||
if i := clamp(x0i+1, width); i < uint(len(buf)) {
|
||||
buf[i] += float32(d * (a1 - a0))
|
||||
}
|
||||
dTimesS := float32(d * s)
|
||||
for xi := x0i + 2; xi < x1i-1; xi++ {
|
||||
if i := clamp(xi, width); i < uint(len(buf)) {
|
||||
buf[i] += dTimesS
|
||||
}
|
||||
}
|
||||
a2 := a1 + float32(s*float32(x1i-x0i-3))
|
||||
if i := clamp(x1i-1, width); i < uint(len(buf)) {
|
||||
buf[i] += float32(d * (1 - a2 - am))
|
||||
}
|
||||
}
|
||||
|
||||
if i := clamp(x1i, width); i < uint(len(buf)) {
|
||||
buf[i] += float32(d * am)
|
||||
}
|
||||
}
|
||||
|
||||
x = xNext
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// almost256 scales a floating point value in the range [0, 1] to a uint8
|
||||
// value in the range [0x00, 0xff].
|
||||
//
|
||||
// 255 is too small. Floating point math accumulates rounding errors, so a
|
||||
// fully covered src value that would in ideal math be float32(1) might be
|
||||
// float32(1-ε), and uint8(255 * (1-ε)) would be 0xfe instead of 0xff. The
|
||||
// uint8 conversion rounds to zero, not to nearest.
|
||||
//
|
||||
// 256 is too big. If we multiplied by 256, below, then a fully covered src
|
||||
// value of float32(1) would translate to uint8(256 * 1), which can be 0x00
|
||||
// instead of the maximal value 0xff.
|
||||
//
|
||||
// math.Float32bits(almost256) is 0x437fffff.
|
||||
almost256 = 255.99998
|
||||
|
||||
// almost65536 scales a floating point value in the range [0, 1] to a
|
||||
// uint16 value in the range [0x0000, 0xffff].
|
||||
//
|
||||
// math.Float32bits(almost65536) is 0x477fffff.
|
||||
almost65536 = almost256 * 256
|
||||
)
|
||||
|
||||
func floatingAccumulateOpOver(dst []uint8, src []float32) {
|
||||
// Sanity check that len(dst) >= len(src).
|
||||
if len(dst) < len(src) {
|
||||
return
|
||||
}
|
||||
|
||||
acc := float32(0)
|
||||
for i, v := range src {
|
||||
acc += v
|
||||
a := acc
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
if a > 1 {
|
||||
a = 1
|
||||
}
|
||||
// This algorithm comes from the standard library's image/draw package.
|
||||
dstA := uint32(dst[i]) * 0x101
|
||||
maskA := uint32(almost65536 * a)
|
||||
outA := dstA*(0xffff-maskA)/0xffff + maskA
|
||||
dst[i] = uint8(outA >> 8)
|
||||
}
|
||||
}
|
||||
|
||||
func floatingAccumulateOpSrc(dst []uint8, src []float32) {
|
||||
// Sanity check that len(dst) >= len(src).
|
||||
if len(dst) < len(src) {
|
||||
return
|
||||
}
|
||||
|
||||
acc := float32(0)
|
||||
for i, v := range src {
|
||||
acc += v
|
||||
a := acc
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
if a > 1 {
|
||||
a = 1
|
||||
}
|
||||
dst[i] = uint8(almost256 * a)
|
||||
}
|
||||
}
|
||||
|
||||
func floatingAccumulateMask(dst []uint32, src []float32) {
|
||||
// Sanity check that len(dst) >= len(src).
|
||||
if len(dst) < len(src) {
|
||||
return
|
||||
}
|
||||
|
||||
acc := float32(0)
|
||||
for i, v := range src {
|
||||
acc += v
|
||||
a := acc
|
||||
if a < 0 {
|
||||
a = -a
|
||||
}
|
||||
if a > 1 {
|
||||
a = 1
|
||||
}
|
||||
dst[i] = uint32(almost65536 * a)
|
||||
}
|
||||
}
|
||||
+472
@@ -0,0 +1,472 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go
|
||||
//go:generate asmfmt -w acc_amd64.s
|
||||
|
||||
// asmfmt is https://github.com/klauspost/asmfmt
|
||||
|
||||
// Package vector provides a rasterizer for 2-D vector graphics.
|
||||
package vector // import "golang.org/x/image/vector"
|
||||
|
||||
// The rasterizer's design follows
|
||||
// https://medium.com/@raphlinus/inside-the-fastest-font-renderer-in-the-world-75ae5270c445
|
||||
//
|
||||
// Proof of concept code is in
|
||||
// https://github.com/google/font-go
|
||||
//
|
||||
// See also:
|
||||
// http://nothings.org/gamedev/rasterize/
|
||||
// http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm
|
||||
// https://people.gnome.org/~mathieu/libart/internals.html#INTERNALS-SCANLINE
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"math"
|
||||
)
|
||||
|
||||
// floatingPointMathThreshold is the width or height above which the rasterizer
|
||||
// chooses to used floating point math instead of fixed point math.
|
||||
//
|
||||
// Both implementations of line segmentation rasterization (see raster_fixed.go
|
||||
// and raster_floating.go) implement the same algorithm (in ideal, infinite
|
||||
// precision math) but they perform differently in practice. The fixed point
|
||||
// math version is roughly 1.25x faster (on GOARCH=amd64) on the benchmarks,
|
||||
// but at sufficiently large scales, the computations will overflow and hence
|
||||
// show rendering artifacts. The floating point math version has more
|
||||
// consistent quality over larger scales, but it is significantly slower.
|
||||
//
|
||||
// This constant determines when to use the faster implementation and when to
|
||||
// use the better quality implementation.
|
||||
//
|
||||
// The rationale for this particular value is that TestRasterizePolygon in
|
||||
// vector_test.go checks the rendering quality of polygon edges at various
|
||||
// angles, inscribed in a circle of diameter 512. It may be that a higher value
|
||||
// would still produce acceptable quality, but 512 seems to work.
|
||||
const floatingPointMathThreshold = 512
|
||||
|
||||
func lerp(t, px, py, qx, qy float32) (x, y float32) {
|
||||
return px + t*(qx-px), py + t*(qy-py)
|
||||
}
|
||||
|
||||
func clamp(i, width int32) uint {
|
||||
if i < 0 {
|
||||
return 0
|
||||
}
|
||||
if i < width {
|
||||
return uint(i)
|
||||
}
|
||||
return uint(width)
|
||||
}
|
||||
|
||||
// NewRasterizer returns a new Rasterizer whose rendered mask image is bounded
|
||||
// by the given width and height.
|
||||
func NewRasterizer(w, h int) *Rasterizer {
|
||||
z := &Rasterizer{}
|
||||
z.Reset(w, h)
|
||||
return z
|
||||
}
|
||||
|
||||
// Raster is a 2-D vector graphics rasterizer.
|
||||
//
|
||||
// The zero value is usable, in that it is a Rasterizer whose rendered mask
|
||||
// image has zero width and zero height. Call Reset to change its bounds.
|
||||
type Rasterizer struct {
|
||||
// bufXxx are buffers of float32 or uint32 values, holding either the
|
||||
// individual or cumulative area values.
|
||||
//
|
||||
// We don't actually need both values at any given time, and to conserve
|
||||
// memory, the integration of the individual to the cumulative could modify
|
||||
// the buffer in place. In other words, we could use a single buffer, say
|
||||
// of type []uint32, and add some math.Float32bits and math.Float32frombits
|
||||
// calls to satisfy the compiler's type checking. As of Go 1.7, though,
|
||||
// there is a performance penalty between:
|
||||
// bufF32[i] += x
|
||||
// and
|
||||
// bufU32[i] = math.Float32bits(x + math.Float32frombits(bufU32[i]))
|
||||
//
|
||||
// See golang.org/issue/17220 for some discussion.
|
||||
bufF32 []float32
|
||||
bufU32 []uint32
|
||||
|
||||
useFloatingPointMath bool
|
||||
|
||||
size image.Point
|
||||
firstX float32
|
||||
firstY float32
|
||||
penX float32
|
||||
penY float32
|
||||
|
||||
// DrawOp is the operator used for the Draw method.
|
||||
//
|
||||
// The zero value is draw.Over.
|
||||
DrawOp draw.Op
|
||||
|
||||
// TODO: an exported field equivalent to the mask point in the
|
||||
// draw.DrawMask function in the stdlib image/draw package?
|
||||
}
|
||||
|
||||
// Reset resets a Rasterizer as if it was just returned by NewRasterizer.
|
||||
//
|
||||
// This includes setting z.DrawOp to draw.Over.
|
||||
func (z *Rasterizer) Reset(w, h int) {
|
||||
z.size = image.Point{w, h}
|
||||
z.firstX = 0
|
||||
z.firstY = 0
|
||||
z.penX = 0
|
||||
z.penY = 0
|
||||
z.DrawOp = draw.Over
|
||||
|
||||
z.setUseFloatingPointMath(w > floatingPointMathThreshold || h > floatingPointMathThreshold)
|
||||
}
|
||||
|
||||
func (z *Rasterizer) setUseFloatingPointMath(b bool) {
|
||||
z.useFloatingPointMath = b
|
||||
|
||||
// Make z.bufF32 or z.bufU32 large enough to hold width * height samples.
|
||||
if z.useFloatingPointMath {
|
||||
if n := z.size.X * z.size.Y; n > cap(z.bufF32) {
|
||||
z.bufF32 = make([]float32, n)
|
||||
} else {
|
||||
z.bufF32 = z.bufF32[:n]
|
||||
for i := range z.bufF32 {
|
||||
z.bufF32[i] = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if n := z.size.X * z.size.Y; n > cap(z.bufU32) {
|
||||
z.bufU32 = make([]uint32, n)
|
||||
} else {
|
||||
z.bufU32 = z.bufU32[:n]
|
||||
for i := range z.bufU32 {
|
||||
z.bufU32[i] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the width and height passed to NewRasterizer or Reset.
|
||||
func (z *Rasterizer) Size() image.Point {
|
||||
return z.size
|
||||
}
|
||||
|
||||
// Bounds returns the rectangle from (0, 0) to the width and height passed to
|
||||
// NewRasterizer or Reset.
|
||||
func (z *Rasterizer) Bounds() image.Rectangle {
|
||||
return image.Rectangle{Max: z.size}
|
||||
}
|
||||
|
||||
// Pen returns the location of the path-drawing pen: the last argument to the
|
||||
// most recent XxxTo call.
|
||||
func (z *Rasterizer) Pen() (x, y float32) {
|
||||
return z.penX, z.penY
|
||||
}
|
||||
|
||||
// ClosePath closes the current path.
|
||||
func (z *Rasterizer) ClosePath() {
|
||||
z.LineTo(z.firstX, z.firstY)
|
||||
}
|
||||
|
||||
// MoveTo starts a new path and moves the pen to (ax, ay).
|
||||
//
|
||||
// The coordinates are allowed to be out of the Rasterizer's bounds.
|
||||
func (z *Rasterizer) MoveTo(ax, ay float32) {
|
||||
z.firstX = ax
|
||||
z.firstY = ay
|
||||
z.penX = ax
|
||||
z.penY = ay
|
||||
}
|
||||
|
||||
// LineTo adds a line segment, from the pen to (bx, by), and moves the pen to
|
||||
// (bx, by).
|
||||
//
|
||||
// The coordinates are allowed to be out of the Rasterizer's bounds.
|
||||
func (z *Rasterizer) LineTo(bx, by float32) {
|
||||
if z.useFloatingPointMath {
|
||||
z.floatingLineTo(bx, by)
|
||||
} else {
|
||||
z.fixedLineTo(bx, by)
|
||||
}
|
||||
}
|
||||
|
||||
// QuadTo adds a quadratic Bézier segment, from the pen via (bx, by) to (cx,
|
||||
// cy), and moves the pen to (cx, cy).
|
||||
//
|
||||
// The coordinates are allowed to be out of the Rasterizer's bounds.
|
||||
func (z *Rasterizer) QuadTo(bx, by, cx, cy float32) {
|
||||
ax, ay := z.penX, z.penY
|
||||
devsq := devSquared(ax, ay, bx, by, cx, cy)
|
||||
if devsq >= 0.333 {
|
||||
const tol = 3
|
||||
n := 1 + int(math.Sqrt(math.Sqrt(tol*float64(devsq))))
|
||||
t, nInv := float32(0), 1/float32(n)
|
||||
for i := 0; i < n-1; i++ {
|
||||
t += nInv
|
||||
abx, aby := lerp(t, ax, ay, bx, by)
|
||||
bcx, bcy := lerp(t, bx, by, cx, cy)
|
||||
z.LineTo(lerp(t, abx, aby, bcx, bcy))
|
||||
}
|
||||
}
|
||||
z.LineTo(cx, cy)
|
||||
}
|
||||
|
||||
// CubeTo adds a cubic Bézier segment, from the pen via (bx, by) and (cx, cy)
|
||||
// to (dx, dy), and moves the pen to (dx, dy).
|
||||
//
|
||||
// The coordinates are allowed to be out of the Rasterizer's bounds.
|
||||
func (z *Rasterizer) CubeTo(bx, by, cx, cy, dx, dy float32) {
|
||||
ax, ay := z.penX, z.penY
|
||||
devsq := devSquared(ax, ay, bx, by, dx, dy)
|
||||
if devsqAlt := devSquared(ax, ay, cx, cy, dx, dy); devsq < devsqAlt {
|
||||
devsq = devsqAlt
|
||||
}
|
||||
if devsq >= 0.333 {
|
||||
const tol = 3
|
||||
n := 1 + int(math.Sqrt(math.Sqrt(tol*float64(devsq))))
|
||||
t, nInv := float32(0), 1/float32(n)
|
||||
for i := 0; i < n-1; i++ {
|
||||
t += nInv
|
||||
abx, aby := lerp(t, ax, ay, bx, by)
|
||||
bcx, bcy := lerp(t, bx, by, cx, cy)
|
||||
cdx, cdy := lerp(t, cx, cy, dx, dy)
|
||||
abcx, abcy := lerp(t, abx, aby, bcx, bcy)
|
||||
bcdx, bcdy := lerp(t, bcx, bcy, cdx, cdy)
|
||||
z.LineTo(lerp(t, abcx, abcy, bcdx, bcdy))
|
||||
}
|
||||
}
|
||||
z.LineTo(dx, dy)
|
||||
}
|
||||
|
||||
// devSquared returns a measure of how curvy the sequence (ax, ay) to (bx, by)
|
||||
// to (cx, cy) is. It determines how many line segments will approximate a
|
||||
// Bézier curve segment.
|
||||
//
|
||||
// http://lists.nongnu.org/archive/html/freetype-devel/2016-08/msg00080.html
|
||||
// gives the rationale for this evenly spaced heuristic instead of a recursive
|
||||
// de Casteljau approach:
|
||||
//
|
||||
// The reason for the subdivision by n is that I expect the "flatness"
|
||||
// computation to be semi-expensive (it's done once rather than on each
|
||||
// potential subdivision) and also because you'll often get fewer subdivisions.
|
||||
// Taking a circular arc as a simplifying assumption (i.e., a spherical cow),
|
||||
// where I get n, a recursive approach would get 2^⌈lg n⌉, which, if I haven't
|
||||
// made any horrible mistakes, is expected to be 33% more in the limit.
|
||||
func devSquared(ax, ay, bx, by, cx, cy float32) float32 {
|
||||
devx := ax - 2*bx + cx
|
||||
devy := ay - 2*by + cy
|
||||
return devx*devx + devy*devy
|
||||
}
|
||||
|
||||
// Draw implements the Drawer interface from the standard library's image/draw
|
||||
// package.
|
||||
//
|
||||
// The vector paths previously added via the XxxTo calls become the mask for
|
||||
// drawing src onto dst.
|
||||
func (z *Rasterizer) Draw(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||
// TODO: adjust r and sp (and mp?) if src.Bounds() doesn't contain
|
||||
// r.Add(sp.Sub(r.Min)).
|
||||
|
||||
if src, ok := src.(*image.Uniform); ok {
|
||||
srcR, srcG, srcB, srcA := src.RGBA()
|
||||
switch dst := dst.(type) {
|
||||
case *image.Alpha:
|
||||
// Fast path for glyph rendering.
|
||||
if srcA == 0xffff {
|
||||
if z.DrawOp == draw.Over {
|
||||
z.rasterizeDstAlphaSrcOpaqueOpOver(dst, r)
|
||||
} else {
|
||||
z.rasterizeDstAlphaSrcOpaqueOpSrc(dst, r)
|
||||
}
|
||||
return
|
||||
}
|
||||
case *image.RGBA:
|
||||
if z.DrawOp == draw.Over {
|
||||
z.rasterizeDstRGBASrcUniformOpOver(dst, r, srcR, srcG, srcB, srcA)
|
||||
} else {
|
||||
z.rasterizeDstRGBASrcUniformOpSrc(dst, r, srcR, srcG, srcB, srcA)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if z.DrawOp == draw.Over {
|
||||
z.rasterizeOpOver(dst, r, src, sp)
|
||||
} else {
|
||||
z.rasterizeOpSrc(dst, r, src, sp)
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Rasterizer) accumulateMask() {
|
||||
if z.useFloatingPointMath {
|
||||
if n := z.size.X * z.size.Y; n > cap(z.bufU32) {
|
||||
z.bufU32 = make([]uint32, n)
|
||||
} else {
|
||||
z.bufU32 = z.bufU32[:n]
|
||||
}
|
||||
if haveAccumulateSIMD {
|
||||
floatingAccumulateMaskSIMD(z.bufU32, z.bufF32)
|
||||
} else {
|
||||
floatingAccumulateMask(z.bufU32, z.bufF32)
|
||||
}
|
||||
} else {
|
||||
if haveAccumulateSIMD {
|
||||
fixedAccumulateMaskSIMD(z.bufU32)
|
||||
} else {
|
||||
fixedAccumulateMask(z.bufU32)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpOver(dst *image.Alpha, r image.Rectangle) {
|
||||
// TODO: non-zero vs even-odd winding?
|
||||
if r == dst.Bounds() && r == z.Bounds() {
|
||||
// We bypass the z.accumulateMask step and convert straight from
|
||||
// z.bufF32 or z.bufU32 to dst.Pix.
|
||||
if z.useFloatingPointMath {
|
||||
if haveAccumulateSIMD {
|
||||
floatingAccumulateOpOverSIMD(dst.Pix, z.bufF32)
|
||||
} else {
|
||||
floatingAccumulateOpOver(dst.Pix, z.bufF32)
|
||||
}
|
||||
} else {
|
||||
if haveAccumulateSIMD {
|
||||
fixedAccumulateOpOverSIMD(dst.Pix, z.bufU32)
|
||||
} else {
|
||||
fixedAccumulateOpOver(dst.Pix, z.bufU32)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
z.accumulateMask()
|
||||
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
|
||||
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
|
||||
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
|
||||
ma := z.bufU32[y*z.size.X+x]
|
||||
i := y*dst.Stride + x
|
||||
|
||||
// This formula is like rasterizeOpOver's, simplified for the
|
||||
// concrete dst type and opaque src assumption.
|
||||
a := 0xffff - ma
|
||||
pix[i] = uint8((uint32(pix[i])*0x101*a/0xffff + ma) >> 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Rasterizer) rasterizeDstAlphaSrcOpaqueOpSrc(dst *image.Alpha, r image.Rectangle) {
|
||||
// TODO: non-zero vs even-odd winding?
|
||||
if r == dst.Bounds() && r == z.Bounds() {
|
||||
// We bypass the z.accumulateMask step and convert straight from
|
||||
// z.bufF32 or z.bufU32 to dst.Pix.
|
||||
if z.useFloatingPointMath {
|
||||
if haveAccumulateSIMD {
|
||||
floatingAccumulateOpSrcSIMD(dst.Pix, z.bufF32)
|
||||
} else {
|
||||
floatingAccumulateOpSrc(dst.Pix, z.bufF32)
|
||||
}
|
||||
} else {
|
||||
if haveAccumulateSIMD {
|
||||
fixedAccumulateOpSrcSIMD(dst.Pix, z.bufU32)
|
||||
} else {
|
||||
fixedAccumulateOpSrc(dst.Pix, z.bufU32)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
z.accumulateMask()
|
||||
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
|
||||
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
|
||||
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
|
||||
ma := z.bufU32[y*z.size.X+x]
|
||||
|
||||
// This formula is like rasterizeOpSrc's, simplified for the
|
||||
// concrete dst type and opaque src assumption.
|
||||
pix[y*dst.Stride+x] = uint8(ma >> 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Rasterizer) rasterizeDstRGBASrcUniformOpOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
|
||||
z.accumulateMask()
|
||||
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
|
||||
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
|
||||
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
|
||||
ma := z.bufU32[y*z.size.X+x]
|
||||
|
||||
// This formula is like rasterizeOpOver's, simplified for the
|
||||
// concrete dst type and uniform src assumption.
|
||||
a := 0xffff - (sa * ma / 0xffff)
|
||||
i := y*dst.Stride + 4*x
|
||||
pix[i+0] = uint8(((uint32(pix[i+0])*0x101*a + sr*ma) / 0xffff) >> 8)
|
||||
pix[i+1] = uint8(((uint32(pix[i+1])*0x101*a + sg*ma) / 0xffff) >> 8)
|
||||
pix[i+2] = uint8(((uint32(pix[i+2])*0x101*a + sb*ma) / 0xffff) >> 8)
|
||||
pix[i+3] = uint8(((uint32(pix[i+3])*0x101*a + sa*ma) / 0xffff) >> 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Rasterizer) rasterizeDstRGBASrcUniformOpSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
|
||||
z.accumulateMask()
|
||||
pix := dst.Pix[dst.PixOffset(r.Min.X, r.Min.Y):]
|
||||
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
|
||||
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
|
||||
ma := z.bufU32[y*z.size.X+x]
|
||||
|
||||
// This formula is like rasterizeOpSrc's, simplified for the
|
||||
// concrete dst type and uniform src assumption.
|
||||
i := y*dst.Stride + 4*x
|
||||
pix[i+0] = uint8((sr * ma / 0xffff) >> 8)
|
||||
pix[i+1] = uint8((sg * ma / 0xffff) >> 8)
|
||||
pix[i+2] = uint8((sb * ma / 0xffff) >> 8)
|
||||
pix[i+3] = uint8((sa * ma / 0xffff) >> 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Rasterizer) rasterizeOpOver(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||
z.accumulateMask()
|
||||
out := color.RGBA64{}
|
||||
outc := color.Color(&out)
|
||||
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
|
||||
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
|
||||
sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
|
||||
ma := z.bufU32[y*z.size.X+x]
|
||||
|
||||
// This algorithm comes from the standard library's image/draw
|
||||
// package.
|
||||
dr, dg, db, da := dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
|
||||
a := 0xffff - (sa * ma / 0xffff)
|
||||
out.R = uint16((dr*a + sr*ma) / 0xffff)
|
||||
out.G = uint16((dg*a + sg*ma) / 0xffff)
|
||||
out.B = uint16((db*a + sb*ma) / 0xffff)
|
||||
out.A = uint16((da*a + sa*ma) / 0xffff)
|
||||
|
||||
dst.Set(r.Min.X+x, r.Min.Y+y, outc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Rasterizer) rasterizeOpSrc(dst draw.Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||
z.accumulateMask()
|
||||
out := color.RGBA64{}
|
||||
outc := color.Color(&out)
|
||||
for y, y1 := 0, r.Max.Y-r.Min.Y; y < y1; y++ {
|
||||
for x, x1 := 0, r.Max.X-r.Min.X; x < x1; x++ {
|
||||
sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
|
||||
ma := z.bufU32[y*z.size.X+x]
|
||||
|
||||
// This algorithm comes from the standard library's image/draw
|
||||
// package.
|
||||
out.R = uint16(sr * ma / 0xffff)
|
||||
out.G = uint16(sg * ma / 0xffff)
|
||||
out.B = uint16(sb * ma / 0xffff)
|
||||
out.A = uint16(sa * ma / 0xffff)
|
||||
|
||||
dst.Set(r.Min.X+x, r.Min.Y+y, outc)
|
||||
}
|
||||
}
|
||||
}
|
||||
+403
@@ -0,0 +1,403 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package vp8 implements a decoder for the VP8 lossy image format.
|
||||
//
|
||||
// The VP8 specification is RFC 6386.
|
||||
package vp8 // import "golang.org/x/image/vp8"
|
||||
|
||||
// This file implements the top-level decoding algorithm.
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"io"
|
||||
)
|
||||
|
||||
// limitReader wraps an io.Reader to read at most n bytes from it.
|
||||
type limitReader struct {
|
||||
r io.Reader
|
||||
n int
|
||||
}
|
||||
|
||||
// ReadFull reads exactly len(p) bytes into p.
|
||||
func (r *limitReader) ReadFull(p []byte) error {
|
||||
if len(p) > r.n {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
n, err := io.ReadFull(r.r, p)
|
||||
r.n -= n
|
||||
return err
|
||||
}
|
||||
|
||||
// FrameHeader is a frame header, as specified in section 9.1.
|
||||
type FrameHeader struct {
|
||||
KeyFrame bool
|
||||
VersionNumber uint8
|
||||
ShowFrame bool
|
||||
FirstPartitionLen uint32
|
||||
Width int
|
||||
Height int
|
||||
XScale uint8
|
||||
YScale uint8
|
||||
}
|
||||
|
||||
const (
|
||||
nSegment = 4
|
||||
nSegmentProb = 3
|
||||
)
|
||||
|
||||
// segmentHeader holds segment-related header information.
|
||||
type segmentHeader struct {
|
||||
useSegment bool
|
||||
updateMap bool
|
||||
relativeDelta bool
|
||||
quantizer [nSegment]int8
|
||||
filterStrength [nSegment]int8
|
||||
prob [nSegmentProb]uint8
|
||||
}
|
||||
|
||||
const (
|
||||
nRefLFDelta = 4
|
||||
nModeLFDelta = 4
|
||||
)
|
||||
|
||||
// filterHeader holds filter-related header information.
|
||||
type filterHeader struct {
|
||||
simple bool
|
||||
level int8
|
||||
sharpness uint8
|
||||
useLFDelta bool
|
||||
refLFDelta [nRefLFDelta]int8
|
||||
modeLFDelta [nModeLFDelta]int8
|
||||
perSegmentLevel [nSegment]int8
|
||||
}
|
||||
|
||||
// mb is the per-macroblock decode state. A decoder maintains mbw+1 of these
|
||||
// as it is decoding macroblocks left-to-right and top-to-bottom: mbw for the
|
||||
// macroblocks in the row above, and one for the macroblock to the left.
|
||||
type mb struct {
|
||||
// pred is the predictor mode for the 4 bottom or right 4x4 luma regions.
|
||||
pred [4]uint8
|
||||
// nzMask is a mask of 8 bits: 4 for the bottom or right 4x4 luma regions,
|
||||
// and 2 + 2 for the bottom or right 4x4 chroma regions. A 1 bit indicates
|
||||
// that region has non-zero coefficients.
|
||||
nzMask uint8
|
||||
// nzY16 is a 0/1 value that is 1 if the macroblock used Y16 prediction and
|
||||
// had non-zero coefficients.
|
||||
nzY16 uint8
|
||||
}
|
||||
|
||||
// Decoder decodes VP8 bitstreams into frames. Decoding one frame consists of
|
||||
// calling Init, DecodeFrameHeader and then DecodeFrame in that order.
|
||||
// A Decoder can be re-used to decode multiple frames.
|
||||
type Decoder struct {
|
||||
// r is the input bitsream.
|
||||
r limitReader
|
||||
// scratch is a scratch buffer.
|
||||
scratch [8]byte
|
||||
// img is the YCbCr image to decode into.
|
||||
img *image.YCbCr
|
||||
// mbw and mbh are the number of 16x16 macroblocks wide and high the image is.
|
||||
mbw, mbh int
|
||||
// frameHeader is the frame header. When decoding multiple frames,
|
||||
// frames that aren't key frames will inherit the Width, Height,
|
||||
// XScale and YScale of the most recent key frame.
|
||||
frameHeader FrameHeader
|
||||
// Other headers.
|
||||
segmentHeader segmentHeader
|
||||
filterHeader filterHeader
|
||||
// The image data is divided into a number of independent partitions.
|
||||
// There is 1 "first partition" and between 1 and 8 "other partitions"
|
||||
// for coefficient data.
|
||||
fp partition
|
||||
op [8]partition
|
||||
nOP int
|
||||
// Quantization factors.
|
||||
quant [nSegment]quant
|
||||
// DCT/WHT coefficient decoding probabilities.
|
||||
tokenProb [nPlane][nBand][nContext][nProb]uint8
|
||||
useSkipProb bool
|
||||
skipProb uint8
|
||||
// Loop filter parameters.
|
||||
filterParams [nSegment][2]filterParam
|
||||
perMBFilterParams []filterParam
|
||||
|
||||
// The eight fields below relate to the current macroblock being decoded.
|
||||
//
|
||||
// Segment-based adjustments.
|
||||
segment int
|
||||
// Per-macroblock state for the macroblock immediately left of and those
|
||||
// macroblocks immediately above the current macroblock.
|
||||
leftMB mb
|
||||
upMB []mb
|
||||
// Bitmasks for which 4x4 regions of coeff contain non-zero coefficients.
|
||||
nzDCMask, nzACMask uint32
|
||||
// Predictor modes.
|
||||
usePredY16 bool // The libwebp C code calls this !is_i4x4_.
|
||||
predY16 uint8
|
||||
predC8 uint8
|
||||
predY4 [4][4]uint8
|
||||
|
||||
// The two fields below form a workspace for reconstructing a macroblock.
|
||||
// Their specific sizes are documented in reconstruct.go.
|
||||
coeff [1*16*16 + 2*8*8 + 1*4*4]int16
|
||||
ybr [1 + 16 + 1 + 8][32]uint8
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder.
|
||||
func NewDecoder() *Decoder {
|
||||
return &Decoder{}
|
||||
}
|
||||
|
||||
// Init initializes the decoder to read at most n bytes from r.
|
||||
func (d *Decoder) Init(r io.Reader, n int) {
|
||||
d.r = limitReader{r, n}
|
||||
}
|
||||
|
||||
// DecodeFrameHeader decodes the frame header.
|
||||
func (d *Decoder) DecodeFrameHeader() (fh FrameHeader, err error) {
|
||||
// All frame headers are at least 3 bytes long.
|
||||
b := d.scratch[:3]
|
||||
if err = d.r.ReadFull(b); err != nil {
|
||||
return
|
||||
}
|
||||
d.frameHeader.KeyFrame = (b[0] & 1) == 0
|
||||
d.frameHeader.VersionNumber = (b[0] >> 1) & 7
|
||||
d.frameHeader.ShowFrame = (b[0]>>4)&1 == 1
|
||||
d.frameHeader.FirstPartitionLen = uint32(b[0])>>5 | uint32(b[1])<<3 | uint32(b[2])<<11
|
||||
if !d.frameHeader.KeyFrame {
|
||||
return d.frameHeader, nil
|
||||
}
|
||||
// Frame headers for key frames are an additional 7 bytes long.
|
||||
b = d.scratch[:7]
|
||||
if err = d.r.ReadFull(b); err != nil {
|
||||
return
|
||||
}
|
||||
// Check the magic sync code.
|
||||
if b[0] != 0x9d || b[1] != 0x01 || b[2] != 0x2a {
|
||||
err = errors.New("vp8: invalid format")
|
||||
return
|
||||
}
|
||||
d.frameHeader.Width = int(b[4]&0x3f)<<8 | int(b[3])
|
||||
d.frameHeader.Height = int(b[6]&0x3f)<<8 | int(b[5])
|
||||
d.frameHeader.XScale = b[4] >> 6
|
||||
d.frameHeader.YScale = b[6] >> 6
|
||||
d.mbw = (d.frameHeader.Width + 0x0f) >> 4
|
||||
d.mbh = (d.frameHeader.Height + 0x0f) >> 4
|
||||
d.segmentHeader = segmentHeader{
|
||||
prob: [3]uint8{0xff, 0xff, 0xff},
|
||||
}
|
||||
d.tokenProb = defaultTokenProb
|
||||
d.segment = 0
|
||||
return d.frameHeader, nil
|
||||
}
|
||||
|
||||
// ensureImg ensures that d.img is large enough to hold the decoded frame.
|
||||
func (d *Decoder) ensureImg() {
|
||||
if d.img != nil {
|
||||
p0, p1 := d.img.Rect.Min, d.img.Rect.Max
|
||||
if p0.X == 0 && p0.Y == 0 && p1.X >= 16*d.mbw && p1.Y >= 16*d.mbh {
|
||||
return
|
||||
}
|
||||
}
|
||||
m := image.NewYCbCr(image.Rect(0, 0, 16*d.mbw, 16*d.mbh), image.YCbCrSubsampleRatio420)
|
||||
d.img = m.SubImage(image.Rect(0, 0, d.frameHeader.Width, d.frameHeader.Height)).(*image.YCbCr)
|
||||
d.perMBFilterParams = make([]filterParam, d.mbw*d.mbh)
|
||||
d.upMB = make([]mb, d.mbw)
|
||||
}
|
||||
|
||||
// parseSegmentHeader parses the segment header, as specified in section 9.3.
|
||||
func (d *Decoder) parseSegmentHeader() {
|
||||
d.segmentHeader.useSegment = d.fp.readBit(uniformProb)
|
||||
if !d.segmentHeader.useSegment {
|
||||
d.segmentHeader.updateMap = false
|
||||
return
|
||||
}
|
||||
d.segmentHeader.updateMap = d.fp.readBit(uniformProb)
|
||||
if d.fp.readBit(uniformProb) {
|
||||
d.segmentHeader.relativeDelta = !d.fp.readBit(uniformProb)
|
||||
for i := range d.segmentHeader.quantizer {
|
||||
d.segmentHeader.quantizer[i] = int8(d.fp.readOptionalInt(uniformProb, 7))
|
||||
}
|
||||
for i := range d.segmentHeader.filterStrength {
|
||||
d.segmentHeader.filterStrength[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
|
||||
}
|
||||
}
|
||||
if !d.segmentHeader.updateMap {
|
||||
return
|
||||
}
|
||||
for i := range d.segmentHeader.prob {
|
||||
if d.fp.readBit(uniformProb) {
|
||||
d.segmentHeader.prob[i] = uint8(d.fp.readUint(uniformProb, 8))
|
||||
} else {
|
||||
d.segmentHeader.prob[i] = 0xff
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parseFilterHeader parses the filter header, as specified in section 9.4.
|
||||
func (d *Decoder) parseFilterHeader() {
|
||||
d.filterHeader.simple = d.fp.readBit(uniformProb)
|
||||
d.filterHeader.level = int8(d.fp.readUint(uniformProb, 6))
|
||||
d.filterHeader.sharpness = uint8(d.fp.readUint(uniformProb, 3))
|
||||
d.filterHeader.useLFDelta = d.fp.readBit(uniformProb)
|
||||
if d.filterHeader.useLFDelta && d.fp.readBit(uniformProb) {
|
||||
for i := range d.filterHeader.refLFDelta {
|
||||
d.filterHeader.refLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
|
||||
}
|
||||
for i := range d.filterHeader.modeLFDelta {
|
||||
d.filterHeader.modeLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
|
||||
}
|
||||
}
|
||||
if d.filterHeader.level == 0 {
|
||||
return
|
||||
}
|
||||
if d.segmentHeader.useSegment {
|
||||
for i := range d.filterHeader.perSegmentLevel {
|
||||
strength := d.segmentHeader.filterStrength[i]
|
||||
if d.segmentHeader.relativeDelta {
|
||||
strength += d.filterHeader.level
|
||||
}
|
||||
d.filterHeader.perSegmentLevel[i] = strength
|
||||
}
|
||||
} else {
|
||||
d.filterHeader.perSegmentLevel[0] = d.filterHeader.level
|
||||
}
|
||||
d.computeFilterParams()
|
||||
}
|
||||
|
||||
// parseOtherPartitions parses the other partitions, as specified in section 9.5.
|
||||
func (d *Decoder) parseOtherPartitions() error {
|
||||
const maxNOP = 1 << 3
|
||||
var partLens [maxNOP]int
|
||||
d.nOP = 1 << d.fp.readUint(uniformProb, 2)
|
||||
|
||||
// The final partition length is implied by the remaining chunk data
|
||||
// (d.r.n) and the other d.nOP-1 partition lengths. Those d.nOP-1 partition
|
||||
// lengths are stored as 24-bit uints, i.e. up to 16 MiB per partition.
|
||||
n := 3 * (d.nOP - 1)
|
||||
partLens[d.nOP-1] = d.r.n - n
|
||||
if partLens[d.nOP-1] < 0 {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if n > 0 {
|
||||
buf := make([]byte, n)
|
||||
if err := d.r.ReadFull(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := 0; i < d.nOP-1; i++ {
|
||||
pl := int(buf[3*i+0]) | int(buf[3*i+1])<<8 | int(buf[3*i+2])<<16
|
||||
if pl > partLens[d.nOP-1] {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
partLens[i] = pl
|
||||
partLens[d.nOP-1] -= pl
|
||||
}
|
||||
}
|
||||
|
||||
// We check if the final partition length can also fit into a 24-bit uint.
|
||||
// Strictly speaking, this isn't part of the spec, but it guards against a
|
||||
// malicious WEBP image that is too large to ReadFull the encoded DCT
|
||||
// coefficients into memory, whether that's because the actual WEBP file is
|
||||
// too large, or whether its RIFF metadata lists too large a chunk.
|
||||
if 1<<24 <= partLens[d.nOP-1] {
|
||||
return errors.New("vp8: too much data to decode")
|
||||
}
|
||||
|
||||
buf := make([]byte, d.r.n)
|
||||
if err := d.r.ReadFull(buf); err != nil {
|
||||
return err
|
||||
}
|
||||
for i, pl := range partLens {
|
||||
if i == d.nOP {
|
||||
break
|
||||
}
|
||||
d.op[i].init(buf[:pl])
|
||||
buf = buf[pl:]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseOtherHeaders parses header information other than the frame header.
|
||||
func (d *Decoder) parseOtherHeaders() error {
|
||||
// Initialize and parse the first partition.
|
||||
firstPartition := make([]byte, d.frameHeader.FirstPartitionLen)
|
||||
if err := d.r.ReadFull(firstPartition); err != nil {
|
||||
return err
|
||||
}
|
||||
d.fp.init(firstPartition)
|
||||
if d.frameHeader.KeyFrame {
|
||||
// Read and ignore the color space and pixel clamp values. They are
|
||||
// specified in section 9.2, but are unimplemented.
|
||||
d.fp.readBit(uniformProb)
|
||||
d.fp.readBit(uniformProb)
|
||||
}
|
||||
d.parseSegmentHeader()
|
||||
d.parseFilterHeader()
|
||||
if err := d.parseOtherPartitions(); err != nil {
|
||||
return err
|
||||
}
|
||||
d.parseQuant()
|
||||
if !d.frameHeader.KeyFrame {
|
||||
// Golden and AltRef frames are specified in section 9.7.
|
||||
// TODO(nigeltao): implement. Note that they are only used for video, not still images.
|
||||
return errors.New("vp8: Golden / AltRef frames are not implemented")
|
||||
}
|
||||
// Read and ignore the refreshLastFrameBuffer bit, specified in section 9.8.
|
||||
// It applies only to video, and not still images.
|
||||
d.fp.readBit(uniformProb)
|
||||
d.parseTokenProb()
|
||||
d.useSkipProb = d.fp.readBit(uniformProb)
|
||||
if d.useSkipProb {
|
||||
d.skipProb = uint8(d.fp.readUint(uniformProb, 8))
|
||||
}
|
||||
if d.fp.unexpectedEOF {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeFrame decodes the frame and returns it as an YCbCr image.
|
||||
// The image's contents are valid up until the next call to Decoder.Init.
|
||||
func (d *Decoder) DecodeFrame() (*image.YCbCr, error) {
|
||||
d.ensureImg()
|
||||
if err := d.parseOtherHeaders(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Reconstruct the rows.
|
||||
for mbx := 0; mbx < d.mbw; mbx++ {
|
||||
d.upMB[mbx] = mb{}
|
||||
}
|
||||
for mby := 0; mby < d.mbh; mby++ {
|
||||
d.leftMB = mb{}
|
||||
for mbx := 0; mbx < d.mbw; mbx++ {
|
||||
skip := d.reconstruct(mbx, mby)
|
||||
fs := d.filterParams[d.segment][btou(!d.usePredY16)]
|
||||
fs.inner = fs.inner || !skip
|
||||
d.perMBFilterParams[d.mbw*mby+mbx] = fs
|
||||
}
|
||||
}
|
||||
if d.fp.unexpectedEOF {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
for i := 0; i < d.nOP; i++ {
|
||||
if d.op[i].unexpectedEOF {
|
||||
return nil, io.ErrUnexpectedEOF
|
||||
}
|
||||
}
|
||||
// Apply the loop filter.
|
||||
//
|
||||
// Even if we are using per-segment levels, section 15 says that "loop
|
||||
// filtering must be skipped entirely if loop_filter_level at either the
|
||||
// frame header level or macroblock override level is 0".
|
||||
if d.filterHeader.level != 0 {
|
||||
if d.filterHeader.simple {
|
||||
d.simpleFilter()
|
||||
} else {
|
||||
d.normalFilter()
|
||||
}
|
||||
}
|
||||
return d.img, nil
|
||||
}
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8
|
||||
|
||||
// filter2 modifies a 2-pixel wide or 2-pixel high band along an edge.
|
||||
func filter2(pix []byte, level, index, iStep, jStep int) {
|
||||
for n := 16; n > 0; n, index = n-1, index+iStep {
|
||||
p1 := int(pix[index-2*jStep])
|
||||
p0 := int(pix[index-1*jStep])
|
||||
q0 := int(pix[index+0*jStep])
|
||||
q1 := int(pix[index+1*jStep])
|
||||
if abs(p0-q0)<<1+abs(p1-q1)>>1 > level {
|
||||
continue
|
||||
}
|
||||
a := 3*(q0-p0) + clamp127(p1-q1)
|
||||
a1 := clamp15((a + 4) >> 3)
|
||||
a2 := clamp15((a + 3) >> 3)
|
||||
pix[index-1*jStep] = clamp255(p0 + a2)
|
||||
pix[index+0*jStep] = clamp255(q0 - a1)
|
||||
}
|
||||
}
|
||||
|
||||
// filter246 modifies a 2-, 4- or 6-pixel wide or high band along an edge.
|
||||
func filter246(pix []byte, n, level, ilevel, hlevel, index, iStep, jStep int, fourNotSix bool) {
|
||||
for ; n > 0; n, index = n-1, index+iStep {
|
||||
p3 := int(pix[index-4*jStep])
|
||||
p2 := int(pix[index-3*jStep])
|
||||
p1 := int(pix[index-2*jStep])
|
||||
p0 := int(pix[index-1*jStep])
|
||||
q0 := int(pix[index+0*jStep])
|
||||
q1 := int(pix[index+1*jStep])
|
||||
q2 := int(pix[index+2*jStep])
|
||||
q3 := int(pix[index+3*jStep])
|
||||
if abs(p0-q0)<<1+abs(p1-q1)>>1 > level {
|
||||
continue
|
||||
}
|
||||
if abs(p3-p2) > ilevel ||
|
||||
abs(p2-p1) > ilevel ||
|
||||
abs(p1-p0) > ilevel ||
|
||||
abs(q1-q0) > ilevel ||
|
||||
abs(q2-q1) > ilevel ||
|
||||
abs(q3-q2) > ilevel {
|
||||
continue
|
||||
}
|
||||
if abs(p1-p0) > hlevel || abs(q1-q0) > hlevel {
|
||||
// Filter 2 pixels.
|
||||
a := 3*(q0-p0) + clamp127(p1-q1)
|
||||
a1 := clamp15((a + 4) >> 3)
|
||||
a2 := clamp15((a + 3) >> 3)
|
||||
pix[index-1*jStep] = clamp255(p0 + a2)
|
||||
pix[index+0*jStep] = clamp255(q0 - a1)
|
||||
} else if fourNotSix {
|
||||
// Filter 4 pixels.
|
||||
a := 3 * (q0 - p0)
|
||||
a1 := clamp15((a + 4) >> 3)
|
||||
a2 := clamp15((a + 3) >> 3)
|
||||
a3 := (a1 + 1) >> 1
|
||||
pix[index-2*jStep] = clamp255(p1 + a3)
|
||||
pix[index-1*jStep] = clamp255(p0 + a2)
|
||||
pix[index+0*jStep] = clamp255(q0 - a1)
|
||||
pix[index+1*jStep] = clamp255(q1 - a3)
|
||||
} else {
|
||||
// Filter 6 pixels.
|
||||
a := clamp127(3*(q0-p0) + clamp127(p1-q1))
|
||||
a1 := (27*a + 63) >> 7
|
||||
a2 := (18*a + 63) >> 7
|
||||
a3 := (9*a + 63) >> 7
|
||||
pix[index-3*jStep] = clamp255(p2 + a3)
|
||||
pix[index-2*jStep] = clamp255(p1 + a2)
|
||||
pix[index-1*jStep] = clamp255(p0 + a1)
|
||||
pix[index+0*jStep] = clamp255(q0 - a1)
|
||||
pix[index+1*jStep] = clamp255(q1 - a2)
|
||||
pix[index+2*jStep] = clamp255(q2 - a3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simpleFilter implements the simple filter, as specified in section 15.2.
|
||||
func (d *Decoder) simpleFilter() {
|
||||
for mby := 0; mby < d.mbh; mby++ {
|
||||
for mbx := 0; mbx < d.mbw; mbx++ {
|
||||
f := d.perMBFilterParams[d.mbw*mby+mbx]
|
||||
if f.level == 0 {
|
||||
continue
|
||||
}
|
||||
l := int(f.level)
|
||||
yIndex := (mby*d.img.YStride + mbx) * 16
|
||||
if mbx > 0 {
|
||||
filter2(d.img.Y, l+4, yIndex, d.img.YStride, 1)
|
||||
}
|
||||
if f.inner {
|
||||
filter2(d.img.Y, l, yIndex+0x4, d.img.YStride, 1)
|
||||
filter2(d.img.Y, l, yIndex+0x8, d.img.YStride, 1)
|
||||
filter2(d.img.Y, l, yIndex+0xc, d.img.YStride, 1)
|
||||
}
|
||||
if mby > 0 {
|
||||
filter2(d.img.Y, l+4, yIndex, 1, d.img.YStride)
|
||||
}
|
||||
if f.inner {
|
||||
filter2(d.img.Y, l, yIndex+d.img.YStride*0x4, 1, d.img.YStride)
|
||||
filter2(d.img.Y, l, yIndex+d.img.YStride*0x8, 1, d.img.YStride)
|
||||
filter2(d.img.Y, l, yIndex+d.img.YStride*0xc, 1, d.img.YStride)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalFilter implements the normal filter, as specified in section 15.3.
|
||||
func (d *Decoder) normalFilter() {
|
||||
for mby := 0; mby < d.mbh; mby++ {
|
||||
for mbx := 0; mbx < d.mbw; mbx++ {
|
||||
f := d.perMBFilterParams[d.mbw*mby+mbx]
|
||||
if f.level == 0 {
|
||||
continue
|
||||
}
|
||||
l, il, hl := int(f.level), int(f.ilevel), int(f.hlevel)
|
||||
yIndex := (mby*d.img.YStride + mbx) * 16
|
||||
cIndex := (mby*d.img.CStride + mbx) * 8
|
||||
if mbx > 0 {
|
||||
filter246(d.img.Y, 16, l+4, il, hl, yIndex, d.img.YStride, 1, false)
|
||||
filter246(d.img.Cb, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false)
|
||||
filter246(d.img.Cr, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false)
|
||||
}
|
||||
if f.inner {
|
||||
filter246(d.img.Y, 16, l, il, hl, yIndex+0x4, d.img.YStride, 1, true)
|
||||
filter246(d.img.Y, 16, l, il, hl, yIndex+0x8, d.img.YStride, 1, true)
|
||||
filter246(d.img.Y, 16, l, il, hl, yIndex+0xc, d.img.YStride, 1, true)
|
||||
filter246(d.img.Cb, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true)
|
||||
filter246(d.img.Cr, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true)
|
||||
}
|
||||
if mby > 0 {
|
||||
filter246(d.img.Y, 16, l+4, il, hl, yIndex, 1, d.img.YStride, false)
|
||||
filter246(d.img.Cb, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false)
|
||||
filter246(d.img.Cr, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false)
|
||||
}
|
||||
if f.inner {
|
||||
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x4, 1, d.img.YStride, true)
|
||||
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x8, 1, d.img.YStride, true)
|
||||
filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0xc, 1, d.img.YStride, true)
|
||||
filter246(d.img.Cb, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true)
|
||||
filter246(d.img.Cr, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// filterParam holds the loop filter parameters for a macroblock.
|
||||
type filterParam struct {
|
||||
// The first three fields are thresholds used by the loop filter to smooth
|
||||
// over the edges and interior of a macroblock. level is used by both the
|
||||
// simple and normal filters. The inner level and high edge variance level
|
||||
// are only used by the normal filter.
|
||||
level, ilevel, hlevel uint8
|
||||
// inner is whether the inner loop filter cannot be optimized out as a
|
||||
// no-op for this particular macroblock.
|
||||
inner bool
|
||||
}
|
||||
|
||||
// computeFilterParams computes the loop filter parameters, as specified in
|
||||
// section 15.4.
|
||||
func (d *Decoder) computeFilterParams() {
|
||||
for i := range d.filterParams {
|
||||
baseLevel := d.filterHeader.level
|
||||
if d.segmentHeader.useSegment {
|
||||
baseLevel = d.segmentHeader.filterStrength[i]
|
||||
if d.segmentHeader.relativeDelta {
|
||||
baseLevel += d.filterHeader.level
|
||||
}
|
||||
}
|
||||
|
||||
for j := range d.filterParams[i] {
|
||||
p := &d.filterParams[i][j]
|
||||
p.inner = j != 0
|
||||
level := baseLevel
|
||||
if d.filterHeader.useLFDelta {
|
||||
// The libwebp C code has a "TODO: only CURRENT is handled for now."
|
||||
level += d.filterHeader.refLFDelta[0]
|
||||
if j != 0 {
|
||||
level += d.filterHeader.modeLFDelta[0]
|
||||
}
|
||||
}
|
||||
if level <= 0 {
|
||||
p.level = 0
|
||||
continue
|
||||
}
|
||||
if level > 63 {
|
||||
level = 63
|
||||
}
|
||||
ilevel := level
|
||||
if d.filterHeader.sharpness > 0 {
|
||||
if d.filterHeader.sharpness > 4 {
|
||||
ilevel >>= 2
|
||||
} else {
|
||||
ilevel >>= 1
|
||||
}
|
||||
if x := int8(9 - d.filterHeader.sharpness); ilevel > x {
|
||||
ilevel = x
|
||||
}
|
||||
}
|
||||
if ilevel < 1 {
|
||||
ilevel = 1
|
||||
}
|
||||
p.ilevel = uint8(ilevel)
|
||||
p.level = uint8(2*level + ilevel)
|
||||
if d.frameHeader.KeyFrame {
|
||||
if level < 15 {
|
||||
p.hlevel = 0
|
||||
} else if level < 40 {
|
||||
p.hlevel = 1
|
||||
} else {
|
||||
p.hlevel = 2
|
||||
}
|
||||
} else {
|
||||
if level < 15 {
|
||||
p.hlevel = 0
|
||||
} else if level < 20 {
|
||||
p.hlevel = 1
|
||||
} else if level < 40 {
|
||||
p.hlevel = 2
|
||||
} else {
|
||||
p.hlevel = 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// intSize is either 32 or 64.
|
||||
const intSize = 32 << (^uint(0) >> 63)
|
||||
|
||||
func abs(x int) int {
|
||||
// m := -1 if x < 0. m := 0 otherwise.
|
||||
m := x >> (intSize - 1)
|
||||
|
||||
// In two's complement representation, the negative number
|
||||
// of any number (except the smallest one) can be computed
|
||||
// by flipping all the bits and add 1. This is faster than
|
||||
// code with a branch.
|
||||
// See Hacker's Delight, section 2-4.
|
||||
return (x ^ m) - m
|
||||
}
|
||||
|
||||
func clamp15(x int) int {
|
||||
if x < -16 {
|
||||
return -16
|
||||
}
|
||||
if x > 15 {
|
||||
return 15
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func clamp127(x int) int {
|
||||
if x < -128 {
|
||||
return -128
|
||||
}
|
||||
if x > 127 {
|
||||
return 127
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func clamp255(x int) uint8 {
|
||||
if x < 0 {
|
||||
return 0
|
||||
}
|
||||
if x > 255 {
|
||||
return 255
|
||||
}
|
||||
return uint8(x)
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8
|
||||
|
||||
// This file implements the inverse Discrete Cosine Transform and the inverse
|
||||
// Walsh Hadamard Transform (WHT), as specified in sections 14.3 and 14.4.
|
||||
|
||||
func clip8(i int32) uint8 {
|
||||
if i < 0 {
|
||||
return 0
|
||||
}
|
||||
if i > 255 {
|
||||
return 255
|
||||
}
|
||||
return uint8(i)
|
||||
}
|
||||
|
||||
func (z *Decoder) inverseDCT4(y, x, coeffBase int) {
|
||||
const (
|
||||
c1 = 85627 // 65536 * cos(pi/8) * sqrt(2).
|
||||
c2 = 35468 // 65536 * sin(pi/8) * sqrt(2).
|
||||
)
|
||||
var m [4][4]int32
|
||||
for i := 0; i < 4; i++ {
|
||||
a := int32(z.coeff[coeffBase+0]) + int32(z.coeff[coeffBase+8])
|
||||
b := int32(z.coeff[coeffBase+0]) - int32(z.coeff[coeffBase+8])
|
||||
c := (int32(z.coeff[coeffBase+4])*c2)>>16 - (int32(z.coeff[coeffBase+12])*c1)>>16
|
||||
d := (int32(z.coeff[coeffBase+4])*c1)>>16 + (int32(z.coeff[coeffBase+12])*c2)>>16
|
||||
m[i][0] = a + d
|
||||
m[i][1] = b + c
|
||||
m[i][2] = b - c
|
||||
m[i][3] = a - d
|
||||
coeffBase++
|
||||
}
|
||||
for j := 0; j < 4; j++ {
|
||||
dc := m[0][j] + 4
|
||||
a := dc + m[2][j]
|
||||
b := dc - m[2][j]
|
||||
c := (m[1][j]*c2)>>16 - (m[3][j]*c1)>>16
|
||||
d := (m[1][j]*c1)>>16 + (m[3][j]*c2)>>16
|
||||
z.ybr[y+j][x+0] = clip8(int32(z.ybr[y+j][x+0]) + (a+d)>>3)
|
||||
z.ybr[y+j][x+1] = clip8(int32(z.ybr[y+j][x+1]) + (b+c)>>3)
|
||||
z.ybr[y+j][x+2] = clip8(int32(z.ybr[y+j][x+2]) + (b-c)>>3)
|
||||
z.ybr[y+j][x+3] = clip8(int32(z.ybr[y+j][x+3]) + (a-d)>>3)
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Decoder) inverseDCT4DCOnly(y, x, coeffBase int) {
|
||||
dc := (int32(z.coeff[coeffBase+0]) + 4) >> 3
|
||||
for j := 0; j < 4; j++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
z.ybr[y+j][x+i] = clip8(int32(z.ybr[y+j][x+i]) + dc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (z *Decoder) inverseDCT8(y, x, coeffBase int) {
|
||||
z.inverseDCT4(y+0, x+0, coeffBase+0*16)
|
||||
z.inverseDCT4(y+0, x+4, coeffBase+1*16)
|
||||
z.inverseDCT4(y+4, x+0, coeffBase+2*16)
|
||||
z.inverseDCT4(y+4, x+4, coeffBase+3*16)
|
||||
}
|
||||
|
||||
func (z *Decoder) inverseDCT8DCOnly(y, x, coeffBase int) {
|
||||
z.inverseDCT4DCOnly(y+0, x+0, coeffBase+0*16)
|
||||
z.inverseDCT4DCOnly(y+0, x+4, coeffBase+1*16)
|
||||
z.inverseDCT4DCOnly(y+4, x+0, coeffBase+2*16)
|
||||
z.inverseDCT4DCOnly(y+4, x+4, coeffBase+3*16)
|
||||
}
|
||||
|
||||
func (d *Decoder) inverseWHT16() {
|
||||
var m [16]int32
|
||||
for i := 0; i < 4; i++ {
|
||||
a0 := int32(d.coeff[384+0+i]) + int32(d.coeff[384+12+i])
|
||||
a1 := int32(d.coeff[384+4+i]) + int32(d.coeff[384+8+i])
|
||||
a2 := int32(d.coeff[384+4+i]) - int32(d.coeff[384+8+i])
|
||||
a3 := int32(d.coeff[384+0+i]) - int32(d.coeff[384+12+i])
|
||||
m[0+i] = a0 + a1
|
||||
m[8+i] = a0 - a1
|
||||
m[4+i] = a3 + a2
|
||||
m[12+i] = a3 - a2
|
||||
}
|
||||
out := 0
|
||||
for i := 0; i < 4; i++ {
|
||||
dc := m[0+i*4] + 3
|
||||
a0 := dc + m[3+i*4]
|
||||
a1 := m[1+i*4] + m[2+i*4]
|
||||
a2 := m[1+i*4] - m[2+i*4]
|
||||
a3 := dc - m[3+i*4]
|
||||
d.coeff[out+0] = int16((a0 + a1) >> 3)
|
||||
d.coeff[out+16] = int16((a3 + a2) >> 3)
|
||||
d.coeff[out+32] = int16((a0 - a1) >> 3)
|
||||
d.coeff[out+48] = int16((a3 - a2) >> 3)
|
||||
out += 64
|
||||
}
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8
|
||||
|
||||
// Each VP8 frame consists of between 2 and 9 bitstream partitions.
|
||||
// Each partition is byte-aligned and is independently arithmetic-encoded.
|
||||
//
|
||||
// This file implements decoding a partition's bitstream, as specified in
|
||||
// chapter 7. The implementation follows libwebp's approach instead of the
|
||||
// specification's reference C implementation. For example, we use a look-up
|
||||
// table instead of a for loop to recalibrate the encoded range.
|
||||
|
||||
var (
|
||||
lutShift = [127]uint8{
|
||||
7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
}
|
||||
lutRangeM1 = [127]uint8{
|
||||
127,
|
||||
127, 191,
|
||||
127, 159, 191, 223,
|
||||
127, 143, 159, 175, 191, 207, 223, 239,
|
||||
127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, 247,
|
||||
127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 183, 187,
|
||||
191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251,
|
||||
127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157,
|
||||
159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189,
|
||||
191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221,
|
||||
223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253,
|
||||
}
|
||||
)
|
||||
|
||||
// uniformProb represents a 50% probability that the next bit is 0.
|
||||
const uniformProb = 128
|
||||
|
||||
// partition holds arithmetic-coded bits.
|
||||
type partition struct {
|
||||
// buf is the input bytes.
|
||||
buf []byte
|
||||
// r is how many of buf's bytes have been consumed.
|
||||
r int
|
||||
// rangeM1 is range minus 1, where range is in the arithmetic coding sense,
|
||||
// not the Go language sense.
|
||||
rangeM1 uint32
|
||||
// bits and nBits hold those bits shifted out of buf but not yet consumed.
|
||||
bits uint32
|
||||
nBits uint8
|
||||
// unexpectedEOF tells whether we tried to read past buf.
|
||||
unexpectedEOF bool
|
||||
}
|
||||
|
||||
// init initializes the partition.
|
||||
func (p *partition) init(buf []byte) {
|
||||
p.buf = buf
|
||||
p.r = 0
|
||||
p.rangeM1 = 254
|
||||
p.bits = 0
|
||||
p.nBits = 0
|
||||
p.unexpectedEOF = false
|
||||
}
|
||||
|
||||
// readBit returns the next bit.
|
||||
func (p *partition) readBit(prob uint8) bool {
|
||||
if p.nBits < 8 {
|
||||
if p.r >= len(p.buf) {
|
||||
p.unexpectedEOF = true
|
||||
return false
|
||||
}
|
||||
// Expression split for 386 compiler.
|
||||
x := uint32(p.buf[p.r])
|
||||
p.bits |= x << (8 - p.nBits)
|
||||
p.r++
|
||||
p.nBits += 8
|
||||
}
|
||||
split := (p.rangeM1*uint32(prob))>>8 + 1
|
||||
bit := p.bits >= split<<8
|
||||
if bit {
|
||||
p.rangeM1 -= split
|
||||
p.bits -= split << 8
|
||||
} else {
|
||||
p.rangeM1 = split - 1
|
||||
}
|
||||
if p.rangeM1 < 127 {
|
||||
shift := lutShift[p.rangeM1]
|
||||
p.rangeM1 = uint32(lutRangeM1[p.rangeM1])
|
||||
p.bits <<= shift
|
||||
p.nBits -= shift
|
||||
}
|
||||
return bit
|
||||
}
|
||||
|
||||
// readUint returns the next n-bit unsigned integer.
|
||||
func (p *partition) readUint(prob, n uint8) uint32 {
|
||||
var u uint32
|
||||
for n > 0 {
|
||||
n--
|
||||
if p.readBit(prob) {
|
||||
u |= 1 << n
|
||||
}
|
||||
}
|
||||
return u
|
||||
}
|
||||
|
||||
// readInt returns the next n-bit signed integer.
|
||||
func (p *partition) readInt(prob, n uint8) int32 {
|
||||
u := p.readUint(prob, n)
|
||||
b := p.readBit(prob)
|
||||
if b {
|
||||
return -int32(u)
|
||||
}
|
||||
return int32(u)
|
||||
}
|
||||
|
||||
// readOptionalInt returns the next n-bit signed integer in an encoding
|
||||
// where the likely result is zero.
|
||||
func (p *partition) readOptionalInt(prob, n uint8) int32 {
|
||||
if !p.readBit(prob) {
|
||||
return 0
|
||||
}
|
||||
return p.readInt(prob, n)
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8
|
||||
|
||||
// This file implements parsing the predictor modes, as specified in chapter
|
||||
// 11.
|
||||
|
||||
func (d *Decoder) parsePredModeY16(mbx int) {
|
||||
var p uint8
|
||||
if !d.fp.readBit(156) {
|
||||
if !d.fp.readBit(163) {
|
||||
p = predDC
|
||||
} else {
|
||||
p = predVE
|
||||
}
|
||||
} else if !d.fp.readBit(128) {
|
||||
p = predHE
|
||||
} else {
|
||||
p = predTM
|
||||
}
|
||||
for i := 0; i < 4; i++ {
|
||||
d.upMB[mbx].pred[i] = p
|
||||
d.leftMB.pred[i] = p
|
||||
}
|
||||
d.predY16 = p
|
||||
}
|
||||
|
||||
func (d *Decoder) parsePredModeC8() {
|
||||
if !d.fp.readBit(142) {
|
||||
d.predC8 = predDC
|
||||
} else if !d.fp.readBit(114) {
|
||||
d.predC8 = predVE
|
||||
} else if !d.fp.readBit(183) {
|
||||
d.predC8 = predHE
|
||||
} else {
|
||||
d.predC8 = predTM
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) parsePredModeY4(mbx int) {
|
||||
for j := 0; j < 4; j++ {
|
||||
p := d.leftMB.pred[j]
|
||||
for i := 0; i < 4; i++ {
|
||||
prob := &predProb[d.upMB[mbx].pred[i]][p]
|
||||
if !d.fp.readBit(prob[0]) {
|
||||
p = predDC
|
||||
} else if !d.fp.readBit(prob[1]) {
|
||||
p = predTM
|
||||
} else if !d.fp.readBit(prob[2]) {
|
||||
p = predVE
|
||||
} else if !d.fp.readBit(prob[3]) {
|
||||
if !d.fp.readBit(prob[4]) {
|
||||
p = predHE
|
||||
} else if !d.fp.readBit(prob[5]) {
|
||||
p = predRD
|
||||
} else {
|
||||
p = predVR
|
||||
}
|
||||
} else if !d.fp.readBit(prob[6]) {
|
||||
p = predLD
|
||||
} else if !d.fp.readBit(prob[7]) {
|
||||
p = predVL
|
||||
} else if !d.fp.readBit(prob[8]) {
|
||||
p = predHD
|
||||
} else {
|
||||
p = predHU
|
||||
}
|
||||
d.predY4[j][i] = p
|
||||
d.upMB[mbx].pred[i] = p
|
||||
}
|
||||
d.leftMB.pred[j] = p
|
||||
}
|
||||
}
|
||||
|
||||
// predProb are the probabilities to decode a 4x4 region's predictor mode given
|
||||
// the predictor modes of the regions above and left of it.
|
||||
// These values are specified in section 11.5.
|
||||
var predProb = [nPred][nPred][9]uint8{
|
||||
{
|
||||
{231, 120, 48, 89, 115, 113, 120, 152, 112},
|
||||
{152, 179, 64, 126, 170, 118, 46, 70, 95},
|
||||
{175, 69, 143, 80, 85, 82, 72, 155, 103},
|
||||
{56, 58, 10, 171, 218, 189, 17, 13, 152},
|
||||
{114, 26, 17, 163, 44, 195, 21, 10, 173},
|
||||
{121, 24, 80, 195, 26, 62, 44, 64, 85},
|
||||
{144, 71, 10, 38, 171, 213, 144, 34, 26},
|
||||
{170, 46, 55, 19, 136, 160, 33, 206, 71},
|
||||
{63, 20, 8, 114, 114, 208, 12, 9, 226},
|
||||
{81, 40, 11, 96, 182, 84, 29, 16, 36},
|
||||
},
|
||||
{
|
||||
{134, 183, 89, 137, 98, 101, 106, 165, 148},
|
||||
{72, 187, 100, 130, 157, 111, 32, 75, 80},
|
||||
{66, 102, 167, 99, 74, 62, 40, 234, 128},
|
||||
{41, 53, 9, 178, 241, 141, 26, 8, 107},
|
||||
{74, 43, 26, 146, 73, 166, 49, 23, 157},
|
||||
{65, 38, 105, 160, 51, 52, 31, 115, 128},
|
||||
{104, 79, 12, 27, 217, 255, 87, 17, 7},
|
||||
{87, 68, 71, 44, 114, 51, 15, 186, 23},
|
||||
{47, 41, 14, 110, 182, 183, 21, 17, 194},
|
||||
{66, 45, 25, 102, 197, 189, 23, 18, 22},
|
||||
},
|
||||
{
|
||||
{88, 88, 147, 150, 42, 46, 45, 196, 205},
|
||||
{43, 97, 183, 117, 85, 38, 35, 179, 61},
|
||||
{39, 53, 200, 87, 26, 21, 43, 232, 171},
|
||||
{56, 34, 51, 104, 114, 102, 29, 93, 77},
|
||||
{39, 28, 85, 171, 58, 165, 90, 98, 64},
|
||||
{34, 22, 116, 206, 23, 34, 43, 166, 73},
|
||||
{107, 54, 32, 26, 51, 1, 81, 43, 31},
|
||||
{68, 25, 106, 22, 64, 171, 36, 225, 114},
|
||||
{34, 19, 21, 102, 132, 188, 16, 76, 124},
|
||||
{62, 18, 78, 95, 85, 57, 50, 48, 51},
|
||||
},
|
||||
{
|
||||
{193, 101, 35, 159, 215, 111, 89, 46, 111},
|
||||
{60, 148, 31, 172, 219, 228, 21, 18, 111},
|
||||
{112, 113, 77, 85, 179, 255, 38, 120, 114},
|
||||
{40, 42, 1, 196, 245, 209, 10, 25, 109},
|
||||
{88, 43, 29, 140, 166, 213, 37, 43, 154},
|
||||
{61, 63, 30, 155, 67, 45, 68, 1, 209},
|
||||
{100, 80, 8, 43, 154, 1, 51, 26, 71},
|
||||
{142, 78, 78, 16, 255, 128, 34, 197, 171},
|
||||
{41, 40, 5, 102, 211, 183, 4, 1, 221},
|
||||
{51, 50, 17, 168, 209, 192, 23, 25, 82},
|
||||
},
|
||||
{
|
||||
{138, 31, 36, 171, 27, 166, 38, 44, 229},
|
||||
{67, 87, 58, 169, 82, 115, 26, 59, 179},
|
||||
{63, 59, 90, 180, 59, 166, 93, 73, 154},
|
||||
{40, 40, 21, 116, 143, 209, 34, 39, 175},
|
||||
{47, 15, 16, 183, 34, 223, 49, 45, 183},
|
||||
{46, 17, 33, 183, 6, 98, 15, 32, 183},
|
||||
{57, 46, 22, 24, 128, 1, 54, 17, 37},
|
||||
{65, 32, 73, 115, 28, 128, 23, 128, 205},
|
||||
{40, 3, 9, 115, 51, 192, 18, 6, 223},
|
||||
{87, 37, 9, 115, 59, 77, 64, 21, 47},
|
||||
},
|
||||
{
|
||||
{104, 55, 44, 218, 9, 54, 53, 130, 226},
|
||||
{64, 90, 70, 205, 40, 41, 23, 26, 57},
|
||||
{54, 57, 112, 184, 5, 41, 38, 166, 213},
|
||||
{30, 34, 26, 133, 152, 116, 10, 32, 134},
|
||||
{39, 19, 53, 221, 26, 114, 32, 73, 255},
|
||||
{31, 9, 65, 234, 2, 15, 1, 118, 73},
|
||||
{75, 32, 12, 51, 192, 255, 160, 43, 51},
|
||||
{88, 31, 35, 67, 102, 85, 55, 186, 85},
|
||||
{56, 21, 23, 111, 59, 205, 45, 37, 192},
|
||||
{55, 38, 70, 124, 73, 102, 1, 34, 98},
|
||||
},
|
||||
{
|
||||
{125, 98, 42, 88, 104, 85, 117, 175, 82},
|
||||
{95, 84, 53, 89, 128, 100, 113, 101, 45},
|
||||
{75, 79, 123, 47, 51, 128, 81, 171, 1},
|
||||
{57, 17, 5, 71, 102, 57, 53, 41, 49},
|
||||
{38, 33, 13, 121, 57, 73, 26, 1, 85},
|
||||
{41, 10, 67, 138, 77, 110, 90, 47, 114},
|
||||
{115, 21, 2, 10, 102, 255, 166, 23, 6},
|
||||
{101, 29, 16, 10, 85, 128, 101, 196, 26},
|
||||
{57, 18, 10, 102, 102, 213, 34, 20, 43},
|
||||
{117, 20, 15, 36, 163, 128, 68, 1, 26},
|
||||
},
|
||||
{
|
||||
{102, 61, 71, 37, 34, 53, 31, 243, 192},
|
||||
{69, 60, 71, 38, 73, 119, 28, 222, 37},
|
||||
{68, 45, 128, 34, 1, 47, 11, 245, 171},
|
||||
{62, 17, 19, 70, 146, 85, 55, 62, 70},
|
||||
{37, 43, 37, 154, 100, 163, 85, 160, 1},
|
||||
{63, 9, 92, 136, 28, 64, 32, 201, 85},
|
||||
{75, 15, 9, 9, 64, 255, 184, 119, 16},
|
||||
{86, 6, 28, 5, 64, 255, 25, 248, 1},
|
||||
{56, 8, 17, 132, 137, 255, 55, 116, 128},
|
||||
{58, 15, 20, 82, 135, 57, 26, 121, 40},
|
||||
},
|
||||
{
|
||||
{164, 50, 31, 137, 154, 133, 25, 35, 218},
|
||||
{51, 103, 44, 131, 131, 123, 31, 6, 158},
|
||||
{86, 40, 64, 135, 148, 224, 45, 183, 128},
|
||||
{22, 26, 17, 131, 240, 154, 14, 1, 209},
|
||||
{45, 16, 21, 91, 64, 222, 7, 1, 197},
|
||||
{56, 21, 39, 155, 60, 138, 23, 102, 213},
|
||||
{83, 12, 13, 54, 192, 255, 68, 47, 28},
|
||||
{85, 26, 85, 85, 128, 128, 32, 146, 171},
|
||||
{18, 11, 7, 63, 144, 171, 4, 4, 246},
|
||||
{35, 27, 10, 146, 174, 171, 12, 26, 128},
|
||||
},
|
||||
{
|
||||
{190, 80, 35, 99, 180, 80, 126, 54, 45},
|
||||
{85, 126, 47, 87, 176, 51, 41, 20, 32},
|
||||
{101, 75, 128, 139, 118, 146, 116, 128, 85},
|
||||
{56, 41, 15, 176, 236, 85, 37, 9, 62},
|
||||
{71, 30, 17, 119, 118, 255, 17, 18, 138},
|
||||
{101, 38, 60, 138, 55, 70, 43, 26, 142},
|
||||
{146, 36, 19, 30, 171, 255, 97, 27, 20},
|
||||
{138, 45, 61, 62, 219, 1, 81, 188, 64},
|
||||
{32, 41, 20, 117, 151, 142, 20, 21, 163},
|
||||
{112, 19, 12, 61, 195, 128, 48, 4, 24},
|
||||
},
|
||||
}
|
||||
+553
@@ -0,0 +1,553 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8
|
||||
|
||||
// This file implements the prediction functions, as specified in chapter 12.
|
||||
//
|
||||
// For each macroblock (of 1x16x16 luma and 2x8x8 chroma coefficients), the
|
||||
// luma values are either predicted as one large 16x16 region or 16 separate
|
||||
// 4x4 regions. The chroma values are always predicted as one 8x8 region.
|
||||
//
|
||||
// For 4x4 regions, the target block's predicted values (Xs) are a function of
|
||||
// its previously-decoded top and left border values, as well as a number of
|
||||
// pixels from the top-right:
|
||||
//
|
||||
// a b c d e f g h
|
||||
// p X X X X
|
||||
// q X X X X
|
||||
// r X X X X
|
||||
// s X X X X
|
||||
//
|
||||
// The predictor modes are:
|
||||
// - DC: all Xs = (b + c + d + e + p + q + r + s + 4) / 8.
|
||||
// - TM: the first X = (b + p - a), the second X = (c + p - a), and so on.
|
||||
// - VE: each X = the weighted average of its column's top value and that
|
||||
// value's neighbors, i.e. averages of abc, bcd, cde or def.
|
||||
// - HE: similar to VE except rows instead of columns, and the final row is
|
||||
// an average of r, s and s.
|
||||
// - RD, VR, LD, VL, HD, HU: these diagonal modes ("Right Down", "Vertical
|
||||
// Right", etc) are more complicated and are described in section 12.3.
|
||||
// All Xs are clipped to the range [0, 255].
|
||||
//
|
||||
// For 8x8 and 16x16 regions, the target block's predicted values are a
|
||||
// function of the top and left border values without the top-right overhang,
|
||||
// i.e. without the 8x8 or 16x16 equivalent of f, g and h. Furthermore:
|
||||
// - There are no diagonal predictor modes, only DC, TM, VE and HE.
|
||||
// - The DC mode has variants for macroblocks in the top row and/or left
|
||||
// column, i.e. for macroblocks with mby == 0 || mbx == 0.
|
||||
// - The VE and HE modes take only the column top or row left values; they do
|
||||
// not smooth that top/left value with its neighbors.
|
||||
|
||||
// nPred is the number of predictor modes, not including the Top/Left versions
|
||||
// of the DC predictor mode.
|
||||
const nPred = 10
|
||||
|
||||
const (
|
||||
predDC = iota
|
||||
predTM
|
||||
predVE
|
||||
predHE
|
||||
predRD
|
||||
predVR
|
||||
predLD
|
||||
predVL
|
||||
predHD
|
||||
predHU
|
||||
predDCTop
|
||||
predDCLeft
|
||||
predDCTopLeft
|
||||
)
|
||||
|
||||
func checkTopLeftPred(mbx, mby int, p uint8) uint8 {
|
||||
if p != predDC {
|
||||
return p
|
||||
}
|
||||
if mbx == 0 {
|
||||
if mby == 0 {
|
||||
return predDCTopLeft
|
||||
}
|
||||
return predDCLeft
|
||||
}
|
||||
if mby == 0 {
|
||||
return predDCTop
|
||||
}
|
||||
return predDC
|
||||
}
|
||||
|
||||
var predFunc4 = [...]func(*Decoder, int, int){
|
||||
predFunc4DC,
|
||||
predFunc4TM,
|
||||
predFunc4VE,
|
||||
predFunc4HE,
|
||||
predFunc4RD,
|
||||
predFunc4VR,
|
||||
predFunc4LD,
|
||||
predFunc4VL,
|
||||
predFunc4HD,
|
||||
predFunc4HU,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
}
|
||||
|
||||
var predFunc8 = [...]func(*Decoder, int, int){
|
||||
predFunc8DC,
|
||||
predFunc8TM,
|
||||
predFunc8VE,
|
||||
predFunc8HE,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
predFunc8DCTop,
|
||||
predFunc8DCLeft,
|
||||
predFunc8DCTopLeft,
|
||||
}
|
||||
|
||||
var predFunc16 = [...]func(*Decoder, int, int){
|
||||
predFunc16DC,
|
||||
predFunc16TM,
|
||||
predFunc16VE,
|
||||
predFunc16HE,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
predFunc16DCTop,
|
||||
predFunc16DCLeft,
|
||||
predFunc16DCTopLeft,
|
||||
}
|
||||
|
||||
func predFunc4DC(z *Decoder, y, x int) {
|
||||
sum := uint32(4)
|
||||
for i := 0; i < 4; i++ {
|
||||
sum += uint32(z.ybr[y-1][x+i])
|
||||
}
|
||||
for j := 0; j < 4; j++ {
|
||||
sum += uint32(z.ybr[y+j][x-1])
|
||||
}
|
||||
avg := uint8(sum / 8)
|
||||
for j := 0; j < 4; j++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
z.ybr[y+j][x+i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc4TM(z *Decoder, y, x int) {
|
||||
delta0 := -int32(z.ybr[y-1][x-1])
|
||||
for j := 0; j < 4; j++ {
|
||||
delta1 := delta0 + int32(z.ybr[y+j][x-1])
|
||||
for i := 0; i < 4; i++ {
|
||||
delta2 := delta1 + int32(z.ybr[y-1][x+i])
|
||||
z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc4VE(z *Decoder, y, x int) {
|
||||
a := int32(z.ybr[y-1][x-1])
|
||||
b := int32(z.ybr[y-1][x+0])
|
||||
c := int32(z.ybr[y-1][x+1])
|
||||
d := int32(z.ybr[y-1][x+2])
|
||||
e := int32(z.ybr[y-1][x+3])
|
||||
f := int32(z.ybr[y-1][x+4])
|
||||
abc := uint8((a + 2*b + c + 2) / 4)
|
||||
bcd := uint8((b + 2*c + d + 2) / 4)
|
||||
cde := uint8((c + 2*d + e + 2) / 4)
|
||||
def := uint8((d + 2*e + f + 2) / 4)
|
||||
for j := 0; j < 4; j++ {
|
||||
z.ybr[y+j][x+0] = abc
|
||||
z.ybr[y+j][x+1] = bcd
|
||||
z.ybr[y+j][x+2] = cde
|
||||
z.ybr[y+j][x+3] = def
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc4HE(z *Decoder, y, x int) {
|
||||
s := int32(z.ybr[y+3][x-1])
|
||||
r := int32(z.ybr[y+2][x-1])
|
||||
q := int32(z.ybr[y+1][x-1])
|
||||
p := int32(z.ybr[y+0][x-1])
|
||||
a := int32(z.ybr[y-1][x-1])
|
||||
ssr := uint8((s + 2*s + r + 2) / 4)
|
||||
srq := uint8((s + 2*r + q + 2) / 4)
|
||||
rqp := uint8((r + 2*q + p + 2) / 4)
|
||||
apq := uint8((a + 2*p + q + 2) / 4)
|
||||
for i := 0; i < 4; i++ {
|
||||
z.ybr[y+0][x+i] = apq
|
||||
z.ybr[y+1][x+i] = rqp
|
||||
z.ybr[y+2][x+i] = srq
|
||||
z.ybr[y+3][x+i] = ssr
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc4RD(z *Decoder, y, x int) {
|
||||
s := int32(z.ybr[y+3][x-1])
|
||||
r := int32(z.ybr[y+2][x-1])
|
||||
q := int32(z.ybr[y+1][x-1])
|
||||
p := int32(z.ybr[y+0][x-1])
|
||||
a := int32(z.ybr[y-1][x-1])
|
||||
b := int32(z.ybr[y-1][x+0])
|
||||
c := int32(z.ybr[y-1][x+1])
|
||||
d := int32(z.ybr[y-1][x+2])
|
||||
e := int32(z.ybr[y-1][x+3])
|
||||
srq := uint8((s + 2*r + q + 2) / 4)
|
||||
rqp := uint8((r + 2*q + p + 2) / 4)
|
||||
qpa := uint8((q + 2*p + a + 2) / 4)
|
||||
pab := uint8((p + 2*a + b + 2) / 4)
|
||||
abc := uint8((a + 2*b + c + 2) / 4)
|
||||
bcd := uint8((b + 2*c + d + 2) / 4)
|
||||
cde := uint8((c + 2*d + e + 2) / 4)
|
||||
z.ybr[y+0][x+0] = pab
|
||||
z.ybr[y+0][x+1] = abc
|
||||
z.ybr[y+0][x+2] = bcd
|
||||
z.ybr[y+0][x+3] = cde
|
||||
z.ybr[y+1][x+0] = qpa
|
||||
z.ybr[y+1][x+1] = pab
|
||||
z.ybr[y+1][x+2] = abc
|
||||
z.ybr[y+1][x+3] = bcd
|
||||
z.ybr[y+2][x+0] = rqp
|
||||
z.ybr[y+2][x+1] = qpa
|
||||
z.ybr[y+2][x+2] = pab
|
||||
z.ybr[y+2][x+3] = abc
|
||||
z.ybr[y+3][x+0] = srq
|
||||
z.ybr[y+3][x+1] = rqp
|
||||
z.ybr[y+3][x+2] = qpa
|
||||
z.ybr[y+3][x+3] = pab
|
||||
}
|
||||
|
||||
func predFunc4VR(z *Decoder, y, x int) {
|
||||
r := int32(z.ybr[y+2][x-1])
|
||||
q := int32(z.ybr[y+1][x-1])
|
||||
p := int32(z.ybr[y+0][x-1])
|
||||
a := int32(z.ybr[y-1][x-1])
|
||||
b := int32(z.ybr[y-1][x+0])
|
||||
c := int32(z.ybr[y-1][x+1])
|
||||
d := int32(z.ybr[y-1][x+2])
|
||||
e := int32(z.ybr[y-1][x+3])
|
||||
ab := uint8((a + b + 1) / 2)
|
||||
bc := uint8((b + c + 1) / 2)
|
||||
cd := uint8((c + d + 1) / 2)
|
||||
de := uint8((d + e + 1) / 2)
|
||||
rqp := uint8((r + 2*q + p + 2) / 4)
|
||||
qpa := uint8((q + 2*p + a + 2) / 4)
|
||||
pab := uint8((p + 2*a + b + 2) / 4)
|
||||
abc := uint8((a + 2*b + c + 2) / 4)
|
||||
bcd := uint8((b + 2*c + d + 2) / 4)
|
||||
cde := uint8((c + 2*d + e + 2) / 4)
|
||||
z.ybr[y+0][x+0] = ab
|
||||
z.ybr[y+0][x+1] = bc
|
||||
z.ybr[y+0][x+2] = cd
|
||||
z.ybr[y+0][x+3] = de
|
||||
z.ybr[y+1][x+0] = pab
|
||||
z.ybr[y+1][x+1] = abc
|
||||
z.ybr[y+1][x+2] = bcd
|
||||
z.ybr[y+1][x+3] = cde
|
||||
z.ybr[y+2][x+0] = qpa
|
||||
z.ybr[y+2][x+1] = ab
|
||||
z.ybr[y+2][x+2] = bc
|
||||
z.ybr[y+2][x+3] = cd
|
||||
z.ybr[y+3][x+0] = rqp
|
||||
z.ybr[y+3][x+1] = pab
|
||||
z.ybr[y+3][x+2] = abc
|
||||
z.ybr[y+3][x+3] = bcd
|
||||
}
|
||||
|
||||
func predFunc4LD(z *Decoder, y, x int) {
|
||||
a := int32(z.ybr[y-1][x+0])
|
||||
b := int32(z.ybr[y-1][x+1])
|
||||
c := int32(z.ybr[y-1][x+2])
|
||||
d := int32(z.ybr[y-1][x+3])
|
||||
e := int32(z.ybr[y-1][x+4])
|
||||
f := int32(z.ybr[y-1][x+5])
|
||||
g := int32(z.ybr[y-1][x+6])
|
||||
h := int32(z.ybr[y-1][x+7])
|
||||
abc := uint8((a + 2*b + c + 2) / 4)
|
||||
bcd := uint8((b + 2*c + d + 2) / 4)
|
||||
cde := uint8((c + 2*d + e + 2) / 4)
|
||||
def := uint8((d + 2*e + f + 2) / 4)
|
||||
efg := uint8((e + 2*f + g + 2) / 4)
|
||||
fgh := uint8((f + 2*g + h + 2) / 4)
|
||||
ghh := uint8((g + 2*h + h + 2) / 4)
|
||||
z.ybr[y+0][x+0] = abc
|
||||
z.ybr[y+0][x+1] = bcd
|
||||
z.ybr[y+0][x+2] = cde
|
||||
z.ybr[y+0][x+3] = def
|
||||
z.ybr[y+1][x+0] = bcd
|
||||
z.ybr[y+1][x+1] = cde
|
||||
z.ybr[y+1][x+2] = def
|
||||
z.ybr[y+1][x+3] = efg
|
||||
z.ybr[y+2][x+0] = cde
|
||||
z.ybr[y+2][x+1] = def
|
||||
z.ybr[y+2][x+2] = efg
|
||||
z.ybr[y+2][x+3] = fgh
|
||||
z.ybr[y+3][x+0] = def
|
||||
z.ybr[y+3][x+1] = efg
|
||||
z.ybr[y+3][x+2] = fgh
|
||||
z.ybr[y+3][x+3] = ghh
|
||||
}
|
||||
|
||||
func predFunc4VL(z *Decoder, y, x int) {
|
||||
a := int32(z.ybr[y-1][x+0])
|
||||
b := int32(z.ybr[y-1][x+1])
|
||||
c := int32(z.ybr[y-1][x+2])
|
||||
d := int32(z.ybr[y-1][x+3])
|
||||
e := int32(z.ybr[y-1][x+4])
|
||||
f := int32(z.ybr[y-1][x+5])
|
||||
g := int32(z.ybr[y-1][x+6])
|
||||
h := int32(z.ybr[y-1][x+7])
|
||||
ab := uint8((a + b + 1) / 2)
|
||||
bc := uint8((b + c + 1) / 2)
|
||||
cd := uint8((c + d + 1) / 2)
|
||||
de := uint8((d + e + 1) / 2)
|
||||
abc := uint8((a + 2*b + c + 2) / 4)
|
||||
bcd := uint8((b + 2*c + d + 2) / 4)
|
||||
cde := uint8((c + 2*d + e + 2) / 4)
|
||||
def := uint8((d + 2*e + f + 2) / 4)
|
||||
efg := uint8((e + 2*f + g + 2) / 4)
|
||||
fgh := uint8((f + 2*g + h + 2) / 4)
|
||||
z.ybr[y+0][x+0] = ab
|
||||
z.ybr[y+0][x+1] = bc
|
||||
z.ybr[y+0][x+2] = cd
|
||||
z.ybr[y+0][x+3] = de
|
||||
z.ybr[y+1][x+0] = abc
|
||||
z.ybr[y+1][x+1] = bcd
|
||||
z.ybr[y+1][x+2] = cde
|
||||
z.ybr[y+1][x+3] = def
|
||||
z.ybr[y+2][x+0] = bc
|
||||
z.ybr[y+2][x+1] = cd
|
||||
z.ybr[y+2][x+2] = de
|
||||
z.ybr[y+2][x+3] = efg
|
||||
z.ybr[y+3][x+0] = bcd
|
||||
z.ybr[y+3][x+1] = cde
|
||||
z.ybr[y+3][x+2] = def
|
||||
z.ybr[y+3][x+3] = fgh
|
||||
}
|
||||
|
||||
func predFunc4HD(z *Decoder, y, x int) {
|
||||
s := int32(z.ybr[y+3][x-1])
|
||||
r := int32(z.ybr[y+2][x-1])
|
||||
q := int32(z.ybr[y+1][x-1])
|
||||
p := int32(z.ybr[y+0][x-1])
|
||||
a := int32(z.ybr[y-1][x-1])
|
||||
b := int32(z.ybr[y-1][x+0])
|
||||
c := int32(z.ybr[y-1][x+1])
|
||||
d := int32(z.ybr[y-1][x+2])
|
||||
sr := uint8((s + r + 1) / 2)
|
||||
rq := uint8((r + q + 1) / 2)
|
||||
qp := uint8((q + p + 1) / 2)
|
||||
pa := uint8((p + a + 1) / 2)
|
||||
srq := uint8((s + 2*r + q + 2) / 4)
|
||||
rqp := uint8((r + 2*q + p + 2) / 4)
|
||||
qpa := uint8((q + 2*p + a + 2) / 4)
|
||||
pab := uint8((p + 2*a + b + 2) / 4)
|
||||
abc := uint8((a + 2*b + c + 2) / 4)
|
||||
bcd := uint8((b + 2*c + d + 2) / 4)
|
||||
z.ybr[y+0][x+0] = pa
|
||||
z.ybr[y+0][x+1] = pab
|
||||
z.ybr[y+0][x+2] = abc
|
||||
z.ybr[y+0][x+3] = bcd
|
||||
z.ybr[y+1][x+0] = qp
|
||||
z.ybr[y+1][x+1] = qpa
|
||||
z.ybr[y+1][x+2] = pa
|
||||
z.ybr[y+1][x+3] = pab
|
||||
z.ybr[y+2][x+0] = rq
|
||||
z.ybr[y+2][x+1] = rqp
|
||||
z.ybr[y+2][x+2] = qp
|
||||
z.ybr[y+2][x+3] = qpa
|
||||
z.ybr[y+3][x+0] = sr
|
||||
z.ybr[y+3][x+1] = srq
|
||||
z.ybr[y+3][x+2] = rq
|
||||
z.ybr[y+3][x+3] = rqp
|
||||
}
|
||||
|
||||
func predFunc4HU(z *Decoder, y, x int) {
|
||||
s := int32(z.ybr[y+3][x-1])
|
||||
r := int32(z.ybr[y+2][x-1])
|
||||
q := int32(z.ybr[y+1][x-1])
|
||||
p := int32(z.ybr[y+0][x-1])
|
||||
pq := uint8((p + q + 1) / 2)
|
||||
qr := uint8((q + r + 1) / 2)
|
||||
rs := uint8((r + s + 1) / 2)
|
||||
pqr := uint8((p + 2*q + r + 2) / 4)
|
||||
qrs := uint8((q + 2*r + s + 2) / 4)
|
||||
rss := uint8((r + 2*s + s + 2) / 4)
|
||||
sss := uint8(s)
|
||||
z.ybr[y+0][x+0] = pq
|
||||
z.ybr[y+0][x+1] = pqr
|
||||
z.ybr[y+0][x+2] = qr
|
||||
z.ybr[y+0][x+3] = qrs
|
||||
z.ybr[y+1][x+0] = qr
|
||||
z.ybr[y+1][x+1] = qrs
|
||||
z.ybr[y+1][x+2] = rs
|
||||
z.ybr[y+1][x+3] = rss
|
||||
z.ybr[y+2][x+0] = rs
|
||||
z.ybr[y+2][x+1] = rss
|
||||
z.ybr[y+2][x+2] = sss
|
||||
z.ybr[y+2][x+3] = sss
|
||||
z.ybr[y+3][x+0] = sss
|
||||
z.ybr[y+3][x+1] = sss
|
||||
z.ybr[y+3][x+2] = sss
|
||||
z.ybr[y+3][x+3] = sss
|
||||
}
|
||||
|
||||
func predFunc8DC(z *Decoder, y, x int) {
|
||||
sum := uint32(8)
|
||||
for i := 0; i < 8; i++ {
|
||||
sum += uint32(z.ybr[y-1][x+i])
|
||||
}
|
||||
for j := 0; j < 8; j++ {
|
||||
sum += uint32(z.ybr[y+j][x-1])
|
||||
}
|
||||
avg := uint8(sum / 16)
|
||||
for j := 0; j < 8; j++ {
|
||||
for i := 0; i < 8; i++ {
|
||||
z.ybr[y+j][x+i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc8TM(z *Decoder, y, x int) {
|
||||
delta0 := -int32(z.ybr[y-1][x-1])
|
||||
for j := 0; j < 8; j++ {
|
||||
delta1 := delta0 + int32(z.ybr[y+j][x-1])
|
||||
for i := 0; i < 8; i++ {
|
||||
delta2 := delta1 + int32(z.ybr[y-1][x+i])
|
||||
z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc8VE(z *Decoder, y, x int) {
|
||||
for j := 0; j < 8; j++ {
|
||||
for i := 0; i < 8; i++ {
|
||||
z.ybr[y+j][x+i] = z.ybr[y-1][x+i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc8HE(z *Decoder, y, x int) {
|
||||
for j := 0; j < 8; j++ {
|
||||
for i := 0; i < 8; i++ {
|
||||
z.ybr[y+j][x+i] = z.ybr[y+j][x-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc8DCTop(z *Decoder, y, x int) {
|
||||
sum := uint32(4)
|
||||
for j := 0; j < 8; j++ {
|
||||
sum += uint32(z.ybr[y+j][x-1])
|
||||
}
|
||||
avg := uint8(sum / 8)
|
||||
for j := 0; j < 8; j++ {
|
||||
for i := 0; i < 8; i++ {
|
||||
z.ybr[y+j][x+i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc8DCLeft(z *Decoder, y, x int) {
|
||||
sum := uint32(4)
|
||||
for i := 0; i < 8; i++ {
|
||||
sum += uint32(z.ybr[y-1][x+i])
|
||||
}
|
||||
avg := uint8(sum / 8)
|
||||
for j := 0; j < 8; j++ {
|
||||
for i := 0; i < 8; i++ {
|
||||
z.ybr[y+j][x+i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc8DCTopLeft(z *Decoder, y, x int) {
|
||||
for j := 0; j < 8; j++ {
|
||||
for i := 0; i < 8; i++ {
|
||||
z.ybr[y+j][x+i] = 0x80
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc16DC(z *Decoder, y, x int) {
|
||||
sum := uint32(16)
|
||||
for i := 0; i < 16; i++ {
|
||||
sum += uint32(z.ybr[y-1][x+i])
|
||||
}
|
||||
for j := 0; j < 16; j++ {
|
||||
sum += uint32(z.ybr[y+j][x-1])
|
||||
}
|
||||
avg := uint8(sum / 32)
|
||||
for j := 0; j < 16; j++ {
|
||||
for i := 0; i < 16; i++ {
|
||||
z.ybr[y+j][x+i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc16TM(z *Decoder, y, x int) {
|
||||
delta0 := -int32(z.ybr[y-1][x-1])
|
||||
for j := 0; j < 16; j++ {
|
||||
delta1 := delta0 + int32(z.ybr[y+j][x-1])
|
||||
for i := 0; i < 16; i++ {
|
||||
delta2 := delta1 + int32(z.ybr[y-1][x+i])
|
||||
z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc16VE(z *Decoder, y, x int) {
|
||||
for j := 0; j < 16; j++ {
|
||||
for i := 0; i < 16; i++ {
|
||||
z.ybr[y+j][x+i] = z.ybr[y-1][x+i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc16HE(z *Decoder, y, x int) {
|
||||
for j := 0; j < 16; j++ {
|
||||
for i := 0; i < 16; i++ {
|
||||
z.ybr[y+j][x+i] = z.ybr[y+j][x-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc16DCTop(z *Decoder, y, x int) {
|
||||
sum := uint32(8)
|
||||
for j := 0; j < 16; j++ {
|
||||
sum += uint32(z.ybr[y+j][x-1])
|
||||
}
|
||||
avg := uint8(sum / 16)
|
||||
for j := 0; j < 16; j++ {
|
||||
for i := 0; i < 16; i++ {
|
||||
z.ybr[y+j][x+i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc16DCLeft(z *Decoder, y, x int) {
|
||||
sum := uint32(8)
|
||||
for i := 0; i < 16; i++ {
|
||||
sum += uint32(z.ybr[y-1][x+i])
|
||||
}
|
||||
avg := uint8(sum / 16)
|
||||
for j := 0; j < 16; j++ {
|
||||
for i := 0; i < 16; i++ {
|
||||
z.ybr[y+j][x+i] = avg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func predFunc16DCTopLeft(z *Decoder, y, x int) {
|
||||
for j := 0; j < 16; j++ {
|
||||
for i := 0; i < 16; i++ {
|
||||
z.ybr[y+j][x+i] = 0x80
|
||||
}
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8
|
||||
|
||||
// This file implements parsing the quantization factors.
|
||||
|
||||
// quant are DC/AC quantization factors.
|
||||
type quant struct {
|
||||
y1 [2]uint16
|
||||
y2 [2]uint16
|
||||
uv [2]uint16
|
||||
}
|
||||
|
||||
// clip clips x to the range [min, max] inclusive.
|
||||
func clip(x, min, max int32) int32 {
|
||||
if x < min {
|
||||
return min
|
||||
}
|
||||
if x > max {
|
||||
return max
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// parseQuant parses the quantization factors, as specified in section 9.6.
|
||||
func (d *Decoder) parseQuant() {
|
||||
baseQ0 := d.fp.readUint(uniformProb, 7)
|
||||
dqy1DC := d.fp.readOptionalInt(uniformProb, 4)
|
||||
const dqy1AC = 0
|
||||
dqy2DC := d.fp.readOptionalInt(uniformProb, 4)
|
||||
dqy2AC := d.fp.readOptionalInt(uniformProb, 4)
|
||||
dquvDC := d.fp.readOptionalInt(uniformProb, 4)
|
||||
dquvAC := d.fp.readOptionalInt(uniformProb, 4)
|
||||
for i := 0; i < nSegment; i++ {
|
||||
q := int32(baseQ0)
|
||||
if d.segmentHeader.useSegment {
|
||||
if d.segmentHeader.relativeDelta {
|
||||
q += int32(d.segmentHeader.quantizer[i])
|
||||
} else {
|
||||
q = int32(d.segmentHeader.quantizer[i])
|
||||
}
|
||||
}
|
||||
d.quant[i].y1[0] = dequantTableDC[clip(q+dqy1DC, 0, 127)]
|
||||
d.quant[i].y1[1] = dequantTableAC[clip(q+dqy1AC, 0, 127)]
|
||||
d.quant[i].y2[0] = dequantTableDC[clip(q+dqy2DC, 0, 127)] * 2
|
||||
d.quant[i].y2[1] = dequantTableAC[clip(q+dqy2AC, 0, 127)] * 155 / 100
|
||||
if d.quant[i].y2[1] < 8 {
|
||||
d.quant[i].y2[1] = 8
|
||||
}
|
||||
// The 117 is not a typo. The dequant_init function in the spec's Reference
|
||||
// Decoder Source Code (http://tools.ietf.org/html/rfc6386#section-9.6 Page 145)
|
||||
// says to clamp the LHS value at 132, which is equal to dequantTableDC[117].
|
||||
d.quant[i].uv[0] = dequantTableDC[clip(q+dquvDC, 0, 117)]
|
||||
d.quant[i].uv[1] = dequantTableAC[clip(q+dquvAC, 0, 127)]
|
||||
}
|
||||
}
|
||||
|
||||
// The dequantization tables are specified in section 14.1.
|
||||
var (
|
||||
dequantTableDC = [128]uint16{
|
||||
4, 5, 6, 7, 8, 9, 10, 10,
|
||||
11, 12, 13, 14, 15, 16, 17, 17,
|
||||
18, 19, 20, 20, 21, 21, 22, 22,
|
||||
23, 23, 24, 25, 25, 26, 27, 28,
|
||||
29, 30, 31, 32, 33, 34, 35, 36,
|
||||
37, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 46, 47, 48, 49, 50,
|
||||
51, 52, 53, 54, 55, 56, 57, 58,
|
||||
59, 60, 61, 62, 63, 64, 65, 66,
|
||||
67, 68, 69, 70, 71, 72, 73, 74,
|
||||
75, 76, 76, 77, 78, 79, 80, 81,
|
||||
82, 83, 84, 85, 86, 87, 88, 89,
|
||||
91, 93, 95, 96, 98, 100, 101, 102,
|
||||
104, 106, 108, 110, 112, 114, 116, 118,
|
||||
122, 124, 126, 128, 130, 132, 134, 136,
|
||||
138, 140, 143, 145, 148, 151, 154, 157,
|
||||
}
|
||||
dequantTableAC = [128]uint16{
|
||||
4, 5, 6, 7, 8, 9, 10, 11,
|
||||
12, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 25, 26, 27,
|
||||
28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43,
|
||||
44, 45, 46, 47, 48, 49, 50, 51,
|
||||
52, 53, 54, 55, 56, 57, 58, 60,
|
||||
62, 64, 66, 68, 70, 72, 74, 76,
|
||||
78, 80, 82, 84, 86, 88, 90, 92,
|
||||
94, 96, 98, 100, 102, 104, 106, 108,
|
||||
110, 112, 114, 116, 119, 122, 125, 128,
|
||||
131, 134, 137, 140, 143, 146, 149, 152,
|
||||
155, 158, 161, 164, 167, 170, 173, 177,
|
||||
181, 185, 189, 193, 197, 201, 205, 209,
|
||||
213, 217, 221, 225, 229, 234, 239, 245,
|
||||
249, 254, 259, 264, 269, 274, 279, 284,
|
||||
}
|
||||
)
|
||||
+442
@@ -0,0 +1,442 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8
|
||||
|
||||
// This file implements decoding DCT/WHT residual coefficients and
|
||||
// reconstructing YCbCr data equal to predicted values plus residuals.
|
||||
//
|
||||
// There are 1*16*16 + 2*8*8 + 1*4*4 coefficients per macroblock:
|
||||
// - 1*16*16 luma DCT coefficients,
|
||||
// - 2*8*8 chroma DCT coefficients, and
|
||||
// - 1*4*4 luma WHT coefficients.
|
||||
// Coefficients are read in lots of 16, and the later coefficients in each lot
|
||||
// are often zero.
|
||||
//
|
||||
// The YCbCr data consists of 1*16*16 luma values and 2*8*8 chroma values,
|
||||
// plus previously decoded values along the top and left borders. The combined
|
||||
// values are laid out as a [1+16+1+8][32]uint8 so that vertically adjacent
|
||||
// samples are 32 bytes apart. In detail, the layout is:
|
||||
//
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// . . . . . . . a b b b b b b b b b b b b b b b b c c c c . . . . 0
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 1
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 2
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 3
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 4
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 5
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 6
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 7
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 8
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 9
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 10
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 11
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 12
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 13
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 14
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 15
|
||||
// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 16
|
||||
// . . . . . . . e f f f f f f f f . . . . . . . g h h h h h h h h 17
|
||||
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 18
|
||||
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 19
|
||||
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 20
|
||||
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 21
|
||||
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 22
|
||||
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 23
|
||||
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 24
|
||||
// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 25
|
||||
//
|
||||
// Y, B and R are the reconstructed luma (Y) and chroma (B, R) values.
|
||||
// The Y values are predicted (either as one 16x16 region or 16 4x4 regions)
|
||||
// based on the row above's Y values (some combination of {abc} or {dYC}) and
|
||||
// the column left's Y values (either {ad} or {bY}). Similarly, B and R values
|
||||
// are predicted on the row above and column left of their respective 8x8
|
||||
// region: {efi} for B, {ghj} for R.
|
||||
//
|
||||
// For uppermost macroblocks (i.e. those with mby == 0), the {abcefgh} values
|
||||
// are initialized to 0x81. Otherwise, they are copied from the bottom row of
|
||||
// the macroblock above. The {c} values are then duplicated from row 0 to rows
|
||||
// 4, 8 and 12 of the ybr workspace.
|
||||
// Similarly, for leftmost macroblocks (i.e. those with mbx == 0), the {adeigj}
|
||||
// values are initialized to 0x7f. Otherwise, they are copied from the right
|
||||
// column of the macroblock to the left.
|
||||
// For the top-left macroblock (with mby == 0 && mbx == 0), {aeg} is 0x81.
|
||||
//
|
||||
// When moving from one macroblock to the next horizontally, the {adeigj}
|
||||
// values can simply be copied from the workspace to itself, shifted by 8 or
|
||||
// 16 columns. When moving from one macroblock to the next vertically,
|
||||
// filtering can occur and hence the row values have to be copied from the
|
||||
// post-filtered image instead of the pre-filtered workspace.
|
||||
|
||||
const (
|
||||
bCoeffBase = 1*16*16 + 0*8*8
|
||||
rCoeffBase = 1*16*16 + 1*8*8
|
||||
whtCoeffBase = 1*16*16 + 2*8*8
|
||||
)
|
||||
|
||||
const (
|
||||
ybrYX = 8
|
||||
ybrYY = 1
|
||||
ybrBX = 8
|
||||
ybrBY = 18
|
||||
ybrRX = 24
|
||||
ybrRY = 18
|
||||
)
|
||||
|
||||
// prepareYBR prepares the {abcdefghij} elements of ybr.
|
||||
func (d *Decoder) prepareYBR(mbx, mby int) {
|
||||
if mbx == 0 {
|
||||
for y := 0; y < 17; y++ {
|
||||
d.ybr[y][7] = 0x81
|
||||
}
|
||||
for y := 17; y < 26; y++ {
|
||||
d.ybr[y][7] = 0x81
|
||||
d.ybr[y][23] = 0x81
|
||||
}
|
||||
} else {
|
||||
for y := 0; y < 17; y++ {
|
||||
d.ybr[y][7] = d.ybr[y][7+16]
|
||||
}
|
||||
for y := 17; y < 26; y++ {
|
||||
d.ybr[y][7] = d.ybr[y][15]
|
||||
d.ybr[y][23] = d.ybr[y][31]
|
||||
}
|
||||
}
|
||||
if mby == 0 {
|
||||
for x := 7; x < 28; x++ {
|
||||
d.ybr[0][x] = 0x7f
|
||||
}
|
||||
for x := 7; x < 16; x++ {
|
||||
d.ybr[17][x] = 0x7f
|
||||
}
|
||||
for x := 23; x < 32; x++ {
|
||||
d.ybr[17][x] = 0x7f
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < 16; i++ {
|
||||
d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+i]
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
d.ybr[17][8+i] = d.img.Cb[(8*mby-1)*d.img.CStride+8*mbx+i]
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
d.ybr[17][24+i] = d.img.Cr[(8*mby-1)*d.img.CStride+8*mbx+i]
|
||||
}
|
||||
if mbx == d.mbw-1 {
|
||||
for i := 16; i < 20; i++ {
|
||||
d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+15]
|
||||
}
|
||||
} else {
|
||||
for i := 16; i < 20; i++ {
|
||||
d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+i]
|
||||
}
|
||||
}
|
||||
}
|
||||
for y := 4; y < 16; y += 4 {
|
||||
d.ybr[y][24] = d.ybr[0][24]
|
||||
d.ybr[y][25] = d.ybr[0][25]
|
||||
d.ybr[y][26] = d.ybr[0][26]
|
||||
d.ybr[y][27] = d.ybr[0][27]
|
||||
}
|
||||
}
|
||||
|
||||
// btou converts a bool to a 0/1 value.
|
||||
func btou(b bool) uint8 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// pack packs four 0/1 values into four bits of a uint32.
|
||||
func pack(x [4]uint8, shift int) uint32 {
|
||||
u := uint32(x[0])<<0 | uint32(x[1])<<1 | uint32(x[2])<<2 | uint32(x[3])<<3
|
||||
return u << uint(shift)
|
||||
}
|
||||
|
||||
// unpack unpacks four 0/1 values from a four-bit value.
|
||||
var unpack = [16][4]uint8{
|
||||
{0, 0, 0, 0},
|
||||
{1, 0, 0, 0},
|
||||
{0, 1, 0, 0},
|
||||
{1, 1, 0, 0},
|
||||
{0, 0, 1, 0},
|
||||
{1, 0, 1, 0},
|
||||
{0, 1, 1, 0},
|
||||
{1, 1, 1, 0},
|
||||
{0, 0, 0, 1},
|
||||
{1, 0, 0, 1},
|
||||
{0, 1, 0, 1},
|
||||
{1, 1, 0, 1},
|
||||
{0, 0, 1, 1},
|
||||
{1, 0, 1, 1},
|
||||
{0, 1, 1, 1},
|
||||
{1, 1, 1, 1},
|
||||
}
|
||||
|
||||
var (
|
||||
// The mapping from 4x4 region position to band is specified in section 13.3.
|
||||
bands = [17]uint8{0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0}
|
||||
// Category probabilities are specified in section 13.2.
|
||||
// Decoding categories 1 and 2 are done inline.
|
||||
cat3456 = [4][12]uint8{
|
||||
{173, 148, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{176, 155, 140, 135, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{180, 157, 141, 134, 130, 0, 0, 0, 0, 0, 0, 0},
|
||||
{254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0},
|
||||
}
|
||||
// The zigzag order is:
|
||||
// 0 1 5 6
|
||||
// 2 4 7 12
|
||||
// 3 8 11 13
|
||||
// 9 10 14 15
|
||||
zigzag = [16]uint8{0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15}
|
||||
)
|
||||
|
||||
// parseResiduals4 parses a 4x4 region of residual coefficients, as specified
|
||||
// in section 13.3, and returns a 0/1 value indicating whether there was at
|
||||
// least one non-zero coefficient.
|
||||
// r is the partition to read bits from.
|
||||
// plane and context describe which token probability table to use. context is
|
||||
// either 0, 1 or 2, and equals how many of the macroblock left and macroblock
|
||||
// above have non-zero coefficients.
|
||||
// quant are the DC/AC quantization factors.
|
||||
// skipFirstCoeff is whether the DC coefficient has already been parsed.
|
||||
// coeffBase is the base index of d.coeff to write to.
|
||||
func (d *Decoder) parseResiduals4(r *partition, plane int, context uint8, quant [2]uint16, skipFirstCoeff bool, coeffBase int) uint8 {
|
||||
prob, n := &d.tokenProb[plane], 0
|
||||
if skipFirstCoeff {
|
||||
n = 1
|
||||
}
|
||||
p := prob[bands[n]][context]
|
||||
if !r.readBit(p[0]) {
|
||||
return 0
|
||||
}
|
||||
for n != 16 {
|
||||
n++
|
||||
if !r.readBit(p[1]) {
|
||||
p = prob[bands[n]][0]
|
||||
continue
|
||||
}
|
||||
var v uint32
|
||||
if !r.readBit(p[2]) {
|
||||
v = 1
|
||||
p = prob[bands[n]][1]
|
||||
} else {
|
||||
if !r.readBit(p[3]) {
|
||||
if !r.readBit(p[4]) {
|
||||
v = 2
|
||||
} else {
|
||||
v = 3 + r.readUint(p[5], 1)
|
||||
}
|
||||
} else if !r.readBit(p[6]) {
|
||||
if !r.readBit(p[7]) {
|
||||
// Category 1.
|
||||
v = 5 + r.readUint(159, 1)
|
||||
} else {
|
||||
// Category 2.
|
||||
v = 7 + 2*r.readUint(165, 1) + r.readUint(145, 1)
|
||||
}
|
||||
} else {
|
||||
// Categories 3, 4, 5 or 6.
|
||||
b1 := r.readUint(p[8], 1)
|
||||
b0 := r.readUint(p[9+b1], 1)
|
||||
cat := 2*b1 + b0
|
||||
tab := &cat3456[cat]
|
||||
v = 0
|
||||
for i := 0; tab[i] != 0; i++ {
|
||||
v *= 2
|
||||
v += r.readUint(tab[i], 1)
|
||||
}
|
||||
v += 3 + (8 << cat)
|
||||
}
|
||||
p = prob[bands[n]][2]
|
||||
}
|
||||
z := zigzag[n-1]
|
||||
c := int32(v) * int32(quant[btou(z > 0)])
|
||||
if r.readBit(uniformProb) {
|
||||
c = -c
|
||||
}
|
||||
d.coeff[coeffBase+int(z)] = int16(c)
|
||||
if n == 16 || !r.readBit(p[0]) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// parseResiduals parses the residuals and returns whether inner loop filtering
|
||||
// should be skipped for this macroblock.
|
||||
func (d *Decoder) parseResiduals(mbx, mby int) (skip bool) {
|
||||
partition := &d.op[mby&(d.nOP-1)]
|
||||
plane := planeY1SansY2
|
||||
quant := &d.quant[d.segment]
|
||||
|
||||
// Parse the DC coefficient of each 4x4 luma region.
|
||||
if d.usePredY16 {
|
||||
nz := d.parseResiduals4(partition, planeY2, d.leftMB.nzY16+d.upMB[mbx].nzY16, quant.y2, false, whtCoeffBase)
|
||||
d.leftMB.nzY16 = nz
|
||||
d.upMB[mbx].nzY16 = nz
|
||||
d.inverseWHT16()
|
||||
plane = planeY1WithY2
|
||||
}
|
||||
|
||||
var (
|
||||
nzDC, nzAC [4]uint8
|
||||
nzDCMask, nzACMask uint32
|
||||
coeffBase int
|
||||
)
|
||||
|
||||
// Parse the luma coefficients.
|
||||
lnz := unpack[d.leftMB.nzMask&0x0f]
|
||||
unz := unpack[d.upMB[mbx].nzMask&0x0f]
|
||||
for y := 0; y < 4; y++ {
|
||||
nz := lnz[y]
|
||||
for x := 0; x < 4; x++ {
|
||||
nz = d.parseResiduals4(partition, plane, nz+unz[x], quant.y1, d.usePredY16, coeffBase)
|
||||
unz[x] = nz
|
||||
nzAC[x] = nz
|
||||
nzDC[x] = btou(d.coeff[coeffBase] != 0)
|
||||
coeffBase += 16
|
||||
}
|
||||
lnz[y] = nz
|
||||
nzDCMask |= pack(nzDC, y*4)
|
||||
nzACMask |= pack(nzAC, y*4)
|
||||
}
|
||||
lnzMask := pack(lnz, 0)
|
||||
unzMask := pack(unz, 0)
|
||||
|
||||
// Parse the chroma coefficients.
|
||||
lnz = unpack[d.leftMB.nzMask>>4]
|
||||
unz = unpack[d.upMB[mbx].nzMask>>4]
|
||||
for c := 0; c < 4; c += 2 {
|
||||
for y := 0; y < 2; y++ {
|
||||
nz := lnz[y+c]
|
||||
for x := 0; x < 2; x++ {
|
||||
nz = d.parseResiduals4(partition, planeUV, nz+unz[x+c], quant.uv, false, coeffBase)
|
||||
unz[x+c] = nz
|
||||
nzAC[y*2+x] = nz
|
||||
nzDC[y*2+x] = btou(d.coeff[coeffBase] != 0)
|
||||
coeffBase += 16
|
||||
}
|
||||
lnz[y+c] = nz
|
||||
}
|
||||
nzDCMask |= pack(nzDC, 16+c*2)
|
||||
nzACMask |= pack(nzAC, 16+c*2)
|
||||
}
|
||||
lnzMask |= pack(lnz, 4)
|
||||
unzMask |= pack(unz, 4)
|
||||
|
||||
// Save decoder state.
|
||||
d.leftMB.nzMask = uint8(lnzMask)
|
||||
d.upMB[mbx].nzMask = uint8(unzMask)
|
||||
d.nzDCMask = nzDCMask
|
||||
d.nzACMask = nzACMask
|
||||
|
||||
// Section 15.1 of the spec says that "Steps 2 and 4 [of the loop filter]
|
||||
// are skipped... [if] there is no DCT coefficient coded for the whole
|
||||
// macroblock."
|
||||
return nzDCMask == 0 && nzACMask == 0
|
||||
}
|
||||
|
||||
// reconstructMacroblock applies the predictor functions and adds the inverse-
|
||||
// DCT transformed residuals to recover the YCbCr data.
|
||||
func (d *Decoder) reconstructMacroblock(mbx, mby int) {
|
||||
if d.usePredY16 {
|
||||
p := checkTopLeftPred(mbx, mby, d.predY16)
|
||||
predFunc16[p](d, 1, 8)
|
||||
for j := 0; j < 4; j++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
n := 4*j + i
|
||||
y := 4*j + 1
|
||||
x := 4*i + 8
|
||||
mask := uint32(1) << uint(n)
|
||||
if d.nzACMask&mask != 0 {
|
||||
d.inverseDCT4(y, x, 16*n)
|
||||
} else if d.nzDCMask&mask != 0 {
|
||||
d.inverseDCT4DCOnly(y, x, 16*n)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for j := 0; j < 4; j++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
n := 4*j + i
|
||||
y := 4*j + 1
|
||||
x := 4*i + 8
|
||||
predFunc4[d.predY4[j][i]](d, y, x)
|
||||
mask := uint32(1) << uint(n)
|
||||
if d.nzACMask&mask != 0 {
|
||||
d.inverseDCT4(y, x, 16*n)
|
||||
} else if d.nzDCMask&mask != 0 {
|
||||
d.inverseDCT4DCOnly(y, x, 16*n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
p := checkTopLeftPred(mbx, mby, d.predC8)
|
||||
predFunc8[p](d, ybrBY, ybrBX)
|
||||
if d.nzACMask&0x0f0000 != 0 {
|
||||
d.inverseDCT8(ybrBY, ybrBX, bCoeffBase)
|
||||
} else if d.nzDCMask&0x0f0000 != 0 {
|
||||
d.inverseDCT8DCOnly(ybrBY, ybrBX, bCoeffBase)
|
||||
}
|
||||
predFunc8[p](d, ybrRY, ybrRX)
|
||||
if d.nzACMask&0xf00000 != 0 {
|
||||
d.inverseDCT8(ybrRY, ybrRX, rCoeffBase)
|
||||
} else if d.nzDCMask&0xf00000 != 0 {
|
||||
d.inverseDCT8DCOnly(ybrRY, ybrRX, rCoeffBase)
|
||||
}
|
||||
}
|
||||
|
||||
// reconstruct reconstructs one macroblock and returns whether inner loop
|
||||
// filtering should be skipped for it.
|
||||
func (d *Decoder) reconstruct(mbx, mby int) (skip bool) {
|
||||
if d.segmentHeader.updateMap {
|
||||
if !d.fp.readBit(d.segmentHeader.prob[0]) {
|
||||
d.segment = int(d.fp.readUint(d.segmentHeader.prob[1], 1))
|
||||
} else {
|
||||
d.segment = int(d.fp.readUint(d.segmentHeader.prob[2], 1)) + 2
|
||||
}
|
||||
}
|
||||
if d.useSkipProb {
|
||||
skip = d.fp.readBit(d.skipProb)
|
||||
}
|
||||
// Prepare the workspace.
|
||||
for i := range d.coeff {
|
||||
d.coeff[i] = 0
|
||||
}
|
||||
d.prepareYBR(mbx, mby)
|
||||
// Parse the predictor modes.
|
||||
d.usePredY16 = d.fp.readBit(145)
|
||||
if d.usePredY16 {
|
||||
d.parsePredModeY16(mbx)
|
||||
} else {
|
||||
d.parsePredModeY4(mbx)
|
||||
}
|
||||
d.parsePredModeC8()
|
||||
// Parse the residuals.
|
||||
if !skip {
|
||||
skip = d.parseResiduals(mbx, mby)
|
||||
} else {
|
||||
if d.usePredY16 {
|
||||
d.leftMB.nzY16 = 0
|
||||
d.upMB[mbx].nzY16 = 0
|
||||
}
|
||||
d.leftMB.nzMask = 0
|
||||
d.upMB[mbx].nzMask = 0
|
||||
d.nzDCMask = 0
|
||||
d.nzACMask = 0
|
||||
}
|
||||
// Reconstruct the YCbCr data and copy it to the image.
|
||||
d.reconstructMacroblock(mbx, mby)
|
||||
for i, y := (mby*d.img.YStride+mbx)*16, 0; y < 16; i, y = i+d.img.YStride, y+1 {
|
||||
copy(d.img.Y[i:i+16], d.ybr[ybrYY+y][ybrYX:ybrYX+16])
|
||||
}
|
||||
for i, y := (mby*d.img.CStride+mbx)*8, 0; y < 8; i, y = i+d.img.CStride, y+1 {
|
||||
copy(d.img.Cb[i:i+8], d.ybr[ybrBY+y][ybrBX:ybrBX+8])
|
||||
copy(d.img.Cr[i:i+8], d.ybr[ybrRY+y][ybrRX:ybrRX+8])
|
||||
}
|
||||
return skip
|
||||
}
|
||||
+381
@@ -0,0 +1,381 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8
|
||||
|
||||
// This file contains token probabilities for decoding DCT/WHT coefficients, as
|
||||
// specified in chapter 13.
|
||||
|
||||
func (d *Decoder) parseTokenProb() {
|
||||
for i := range d.tokenProb {
|
||||
for j := range d.tokenProb[i] {
|
||||
for k := range d.tokenProb[i][j] {
|
||||
for l := range d.tokenProb[i][j][k] {
|
||||
if d.fp.readBit(tokenProbUpdateProb[i][j][k][l]) {
|
||||
d.tokenProb[i][j][k][l] = uint8(d.fp.readUint(uniformProb, 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The plane enumeration is specified in section 13.3.
|
||||
const (
|
||||
planeY1WithY2 = iota
|
||||
planeY2
|
||||
planeUV
|
||||
planeY1SansY2
|
||||
nPlane
|
||||
)
|
||||
|
||||
const (
|
||||
nBand = 8
|
||||
nContext = 3
|
||||
nProb = 11
|
||||
)
|
||||
|
||||
// Token probability update probabilities are specified in section 13.4.
|
||||
var tokenProbUpdateProb = [nPlane][nBand][nContext][nProb]uint8{
|
||||
{
|
||||
{
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255},
|
||||
{250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255},
|
||||
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
{217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255},
|
||||
{234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
{186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255},
|
||||
{251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
{248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255},
|
||||
{248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
{
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Default token probabilities are specified in section 13.5.
|
||||
var defaultTokenProb = [nPlane][nBand][nContext][nProb]uint8{
|
||||
{
|
||||
{
|
||||
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128},
|
||||
{189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128},
|
||||
{106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128},
|
||||
{181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128},
|
||||
{78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128},
|
||||
{184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128},
|
||||
{77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128},
|
||||
{170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128},
|
||||
{37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128},
|
||||
{207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128},
|
||||
{102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128},
|
||||
{177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128},
|
||||
{80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
{198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62},
|
||||
{131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1},
|
||||
{68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128},
|
||||
},
|
||||
{
|
||||
{1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128},
|
||||
{184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128},
|
||||
{81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128},
|
||||
},
|
||||
{
|
||||
{1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128},
|
||||
{99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128},
|
||||
{23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128},
|
||||
},
|
||||
{
|
||||
{1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128},
|
||||
{109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128},
|
||||
{44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128},
|
||||
{94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128},
|
||||
{22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128},
|
||||
{124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128},
|
||||
{35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128},
|
||||
{121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128},
|
||||
{45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128},
|
||||
{203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128},
|
||||
{137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128},
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
{253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128},
|
||||
{175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128},
|
||||
{73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128},
|
||||
},
|
||||
{
|
||||
{1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128},
|
||||
{239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128},
|
||||
{155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128},
|
||||
{201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128},
|
||||
{69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128},
|
||||
{223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128},
|
||||
{141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128},
|
||||
{190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128},
|
||||
{149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128},
|
||||
{213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128},
|
||||
{55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
{202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255},
|
||||
{126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128},
|
||||
{61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128},
|
||||
},
|
||||
{
|
||||
{1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128},
|
||||
{166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128},
|
||||
{39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128},
|
||||
},
|
||||
{
|
||||
{1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128},
|
||||
{124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128},
|
||||
{24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128},
|
||||
},
|
||||
{
|
||||
{1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128},
|
||||
{149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128},
|
||||
{28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128},
|
||||
},
|
||||
{
|
||||
{1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128},
|
||||
{123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128},
|
||||
{20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128},
|
||||
{168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128},
|
||||
{47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128},
|
||||
{141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128},
|
||||
{42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128},
|
||||
},
|
||||
{
|
||||
{1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
{238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
|
||||
},
|
||||
},
|
||||
}
|
||||
+603
@@ -0,0 +1,603 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package vp8l implements a decoder for the VP8L lossless image format.
|
||||
//
|
||||
// The VP8L specification is at:
|
||||
// https://developers.google.com/speed/webp/docs/riff_container
|
||||
package vp8l // import "golang.org/x/image/vp8l"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidCodeLengths = errors.New("vp8l: invalid code lengths")
|
||||
errInvalidHuffmanTree = errors.New("vp8l: invalid Huffman tree")
|
||||
)
|
||||
|
||||
// colorCacheMultiplier is the multiplier used for the color cache hash
|
||||
// function, specified in section 4.2.3.
|
||||
const colorCacheMultiplier = 0x1e35a7bd
|
||||
|
||||
// distanceMapTable is the look-up table for distanceMap.
|
||||
var distanceMapTable = [120]uint8{
|
||||
0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
|
||||
0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
|
||||
0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
|
||||
0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
|
||||
0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
|
||||
0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
|
||||
0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
|
||||
0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
|
||||
0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
|
||||
0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
|
||||
0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
|
||||
0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70,
|
||||
}
|
||||
|
||||
// distanceMap maps a LZ77 backwards reference distance to a two-dimensional
|
||||
// pixel offset, specified in section 4.2.2.
|
||||
func distanceMap(w int32, code uint32) int32 {
|
||||
if int32(code) > int32(len(distanceMapTable)) {
|
||||
return int32(code) - int32(len(distanceMapTable))
|
||||
}
|
||||
distCode := int32(distanceMapTable[code-1])
|
||||
yOffset := distCode >> 4
|
||||
xOffset := 8 - distCode&0xf
|
||||
if d := yOffset*w + xOffset; d >= 1 {
|
||||
return d
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
// decoder holds the bit-stream for a VP8L image.
|
||||
type decoder struct {
|
||||
r io.ByteReader
|
||||
bits uint32
|
||||
nBits uint32
|
||||
}
|
||||
|
||||
// read reads the next n bits from the decoder's bit-stream.
|
||||
func (d *decoder) read(n uint32) (uint32, error) {
|
||||
for d.nBits < n {
|
||||
c, err := d.r.ReadByte()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
d.bits |= uint32(c) << d.nBits
|
||||
d.nBits += 8
|
||||
}
|
||||
u := d.bits & (1<<n - 1)
|
||||
d.bits >>= n
|
||||
d.nBits -= n
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// decodeTransform decodes the next transform and the width of the image after
|
||||
// transformation (or equivalently, before inverse transformation), specified
|
||||
// in section 3.
|
||||
func (d *decoder) decodeTransform(w int32, h int32) (t transform, newWidth int32, err error) {
|
||||
t.oldWidth = w
|
||||
t.transformType, err = d.read(2)
|
||||
if err != nil {
|
||||
return transform{}, 0, err
|
||||
}
|
||||
switch t.transformType {
|
||||
case transformTypePredictor, transformTypeCrossColor:
|
||||
t.bits, err = d.read(3)
|
||||
if err != nil {
|
||||
return transform{}, 0, err
|
||||
}
|
||||
t.bits += 2
|
||||
t.pix, err = d.decodePix(nTiles(w, t.bits), nTiles(h, t.bits), 0, false)
|
||||
if err != nil {
|
||||
return transform{}, 0, err
|
||||
}
|
||||
case transformTypeSubtractGreen:
|
||||
// No-op.
|
||||
case transformTypeColorIndexing:
|
||||
nColors, err := d.read(8)
|
||||
if err != nil {
|
||||
return transform{}, 0, err
|
||||
}
|
||||
nColors++
|
||||
t.bits = 0
|
||||
switch {
|
||||
case nColors <= 2:
|
||||
t.bits = 3
|
||||
case nColors <= 4:
|
||||
t.bits = 2
|
||||
case nColors <= 16:
|
||||
t.bits = 1
|
||||
}
|
||||
w = nTiles(w, t.bits)
|
||||
pix, err := d.decodePix(int32(nColors), 1, 4*256, false)
|
||||
if err != nil {
|
||||
return transform{}, 0, err
|
||||
}
|
||||
for p := 4; p < len(pix); p += 4 {
|
||||
pix[p+0] += pix[p-4]
|
||||
pix[p+1] += pix[p-3]
|
||||
pix[p+2] += pix[p-2]
|
||||
pix[p+3] += pix[p-1]
|
||||
}
|
||||
// The spec says that "if the index is equal or larger than color_table_size,
|
||||
// the argb color value should be set to 0x00000000 (transparent black)."
|
||||
// We re-slice up to 256 4-byte pixels.
|
||||
t.pix = pix[:4*256]
|
||||
}
|
||||
return t, w, nil
|
||||
}
|
||||
|
||||
// repeatsCodeLength is the minimum code length for repeated codes.
|
||||
const repeatsCodeLength = 16
|
||||
|
||||
// These magic numbers are specified at the end of section 5.2.2.
|
||||
// The 3-length arrays apply to code lengths >= repeatsCodeLength.
|
||||
var (
|
||||
codeLengthCodeOrder = [19]uint8{
|
||||
17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
}
|
||||
repeatBits = [3]uint8{2, 3, 7}
|
||||
repeatOffsets = [3]uint8{3, 3, 11}
|
||||
)
|
||||
|
||||
// decodeCodeLengths decodes a Huffman tree's code lengths which are themselves
|
||||
// encoded via a Huffman tree, specified in section 5.2.2.
|
||||
func (d *decoder) decodeCodeLengths(dst []uint32, codeLengthCodeLengths []uint32) error {
|
||||
h := hTree{}
|
||||
if err := h.build(codeLengthCodeLengths); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
maxSymbol := len(dst)
|
||||
useLength, err := d.read(1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if useLength != 0 {
|
||||
n, err := d.read(3)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n = 2 + 2*n
|
||||
ms, err := d.read(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
maxSymbol = int(ms) + 2
|
||||
if maxSymbol > len(dst) {
|
||||
return errInvalidCodeLengths
|
||||
}
|
||||
}
|
||||
|
||||
// The spec says that "if code 16 [meaning repeat] is used before
|
||||
// a non-zero value has been emitted, a value of 8 is repeated."
|
||||
prevCodeLength := uint32(8)
|
||||
|
||||
for symbol := 0; symbol < len(dst); {
|
||||
if maxSymbol == 0 {
|
||||
break
|
||||
}
|
||||
maxSymbol--
|
||||
codeLength, err := h.next(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if codeLength < repeatsCodeLength {
|
||||
dst[symbol] = codeLength
|
||||
symbol++
|
||||
if codeLength != 0 {
|
||||
prevCodeLength = codeLength
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
repeat, err := d.read(uint32(repeatBits[codeLength-repeatsCodeLength]))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repeat += uint32(repeatOffsets[codeLength-repeatsCodeLength])
|
||||
if symbol+int(repeat) > len(dst) {
|
||||
return errInvalidCodeLengths
|
||||
}
|
||||
// A code length of 16 repeats the previous non-zero code.
|
||||
// A code length of 17 or 18 repeats zeroes.
|
||||
cl := uint32(0)
|
||||
if codeLength == 16 {
|
||||
cl = prevCodeLength
|
||||
}
|
||||
for ; repeat > 0; repeat-- {
|
||||
dst[symbol] = cl
|
||||
symbol++
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// decodeHuffmanTree decodes a Huffman tree into h.
|
||||
func (d *decoder) decodeHuffmanTree(h *hTree, alphabetSize uint32) error {
|
||||
useSimple, err := d.read(1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if useSimple != 0 {
|
||||
nSymbols, err := d.read(1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nSymbols++
|
||||
firstSymbolLengthCode, err := d.read(1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
firstSymbolLengthCode = 7*firstSymbolLengthCode + 1
|
||||
var symbols [2]uint32
|
||||
symbols[0], err = d.read(firstSymbolLengthCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nSymbols == 2 {
|
||||
symbols[1], err = d.read(8)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return h.buildSimple(nSymbols, symbols, alphabetSize)
|
||||
}
|
||||
|
||||
nCodes, err := d.read(4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nCodes += 4
|
||||
if int(nCodes) > len(codeLengthCodeOrder) {
|
||||
return errInvalidHuffmanTree
|
||||
}
|
||||
codeLengthCodeLengths := [len(codeLengthCodeOrder)]uint32{}
|
||||
for i := uint32(0); i < nCodes; i++ {
|
||||
codeLengthCodeLengths[codeLengthCodeOrder[i]], err = d.read(3)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
codeLengths := make([]uint32, alphabetSize)
|
||||
if err = d.decodeCodeLengths(codeLengths, codeLengthCodeLengths[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return h.build(codeLengths)
|
||||
}
|
||||
|
||||
const (
|
||||
huffGreen = 0
|
||||
huffRed = 1
|
||||
huffBlue = 2
|
||||
huffAlpha = 3
|
||||
huffDistance = 4
|
||||
nHuff = 5
|
||||
)
|
||||
|
||||
// hGroup is an array of 5 Huffman trees.
|
||||
type hGroup [nHuff]hTree
|
||||
|
||||
// decodeHuffmanGroups decodes the one or more hGroups used to decode the pixel
|
||||
// data. If one hGroup is used for the entire image, then hPix and hBits will
|
||||
// be zero. If more than one hGroup is used, then hPix contains the meta-image
|
||||
// that maps tiles to hGroup index, and hBits contains the log-2 tile size.
|
||||
func (d *decoder) decodeHuffmanGroups(w int32, h int32, topLevel bool, ccBits uint32) (
|
||||
hGroups []hGroup, hPix []byte, hBits uint32, err error) {
|
||||
|
||||
maxHGroupIndex := 0
|
||||
if topLevel {
|
||||
useMeta, err := d.read(1)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
if useMeta != 0 {
|
||||
hBits, err = d.read(3)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
hBits += 2
|
||||
hPix, err = d.decodePix(nTiles(w, hBits), nTiles(h, hBits), 0, false)
|
||||
if err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
for p := 0; p < len(hPix); p += 4 {
|
||||
i := int(hPix[p])<<8 | int(hPix[p+1])
|
||||
if maxHGroupIndex < i {
|
||||
maxHGroupIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hGroups = make([]hGroup, maxHGroupIndex+1)
|
||||
for i := range hGroups {
|
||||
for j, alphabetSize := range alphabetSizes {
|
||||
if j == 0 && ccBits > 0 {
|
||||
alphabetSize += 1 << ccBits
|
||||
}
|
||||
if err := d.decodeHuffmanTree(&hGroups[i][j], alphabetSize); err != nil {
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return hGroups, hPix, hBits, nil
|
||||
}
|
||||
|
||||
const (
|
||||
nLiteralCodes = 256
|
||||
nLengthCodes = 24
|
||||
nDistanceCodes = 40
|
||||
)
|
||||
|
||||
var alphabetSizes = [nHuff]uint32{
|
||||
nLiteralCodes + nLengthCodes,
|
||||
nLiteralCodes,
|
||||
nLiteralCodes,
|
||||
nLiteralCodes,
|
||||
nDistanceCodes,
|
||||
}
|
||||
|
||||
// decodePix decodes pixel data, specified in section 5.2.2.
|
||||
func (d *decoder) decodePix(w int32, h int32, minCap int32, topLevel bool) ([]byte, error) {
|
||||
// Decode the color cache parameters.
|
||||
ccBits, ccShift, ccEntries := uint32(0), uint32(0), ([]uint32)(nil)
|
||||
useColorCache, err := d.read(1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if useColorCache != 0 {
|
||||
ccBits, err = d.read(4)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ccBits < 1 || 11 < ccBits {
|
||||
return nil, errors.New("vp8l: invalid color cache parameters")
|
||||
}
|
||||
ccShift = 32 - ccBits
|
||||
ccEntries = make([]uint32, 1<<ccBits)
|
||||
}
|
||||
|
||||
// Decode the Huffman groups.
|
||||
hGroups, hPix, hBits, err := d.decodeHuffmanGroups(w, h, topLevel, ccBits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hMask, tilesPerRow := int32(0), int32(0)
|
||||
if hBits != 0 {
|
||||
hMask, tilesPerRow = 1<<hBits-1, nTiles(w, hBits)
|
||||
}
|
||||
|
||||
// Decode the pixels.
|
||||
if minCap < 4*w*h {
|
||||
minCap = 4 * w * h
|
||||
}
|
||||
pix := make([]byte, 4*w*h, minCap)
|
||||
p, cachedP := 0, 0
|
||||
x, y := int32(0), int32(0)
|
||||
hg, lookupHG := &hGroups[0], hMask != 0
|
||||
for p < len(pix) {
|
||||
if lookupHG {
|
||||
i := 4 * (tilesPerRow*(y>>hBits) + (x >> hBits))
|
||||
hg = &hGroups[uint32(hPix[i])<<8|uint32(hPix[i+1])]
|
||||
}
|
||||
|
||||
green, err := hg[huffGreen].next(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch {
|
||||
case green < nLiteralCodes:
|
||||
// We have a literal pixel.
|
||||
red, err := hg[huffRed].next(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blue, err := hg[huffBlue].next(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
alpha, err := hg[huffAlpha].next(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pix[p+0] = uint8(red)
|
||||
pix[p+1] = uint8(green)
|
||||
pix[p+2] = uint8(blue)
|
||||
pix[p+3] = uint8(alpha)
|
||||
p += 4
|
||||
|
||||
x++
|
||||
if x == w {
|
||||
x, y = 0, y+1
|
||||
}
|
||||
lookupHG = hMask != 0 && x&hMask == 0
|
||||
|
||||
case green < nLiteralCodes+nLengthCodes:
|
||||
// We have a LZ77 backwards reference.
|
||||
length, err := d.lz77Param(green - nLiteralCodes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
distSym, err := hg[huffDistance].next(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
distCode, err := d.lz77Param(distSym)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dist := distanceMap(w, distCode)
|
||||
pEnd := p + 4*int(length)
|
||||
q := p - 4*int(dist)
|
||||
qEnd := pEnd - 4*int(dist)
|
||||
if p < 0 || len(pix) < pEnd || q < 0 || len(pix) < qEnd {
|
||||
return nil, errors.New("vp8l: invalid LZ77 parameters")
|
||||
}
|
||||
for ; p < pEnd; p, q = p+1, q+1 {
|
||||
pix[p] = pix[q]
|
||||
}
|
||||
|
||||
x += int32(length)
|
||||
for x >= w {
|
||||
x, y = x-w, y+1
|
||||
}
|
||||
lookupHG = hMask != 0
|
||||
|
||||
default:
|
||||
// We have a color cache lookup. First, insert previous pixels
|
||||
// into the cache. Note that VP8L assumes ARGB order, but the
|
||||
// Go image.RGBA type is in RGBA order.
|
||||
for ; cachedP < p; cachedP += 4 {
|
||||
argb := uint32(pix[cachedP+0])<<16 |
|
||||
uint32(pix[cachedP+1])<<8 |
|
||||
uint32(pix[cachedP+2])<<0 |
|
||||
uint32(pix[cachedP+3])<<24
|
||||
ccEntries[(argb*colorCacheMultiplier)>>ccShift] = argb
|
||||
}
|
||||
green -= nLiteralCodes + nLengthCodes
|
||||
if int(green) >= len(ccEntries) {
|
||||
return nil, errors.New("vp8l: invalid color cache index")
|
||||
}
|
||||
argb := ccEntries[green]
|
||||
pix[p+0] = uint8(argb >> 16)
|
||||
pix[p+1] = uint8(argb >> 8)
|
||||
pix[p+2] = uint8(argb >> 0)
|
||||
pix[p+3] = uint8(argb >> 24)
|
||||
p += 4
|
||||
|
||||
x++
|
||||
if x == w {
|
||||
x, y = 0, y+1
|
||||
}
|
||||
lookupHG = hMask != 0 && x&hMask == 0
|
||||
}
|
||||
}
|
||||
return pix, nil
|
||||
}
|
||||
|
||||
// lz77Param returns the next LZ77 parameter: a length or a distance, specified
|
||||
// in section 4.2.2.
|
||||
func (d *decoder) lz77Param(symbol uint32) (uint32, error) {
|
||||
if symbol < 4 {
|
||||
return symbol + 1, nil
|
||||
}
|
||||
extraBits := (symbol - 2) >> 1
|
||||
offset := (2 + symbol&1) << extraBits
|
||||
n, err := d.read(extraBits)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return offset + n + 1, nil
|
||||
}
|
||||
|
||||
// decodeHeader decodes the VP8L header from r.
|
||||
func decodeHeader(r io.Reader) (d *decoder, w int32, h int32, err error) {
|
||||
rr, ok := r.(io.ByteReader)
|
||||
if !ok {
|
||||
rr = bufio.NewReader(r)
|
||||
}
|
||||
d = &decoder{r: rr}
|
||||
magic, err := d.read(8)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if magic != 0x2f {
|
||||
return nil, 0, 0, errors.New("vp8l: invalid header")
|
||||
}
|
||||
width, err := d.read(14)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
width++
|
||||
height, err := d.read(14)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
height++
|
||||
_, err = d.read(1) // Read and ignore the hasAlpha hint.
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
version, err := d.read(3)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if version != 0 {
|
||||
return nil, 0, 0, errors.New("vp8l: invalid version")
|
||||
}
|
||||
return d, int32(width), int32(height), nil
|
||||
}
|
||||
|
||||
// DecodeConfig decodes the color model and dimensions of a VP8L image from r.
|
||||
func DecodeConfig(r io.Reader) (image.Config, error) {
|
||||
_, w, h, err := decodeHeader(r)
|
||||
if err != nil {
|
||||
return image.Config{}, err
|
||||
}
|
||||
return image.Config{
|
||||
ColorModel: color.NRGBAModel,
|
||||
Width: int(w),
|
||||
Height: int(h),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Decode decodes a VP8L image from r.
|
||||
func Decode(r io.Reader) (image.Image, error) {
|
||||
d, w, h, err := decodeHeader(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Decode the transforms.
|
||||
var (
|
||||
nTransforms int
|
||||
transforms [nTransformTypes]transform
|
||||
transformsSeen [nTransformTypes]bool
|
||||
originalW = w
|
||||
)
|
||||
for {
|
||||
more, err := d.read(1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if more == 0 {
|
||||
break
|
||||
}
|
||||
var t transform
|
||||
t, w, err = d.decodeTransform(w, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if transformsSeen[t.transformType] {
|
||||
return nil, errors.New("vp8l: repeated transform")
|
||||
}
|
||||
transformsSeen[t.transformType] = true
|
||||
transforms[nTransforms] = t
|
||||
nTransforms++
|
||||
}
|
||||
// Decode the transformed pixels.
|
||||
pix, err := d.decodePix(w, h, 0, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Apply the inverse transformations.
|
||||
for i := nTransforms - 1; i >= 0; i-- {
|
||||
t := &transforms[i]
|
||||
pix = inverseTransforms[t.transformType](t, pix, h)
|
||||
}
|
||||
return &image.NRGBA{
|
||||
Pix: pix,
|
||||
Stride: 4 * int(originalW),
|
||||
Rect: image.Rect(0, 0, int(originalW), int(h)),
|
||||
}, nil
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8l
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// reverseBits reverses the bits in a byte.
|
||||
var reverseBits = [256]uint8{
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
|
||||
}
|
||||
|
||||
// hNode is a node in a Huffman tree.
|
||||
type hNode struct {
|
||||
// symbol is the symbol held by this node.
|
||||
symbol uint32
|
||||
// children, if positive, is the hTree.nodes index of the first of
|
||||
// this node's two children. Zero means an uninitialized node,
|
||||
// and -1 means a leaf node.
|
||||
children int32
|
||||
}
|
||||
|
||||
const leafNode = -1
|
||||
|
||||
// lutSize is the log-2 size of an hTree's look-up table.
|
||||
const lutSize, lutMask = 7, 1<<7 - 1
|
||||
|
||||
// hTree is a Huffman tree.
|
||||
type hTree struct {
|
||||
// nodes are the nodes of the Huffman tree. During construction,
|
||||
// len(nodes) grows from 1 up to cap(nodes) by steps of two.
|
||||
// After construction, len(nodes) == cap(nodes), and both equal
|
||||
// 2*theNumberOfSymbols - 1.
|
||||
nodes []hNode
|
||||
// lut is a look-up table for walking the nodes. The x in lut[x] is
|
||||
// the next lutSize bits in the bit-stream. The low 8 bits of lut[x]
|
||||
// equals 1 plus the number of bits in the next code, or 0 if the
|
||||
// next code requires more than lutSize bits. The high 24 bits are:
|
||||
// - the symbol, if the code requires lutSize or fewer bits, or
|
||||
// - the hTree.nodes index to start the tree traversal from, if
|
||||
// the next code requires more than lutSize bits.
|
||||
lut [1 << lutSize]uint32
|
||||
}
|
||||
|
||||
// insert inserts into the hTree a symbol whose encoding is the least
|
||||
// significant codeLength bits of code.
|
||||
func (h *hTree) insert(symbol uint32, code uint32, codeLength uint32) error {
|
||||
if symbol > 0xffff || codeLength > 0xfe {
|
||||
return errInvalidHuffmanTree
|
||||
}
|
||||
baseCode := uint32(0)
|
||||
if codeLength > lutSize {
|
||||
baseCode = uint32(reverseBits[(code>>(codeLength-lutSize))&0xff]) >> (8 - lutSize)
|
||||
} else {
|
||||
baseCode = uint32(reverseBits[code&0xff]) >> (8 - codeLength)
|
||||
for i := 0; i < 1<<(lutSize-codeLength); i++ {
|
||||
h.lut[baseCode|uint32(i)<<codeLength] = symbol<<8 | (codeLength + 1)
|
||||
}
|
||||
}
|
||||
|
||||
n := uint32(0)
|
||||
for jump := lutSize; codeLength > 0; {
|
||||
codeLength--
|
||||
if int(n) > len(h.nodes) {
|
||||
return errInvalidHuffmanTree
|
||||
}
|
||||
switch h.nodes[n].children {
|
||||
case leafNode:
|
||||
return errInvalidHuffmanTree
|
||||
case 0:
|
||||
if len(h.nodes) == cap(h.nodes) {
|
||||
return errInvalidHuffmanTree
|
||||
}
|
||||
// Create two empty child nodes.
|
||||
h.nodes[n].children = int32(len(h.nodes))
|
||||
h.nodes = h.nodes[:len(h.nodes)+2]
|
||||
}
|
||||
n = uint32(h.nodes[n].children) + 1&(code>>codeLength)
|
||||
jump--
|
||||
if jump == 0 && h.lut[baseCode] == 0 {
|
||||
h.lut[baseCode] = n << 8
|
||||
}
|
||||
}
|
||||
|
||||
switch h.nodes[n].children {
|
||||
case leafNode:
|
||||
// No-op.
|
||||
case 0:
|
||||
// Turn the uninitialized node into a leaf.
|
||||
h.nodes[n].children = leafNode
|
||||
default:
|
||||
return errInvalidHuffmanTree
|
||||
}
|
||||
h.nodes[n].symbol = symbol
|
||||
return nil
|
||||
}
|
||||
|
||||
// codeLengthsToCodes returns the canonical Huffman codes implied by the
|
||||
// sequence of code lengths.
|
||||
func codeLengthsToCodes(codeLengths []uint32) ([]uint32, error) {
|
||||
maxCodeLength := uint32(0)
|
||||
for _, cl := range codeLengths {
|
||||
if maxCodeLength < cl {
|
||||
maxCodeLength = cl
|
||||
}
|
||||
}
|
||||
const maxAllowedCodeLength = 15
|
||||
if len(codeLengths) == 0 || maxCodeLength > maxAllowedCodeLength {
|
||||
return nil, errInvalidHuffmanTree
|
||||
}
|
||||
histogram := [maxAllowedCodeLength + 1]uint32{}
|
||||
for _, cl := range codeLengths {
|
||||
histogram[cl]++
|
||||
}
|
||||
currCode, nextCodes := uint32(0), [maxAllowedCodeLength + 1]uint32{}
|
||||
for cl := 1; cl < len(nextCodes); cl++ {
|
||||
currCode = (currCode + histogram[cl-1]) << 1
|
||||
nextCodes[cl] = currCode
|
||||
}
|
||||
codes := make([]uint32, len(codeLengths))
|
||||
for symbol, cl := range codeLengths {
|
||||
if cl > 0 {
|
||||
codes[symbol] = nextCodes[cl]
|
||||
nextCodes[cl]++
|
||||
}
|
||||
}
|
||||
return codes, nil
|
||||
}
|
||||
|
||||
// build builds a canonical Huffman tree from the given code lengths.
|
||||
func (h *hTree) build(codeLengths []uint32) error {
|
||||
// Calculate the number of symbols.
|
||||
var nSymbols, lastSymbol uint32
|
||||
for symbol, cl := range codeLengths {
|
||||
if cl != 0 {
|
||||
nSymbols++
|
||||
lastSymbol = uint32(symbol)
|
||||
}
|
||||
}
|
||||
if nSymbols == 0 {
|
||||
return errInvalidHuffmanTree
|
||||
}
|
||||
h.nodes = make([]hNode, 1, 2*nSymbols-1)
|
||||
// Handle the trivial case.
|
||||
if nSymbols == 1 {
|
||||
if len(codeLengths) <= int(lastSymbol) {
|
||||
return errInvalidHuffmanTree
|
||||
}
|
||||
return h.insert(lastSymbol, 0, 0)
|
||||
}
|
||||
// Handle the non-trivial case.
|
||||
codes, err := codeLengthsToCodes(codeLengths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for symbol, cl := range codeLengths {
|
||||
if cl > 0 {
|
||||
if err := h.insert(uint32(symbol), codes[symbol], cl); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildSimple builds a Huffman tree with 1 or 2 symbols.
|
||||
func (h *hTree) buildSimple(nSymbols uint32, symbols [2]uint32, alphabetSize uint32) error {
|
||||
h.nodes = make([]hNode, 1, 2*nSymbols-1)
|
||||
for i := uint32(0); i < nSymbols; i++ {
|
||||
if symbols[i] >= alphabetSize {
|
||||
return errInvalidHuffmanTree
|
||||
}
|
||||
if err := h.insert(symbols[i], i, nSymbols-1); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// next returns the next Huffman-encoded symbol from the bit-stream d.
|
||||
func (h *hTree) next(d *decoder) (uint32, error) {
|
||||
var n uint32
|
||||
// Read enough bits so that we can use the look-up table.
|
||||
if d.nBits < lutSize {
|
||||
c, err := d.r.ReadByte()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
// There are no more bytes of data, but we may still be able
|
||||
// to read the next symbol out of the previously read bits.
|
||||
goto slowPath
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
d.bits |= uint32(c) << d.nBits
|
||||
d.nBits += 8
|
||||
}
|
||||
// Use the look-up table.
|
||||
n = h.lut[d.bits&lutMask]
|
||||
if b := n & 0xff; b != 0 {
|
||||
b--
|
||||
d.bits >>= b
|
||||
d.nBits -= b
|
||||
return n >> 8, nil
|
||||
}
|
||||
n >>= 8
|
||||
d.bits >>= lutSize
|
||||
d.nBits -= lutSize
|
||||
|
||||
slowPath:
|
||||
for h.nodes[n].children != leafNode {
|
||||
if d.nBits == 0 {
|
||||
c, err := d.r.ReadByte()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
d.bits = uint32(c)
|
||||
d.nBits = 8
|
||||
}
|
||||
n = uint32(h.nodes[n].children) + 1&d.bits
|
||||
d.bits >>= 1
|
||||
d.nBits--
|
||||
}
|
||||
return h.nodes[n].symbol, nil
|
||||
}
|
||||
+299
@@ -0,0 +1,299 @@
|
||||
// Copyright 2014 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vp8l
|
||||
|
||||
// This file deals with image transforms, specified in section 3.
|
||||
|
||||
// nTiles returns the number of tiles needed to cover size pixels, where each
|
||||
// tile's side is 1<<bits pixels long.
|
||||
func nTiles(size int32, bits uint32) int32 {
|
||||
return (size + 1<<bits - 1) >> bits
|
||||
}
|
||||
|
||||
const (
|
||||
transformTypePredictor = 0
|
||||
transformTypeCrossColor = 1
|
||||
transformTypeSubtractGreen = 2
|
||||
transformTypeColorIndexing = 3
|
||||
nTransformTypes = 4
|
||||
)
|
||||
|
||||
// transform holds the parameters for an invertible transform.
|
||||
type transform struct {
|
||||
// transformType is the type of the transform.
|
||||
transformType uint32
|
||||
// oldWidth is the width of the image before transformation (or
|
||||
// equivalently, after inverse transformation). The color-indexing
|
||||
// transform can reduce the width. For example, a 50-pixel-wide
|
||||
// image that only needs 4 bits (half a byte) per color index can
|
||||
// be transformed into a 25-pixel-wide image.
|
||||
oldWidth int32
|
||||
// bits is the log-2 size of the transform's tiles, for the predictor
|
||||
// and cross-color transforms. 8>>bits is the number of bits per
|
||||
// color index, for the color-index transform.
|
||||
bits uint32
|
||||
// pix is the tile values, for the predictor and cross-color
|
||||
// transforms, and the color palette, for the color-index transform.
|
||||
pix []byte
|
||||
}
|
||||
|
||||
var inverseTransforms = [nTransformTypes]func(*transform, []byte, int32) []byte{
|
||||
transformTypePredictor: inversePredictor,
|
||||
transformTypeCrossColor: inverseCrossColor,
|
||||
transformTypeSubtractGreen: inverseSubtractGreen,
|
||||
transformTypeColorIndexing: inverseColorIndexing,
|
||||
}
|
||||
|
||||
func inversePredictor(t *transform, pix []byte, h int32) []byte {
|
||||
if t.oldWidth == 0 || h == 0 {
|
||||
return pix
|
||||
}
|
||||
// The first pixel's predictor is mode 0 (opaque black).
|
||||
pix[3] += 0xff
|
||||
p, mask := int32(4), int32(1)<<t.bits-1
|
||||
for x := int32(1); x < t.oldWidth; x++ {
|
||||
// The rest of the first row's predictor is mode 1 (L).
|
||||
pix[p+0] += pix[p-4]
|
||||
pix[p+1] += pix[p-3]
|
||||
pix[p+2] += pix[p-2]
|
||||
pix[p+3] += pix[p-1]
|
||||
p += 4
|
||||
}
|
||||
top, tilesPerRow := 0, nTiles(t.oldWidth, t.bits)
|
||||
for y := int32(1); y < h; y++ {
|
||||
// The first column's predictor is mode 2 (T).
|
||||
pix[p+0] += pix[top+0]
|
||||
pix[p+1] += pix[top+1]
|
||||
pix[p+2] += pix[top+2]
|
||||
pix[p+3] += pix[top+3]
|
||||
p, top = p+4, top+4
|
||||
|
||||
q := 4 * (y >> t.bits) * tilesPerRow
|
||||
predictorMode := t.pix[q+1] & 0x0f
|
||||
q += 4
|
||||
for x := int32(1); x < t.oldWidth; x++ {
|
||||
if x&mask == 0 {
|
||||
predictorMode = t.pix[q+1] & 0x0f
|
||||
q += 4
|
||||
}
|
||||
switch predictorMode {
|
||||
case 0: // Opaque black.
|
||||
pix[p+3] += 0xff
|
||||
|
||||
case 1: // L.
|
||||
pix[p+0] += pix[p-4]
|
||||
pix[p+1] += pix[p-3]
|
||||
pix[p+2] += pix[p-2]
|
||||
pix[p+3] += pix[p-1]
|
||||
|
||||
case 2: // T.
|
||||
pix[p+0] += pix[top+0]
|
||||
pix[p+1] += pix[top+1]
|
||||
pix[p+2] += pix[top+2]
|
||||
pix[p+3] += pix[top+3]
|
||||
|
||||
case 3: // TR.
|
||||
pix[p+0] += pix[top+4]
|
||||
pix[p+1] += pix[top+5]
|
||||
pix[p+2] += pix[top+6]
|
||||
pix[p+3] += pix[top+7]
|
||||
|
||||
case 4: // TL.
|
||||
pix[p+0] += pix[top-4]
|
||||
pix[p+1] += pix[top-3]
|
||||
pix[p+2] += pix[top-2]
|
||||
pix[p+3] += pix[top-1]
|
||||
|
||||
case 5: // Average2(Average2(L, TR), T).
|
||||
pix[p+0] += avg2(avg2(pix[p-4], pix[top+4]), pix[top+0])
|
||||
pix[p+1] += avg2(avg2(pix[p-3], pix[top+5]), pix[top+1])
|
||||
pix[p+2] += avg2(avg2(pix[p-2], pix[top+6]), pix[top+2])
|
||||
pix[p+3] += avg2(avg2(pix[p-1], pix[top+7]), pix[top+3])
|
||||
|
||||
case 6: // Average2(L, TL).
|
||||
pix[p+0] += avg2(pix[p-4], pix[top-4])
|
||||
pix[p+1] += avg2(pix[p-3], pix[top-3])
|
||||
pix[p+2] += avg2(pix[p-2], pix[top-2])
|
||||
pix[p+3] += avg2(pix[p-1], pix[top-1])
|
||||
|
||||
case 7: // Average2(L, T).
|
||||
pix[p+0] += avg2(pix[p-4], pix[top+0])
|
||||
pix[p+1] += avg2(pix[p-3], pix[top+1])
|
||||
pix[p+2] += avg2(pix[p-2], pix[top+2])
|
||||
pix[p+3] += avg2(pix[p-1], pix[top+3])
|
||||
|
||||
case 8: // Average2(TL, T).
|
||||
pix[p+0] += avg2(pix[top-4], pix[top+0])
|
||||
pix[p+1] += avg2(pix[top-3], pix[top+1])
|
||||
pix[p+2] += avg2(pix[top-2], pix[top+2])
|
||||
pix[p+3] += avg2(pix[top-1], pix[top+3])
|
||||
|
||||
case 9: // Average2(T, TR).
|
||||
pix[p+0] += avg2(pix[top+0], pix[top+4])
|
||||
pix[p+1] += avg2(pix[top+1], pix[top+5])
|
||||
pix[p+2] += avg2(pix[top+2], pix[top+6])
|
||||
pix[p+3] += avg2(pix[top+3], pix[top+7])
|
||||
|
||||
case 10: // Average2(Average2(L, TL), Average2(T, TR)).
|
||||
pix[p+0] += avg2(avg2(pix[p-4], pix[top-4]), avg2(pix[top+0], pix[top+4]))
|
||||
pix[p+1] += avg2(avg2(pix[p-3], pix[top-3]), avg2(pix[top+1], pix[top+5]))
|
||||
pix[p+2] += avg2(avg2(pix[p-2], pix[top-2]), avg2(pix[top+2], pix[top+6]))
|
||||
pix[p+3] += avg2(avg2(pix[p-1], pix[top-1]), avg2(pix[top+3], pix[top+7]))
|
||||
|
||||
case 11: // Select(L, T, TL).
|
||||
l0 := int32(pix[p-4])
|
||||
l1 := int32(pix[p-3])
|
||||
l2 := int32(pix[p-2])
|
||||
l3 := int32(pix[p-1])
|
||||
c0 := int32(pix[top-4])
|
||||
c1 := int32(pix[top-3])
|
||||
c2 := int32(pix[top-2])
|
||||
c3 := int32(pix[top-1])
|
||||
t0 := int32(pix[top+0])
|
||||
t1 := int32(pix[top+1])
|
||||
t2 := int32(pix[top+2])
|
||||
t3 := int32(pix[top+3])
|
||||
l := abs(c0-t0) + abs(c1-t1) + abs(c2-t2) + abs(c3-t3)
|
||||
t := abs(c0-l0) + abs(c1-l1) + abs(c2-l2) + abs(c3-l3)
|
||||
if l < t {
|
||||
pix[p+0] += uint8(l0)
|
||||
pix[p+1] += uint8(l1)
|
||||
pix[p+2] += uint8(l2)
|
||||
pix[p+3] += uint8(l3)
|
||||
} else {
|
||||
pix[p+0] += uint8(t0)
|
||||
pix[p+1] += uint8(t1)
|
||||
pix[p+2] += uint8(t2)
|
||||
pix[p+3] += uint8(t3)
|
||||
}
|
||||
|
||||
case 12: // ClampAddSubtractFull(L, T, TL).
|
||||
pix[p+0] += clampAddSubtractFull(pix[p-4], pix[top+0], pix[top-4])
|
||||
pix[p+1] += clampAddSubtractFull(pix[p-3], pix[top+1], pix[top-3])
|
||||
pix[p+2] += clampAddSubtractFull(pix[p-2], pix[top+2], pix[top-2])
|
||||
pix[p+3] += clampAddSubtractFull(pix[p-1], pix[top+3], pix[top-1])
|
||||
|
||||
case 13: // ClampAddSubtractHalf(Average2(L, T), TL).
|
||||
pix[p+0] += clampAddSubtractHalf(avg2(pix[p-4], pix[top+0]), pix[top-4])
|
||||
pix[p+1] += clampAddSubtractHalf(avg2(pix[p-3], pix[top+1]), pix[top-3])
|
||||
pix[p+2] += clampAddSubtractHalf(avg2(pix[p-2], pix[top+2]), pix[top-2])
|
||||
pix[p+3] += clampAddSubtractHalf(avg2(pix[p-1], pix[top+3]), pix[top-1])
|
||||
}
|
||||
p, top = p+4, top+4
|
||||
}
|
||||
}
|
||||
return pix
|
||||
}
|
||||
|
||||
func inverseCrossColor(t *transform, pix []byte, h int32) []byte {
|
||||
var greenToRed, greenToBlue, redToBlue int32
|
||||
p, mask, tilesPerRow := int32(0), int32(1)<<t.bits-1, nTiles(t.oldWidth, t.bits)
|
||||
for y := int32(0); y < h; y++ {
|
||||
q := 4 * (y >> t.bits) * tilesPerRow
|
||||
for x := int32(0); x < t.oldWidth; x++ {
|
||||
if x&mask == 0 {
|
||||
redToBlue = int32(int8(t.pix[q+0]))
|
||||
greenToBlue = int32(int8(t.pix[q+1]))
|
||||
greenToRed = int32(int8(t.pix[q+2]))
|
||||
q += 4
|
||||
}
|
||||
red := pix[p+0]
|
||||
green := pix[p+1]
|
||||
blue := pix[p+2]
|
||||
red += uint8(uint32(greenToRed*int32(int8(green))) >> 5)
|
||||
blue += uint8(uint32(greenToBlue*int32(int8(green))) >> 5)
|
||||
blue += uint8(uint32(redToBlue*int32(int8(red))) >> 5)
|
||||
pix[p+0] = red
|
||||
pix[p+2] = blue
|
||||
p += 4
|
||||
}
|
||||
}
|
||||
return pix
|
||||
}
|
||||
|
||||
func inverseSubtractGreen(t *transform, pix []byte, h int32) []byte {
|
||||
for p := 0; p < len(pix); p += 4 {
|
||||
green := pix[p+1]
|
||||
pix[p+0] += green
|
||||
pix[p+2] += green
|
||||
}
|
||||
return pix
|
||||
}
|
||||
|
||||
func inverseColorIndexing(t *transform, pix []byte, h int32) []byte {
|
||||
if t.bits == 0 {
|
||||
for p := 0; p < len(pix); p += 4 {
|
||||
i := 4 * uint32(pix[p+1])
|
||||
pix[p+0] = t.pix[i+0]
|
||||
pix[p+1] = t.pix[i+1]
|
||||
pix[p+2] = t.pix[i+2]
|
||||
pix[p+3] = t.pix[i+3]
|
||||
}
|
||||
return pix
|
||||
}
|
||||
|
||||
vMask, xMask, bitsPerPixel := uint32(0), int32(0), uint32(8>>t.bits)
|
||||
switch t.bits {
|
||||
case 1:
|
||||
vMask, xMask = 0x0f, 0x01
|
||||
case 2:
|
||||
vMask, xMask = 0x03, 0x03
|
||||
case 3:
|
||||
vMask, xMask = 0x01, 0x07
|
||||
}
|
||||
|
||||
d, p, v, dst := 0, 0, uint32(0), make([]byte, 4*t.oldWidth*h)
|
||||
for y := int32(0); y < h; y++ {
|
||||
for x := int32(0); x < t.oldWidth; x++ {
|
||||
if x&xMask == 0 {
|
||||
v = uint32(pix[p+1])
|
||||
p += 4
|
||||
}
|
||||
|
||||
i := 4 * (v & vMask)
|
||||
dst[d+0] = t.pix[i+0]
|
||||
dst[d+1] = t.pix[i+1]
|
||||
dst[d+2] = t.pix[i+2]
|
||||
dst[d+3] = t.pix[i+3]
|
||||
d += 4
|
||||
|
||||
v >>= bitsPerPixel
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func abs(x int32) int32 {
|
||||
if x < 0 {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func avg2(a, b uint8) uint8 {
|
||||
return uint8((int32(a) + int32(b)) / 2)
|
||||
}
|
||||
|
||||
func clampAddSubtractFull(a, b, c uint8) uint8 {
|
||||
x := int32(a) + int32(b) - int32(c)
|
||||
if x < 0 {
|
||||
return 0
|
||||
}
|
||||
if x > 255 {
|
||||
return 255
|
||||
}
|
||||
return uint8(x)
|
||||
}
|
||||
|
||||
func clampAddSubtractHalf(a, b uint8) uint8 {
|
||||
x := int32(a) + (int32(a)-int32(b))/2
|
||||
if x < 0 {
|
||||
return 0
|
||||
}
|
||||
if x > 255 {
|
||||
return 255
|
||||
}
|
||||
return uint8(x)
|
||||
}
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package webp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
|
||||
"golang.org/x/image/riff"
|
||||
"golang.org/x/image/vp8"
|
||||
"golang.org/x/image/vp8l"
|
||||
)
|
||||
|
||||
var errInvalidFormat = errors.New("webp: invalid format")
|
||||
|
||||
var (
|
||||
fccALPH = riff.FourCC{'A', 'L', 'P', 'H'}
|
||||
fccVP8 = riff.FourCC{'V', 'P', '8', ' '}
|
||||
fccVP8L = riff.FourCC{'V', 'P', '8', 'L'}
|
||||
fccVP8X = riff.FourCC{'V', 'P', '8', 'X'}
|
||||
fccWEBP = riff.FourCC{'W', 'E', 'B', 'P'}
|
||||
)
|
||||
|
||||
func decode(r io.Reader, configOnly bool) (image.Image, image.Config, error) {
|
||||
formType, riffReader, err := riff.NewReader(r)
|
||||
if err != nil {
|
||||
return nil, image.Config{}, err
|
||||
}
|
||||
if formType != fccWEBP {
|
||||
return nil, image.Config{}, errInvalidFormat
|
||||
}
|
||||
|
||||
var (
|
||||
alpha []byte
|
||||
alphaStride int
|
||||
wantAlpha bool
|
||||
seenVP8X bool
|
||||
widthMinusOne uint32
|
||||
heightMinusOne uint32
|
||||
buf [10]byte
|
||||
)
|
||||
for {
|
||||
chunkID, chunkLen, chunkData, err := riffReader.Next()
|
||||
if err == io.EOF {
|
||||
err = errInvalidFormat
|
||||
}
|
||||
if err != nil {
|
||||
return nil, image.Config{}, err
|
||||
}
|
||||
|
||||
switch chunkID {
|
||||
case fccALPH:
|
||||
if !wantAlpha {
|
||||
return nil, image.Config{}, errInvalidFormat
|
||||
}
|
||||
wantAlpha = false
|
||||
// Read the Pre-processing | Filter | Compression byte.
|
||||
if _, err := io.ReadFull(chunkData, buf[:1]); err != nil {
|
||||
if err == io.EOF {
|
||||
err = errInvalidFormat
|
||||
}
|
||||
return nil, image.Config{}, err
|
||||
}
|
||||
alpha, alphaStride, err = readAlpha(chunkData, widthMinusOne, heightMinusOne, buf[0]&0x03)
|
||||
if err != nil {
|
||||
return nil, image.Config{}, err
|
||||
}
|
||||
unfilterAlpha(alpha, alphaStride, (buf[0]>>2)&0x03)
|
||||
|
||||
case fccVP8:
|
||||
if wantAlpha || int32(chunkLen) < 0 {
|
||||
return nil, image.Config{}, errInvalidFormat
|
||||
}
|
||||
d := vp8.NewDecoder()
|
||||
d.Init(chunkData, int(chunkLen))
|
||||
fh, err := d.DecodeFrameHeader()
|
||||
if err != nil {
|
||||
return nil, image.Config{}, err
|
||||
}
|
||||
if configOnly {
|
||||
return nil, image.Config{
|
||||
ColorModel: color.YCbCrModel,
|
||||
Width: fh.Width,
|
||||
Height: fh.Height,
|
||||
}, nil
|
||||
}
|
||||
m, err := d.DecodeFrame()
|
||||
if err != nil {
|
||||
return nil, image.Config{}, err
|
||||
}
|
||||
if alpha != nil {
|
||||
return &image.NYCbCrA{
|
||||
YCbCr: *m,
|
||||
A: alpha,
|
||||
AStride: alphaStride,
|
||||
}, image.Config{}, nil
|
||||
}
|
||||
return m, image.Config{}, nil
|
||||
|
||||
case fccVP8L:
|
||||
if alpha != nil {
|
||||
return nil, image.Config{}, errInvalidFormat
|
||||
}
|
||||
if configOnly {
|
||||
c, err := vp8l.DecodeConfig(chunkData)
|
||||
return nil, c, err
|
||||
}
|
||||
m, err := vp8l.Decode(chunkData)
|
||||
return m, image.Config{}, err
|
||||
|
||||
case fccVP8X:
|
||||
if seenVP8X {
|
||||
return nil, image.Config{}, errInvalidFormat
|
||||
}
|
||||
seenVP8X = true
|
||||
if chunkLen != 10 {
|
||||
return nil, image.Config{}, errInvalidFormat
|
||||
}
|
||||
if _, err := io.ReadFull(chunkData, buf[:10]); err != nil {
|
||||
return nil, image.Config{}, err
|
||||
}
|
||||
const (
|
||||
animationBit = 1 << 1
|
||||
xmpMetadataBit = 1 << 2
|
||||
exifMetadataBit = 1 << 3
|
||||
alphaBit = 1 << 4
|
||||
iccProfileBit = 1 << 5
|
||||
)
|
||||
wantAlpha = (buf[0] & alphaBit) != 0
|
||||
widthMinusOne = uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16
|
||||
heightMinusOne = uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16
|
||||
if uint64(widthMinusOne+1)*uint64(heightMinusOne+1) > 1<<32-1 {
|
||||
// The product of _Canvas Width_ and _Canvas Height_ MUST be
|
||||
// at most 2^32 - 1.
|
||||
// https://www.rfc-editor.org/rfc/rfc9649.html#section-2.7-12
|
||||
return nil, image.Config{}, errInvalidFormat
|
||||
}
|
||||
if configOnly {
|
||||
if wantAlpha {
|
||||
return nil, image.Config{
|
||||
ColorModel: color.NYCbCrAModel,
|
||||
Width: int(widthMinusOne) + 1,
|
||||
Height: int(heightMinusOne) + 1,
|
||||
}, nil
|
||||
}
|
||||
return nil, image.Config{
|
||||
ColorModel: color.YCbCrModel,
|
||||
Width: int(widthMinusOne) + 1,
|
||||
Height: int(heightMinusOne) + 1,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func readAlpha(chunkData io.Reader, widthMinusOne, heightMinusOne uint32, compression byte) (
|
||||
alpha []byte, alphaStride int, err error) {
|
||||
|
||||
switch compression {
|
||||
case 0:
|
||||
w := int(widthMinusOne) + 1
|
||||
h := int(heightMinusOne) + 1
|
||||
alpha = make([]byte, w*h)
|
||||
if _, err := io.ReadFull(chunkData, alpha); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return alpha, w, nil
|
||||
|
||||
case 1:
|
||||
// Read the VP8L-compressed alpha values. First, synthesize a 5-byte VP8L header:
|
||||
// a 1-byte magic number, a 14-bit widthMinusOne, a 14-bit heightMinusOne,
|
||||
// a 1-bit (ignored, zero) alphaIsUsed and a 3-bit (zero) version.
|
||||
// TODO(nigeltao): be more efficient than decoding an *image.NRGBA just to
|
||||
// extract the green values to a separately allocated []byte. Fixing this
|
||||
// will require changes to the vp8l package's API.
|
||||
if widthMinusOne > 0x3fff || heightMinusOne > 0x3fff {
|
||||
return nil, 0, errors.New("webp: invalid format")
|
||||
}
|
||||
alphaImage, err := vp8l.Decode(io.MultiReader(
|
||||
bytes.NewReader([]byte{
|
||||
0x2f, // VP8L magic number.
|
||||
uint8(widthMinusOne),
|
||||
uint8(widthMinusOne>>8) | uint8(heightMinusOne<<6),
|
||||
uint8(heightMinusOne >> 2),
|
||||
uint8(heightMinusOne >> 10),
|
||||
}),
|
||||
chunkData,
|
||||
))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
// The green values of the inner NRGBA image are the alpha values of the
|
||||
// outer NYCbCrA image.
|
||||
pix := alphaImage.(*image.NRGBA).Pix
|
||||
alpha = make([]byte, len(pix)/4)
|
||||
for i := range alpha {
|
||||
alpha[i] = pix[4*i+1]
|
||||
}
|
||||
return alpha, int(widthMinusOne) + 1, nil
|
||||
}
|
||||
return nil, 0, errInvalidFormat
|
||||
}
|
||||
|
||||
func unfilterAlpha(alpha []byte, alphaStride int, filter byte) {
|
||||
if len(alpha) == 0 || alphaStride == 0 {
|
||||
return
|
||||
}
|
||||
switch filter {
|
||||
case 1: // Horizontal filter.
|
||||
for i := 1; i < alphaStride; i++ {
|
||||
alpha[i] += alpha[i-1]
|
||||
}
|
||||
for i := alphaStride; i < len(alpha); i += alphaStride {
|
||||
// The first column is equivalent to the vertical filter.
|
||||
alpha[i] += alpha[i-alphaStride]
|
||||
|
||||
for j := 1; j < alphaStride; j++ {
|
||||
alpha[i+j] += alpha[i+j-1]
|
||||
}
|
||||
}
|
||||
|
||||
case 2: // Vertical filter.
|
||||
// The first row is equivalent to the horizontal filter.
|
||||
for i := 1; i < alphaStride; i++ {
|
||||
alpha[i] += alpha[i-1]
|
||||
}
|
||||
|
||||
for i := alphaStride; i < len(alpha); i++ {
|
||||
alpha[i] += alpha[i-alphaStride]
|
||||
}
|
||||
|
||||
case 3: // Gradient filter.
|
||||
// The first row is equivalent to the horizontal filter.
|
||||
for i := 1; i < alphaStride; i++ {
|
||||
alpha[i] += alpha[i-1]
|
||||
}
|
||||
|
||||
for i := alphaStride; i < len(alpha); i += alphaStride {
|
||||
// The first column is equivalent to the vertical filter.
|
||||
alpha[i] += alpha[i-alphaStride]
|
||||
|
||||
// The interior is predicted on the three top/left pixels.
|
||||
for j := 1; j < alphaStride; j++ {
|
||||
c := int(alpha[i+j-alphaStride-1])
|
||||
b := int(alpha[i+j-alphaStride])
|
||||
a := int(alpha[i+j-1])
|
||||
x := a + b - c
|
||||
if x < 0 {
|
||||
x = 0
|
||||
} else if x > 255 {
|
||||
x = 255
|
||||
}
|
||||
alpha[i+j] += uint8(x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decode reads a WEBP image from r and returns it as an image.Image.
|
||||
func Decode(r io.Reader) (image.Image, error) {
|
||||
m, _, err := decode(r, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DecodeConfig returns the color model and dimensions of a WEBP image without
|
||||
// decoding the entire image.
|
||||
func DecodeConfig(r io.Reader) (image.Config, error) {
|
||||
_, c, err := decode(r, true)
|
||||
return c, err
|
||||
}
|
||||
|
||||
func init() {
|
||||
image.RegisterFormat("webp", "RIFF????WEBPVP8", Decode, DecodeConfig)
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package webp implements a decoder for WEBP images.
|
||||
//
|
||||
// WEBP is defined at:
|
||||
// https://developers.google.com/speed/webp/docs/riff_container
|
||||
package webp // import "golang.org/x/image/webp"
|
||||
Reference in New Issue
Block a user