Added support for .bmp images
This commit is contained in:
parent
297c561fab
commit
f6924ba7b5
|
@ -23,6 +23,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
_ "golang.org/x/image/bmp"
|
||||
_ "golang.org/x/image/webp"
|
||||
|
||||
"github.com/h2non/filetype"
|
||||
|
@ -30,7 +31,7 @@ import (
|
|||
|
||||
var (
|
||||
ErrNoImagesFound = fmt.Errorf("no supported image formats found")
|
||||
extensions = [5]string{".jpg", ".jpeg", ".png", ".gif", ".webp"}
|
||||
extensions = [7]string{".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"}
|
||||
)
|
||||
|
||||
type Files struct {
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var Version = "0.20.7"
|
||||
var Version = "0.20.8"
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package bmp implements a BMP image decoder and encoder.
|
||||
//
|
||||
// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
|
||||
package bmp // import "golang.org/x/image/bmp"
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ErrUnsupported means that the input BMP image uses a valid but unsupported
|
||||
// feature.
|
||||
var ErrUnsupported = errors.New("bmp: unsupported BMP image")
|
||||
|
||||
func readUint16(b []byte) uint16 {
|
||||
return uint16(b[0]) | uint16(b[1])<<8
|
||||
}
|
||||
|
||||
func readUint32(b []byte) uint32 {
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
// decodePaletted reads an 8 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodePaletted(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
|
||||
paletted := image.NewPaletted(image.Rect(0, 0, c.Width, c.Height), c.ColorModel.(color.Palette))
|
||||
if c.Width == 0 || c.Height == 0 {
|
||||
return paletted, nil
|
||||
}
|
||||
var tmp [4]byte
|
||||
y0, y1, yDelta := c.Height-1, -1, -1
|
||||
if topDown {
|
||||
y0, y1, yDelta = 0, c.Height, +1
|
||||
}
|
||||
for y := y0; y != y1; y += yDelta {
|
||||
p := paletted.Pix[y*paletted.Stride : y*paletted.Stride+c.Width]
|
||||
if _, err := io.ReadFull(r, p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Each row is 4-byte aligned.
|
||||
if c.Width%4 != 0 {
|
||||
_, err := io.ReadFull(r, tmp[:4-c.Width%4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return paletted, nil
|
||||
}
|
||||
|
||||
// decodeRGB reads a 24 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodeRGB(r io.Reader, c image.Config, topDown bool) (image.Image, error) {
|
||||
rgba := image.NewRGBA(image.Rect(0, 0, c.Width, c.Height))
|
||||
if c.Width == 0 || c.Height == 0 {
|
||||
return rgba, nil
|
||||
}
|
||||
// There are 3 bytes per pixel, and each row is 4-byte aligned.
|
||||
b := make([]byte, (3*c.Width+3)&^3)
|
||||
y0, y1, yDelta := c.Height-1, -1, -1
|
||||
if topDown {
|
||||
y0, y1, yDelta = 0, c.Height, +1
|
||||
}
|
||||
for y := y0; y != y1; y += yDelta {
|
||||
if _, err := io.ReadFull(r, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := rgba.Pix[y*rgba.Stride : y*rgba.Stride+c.Width*4]
|
||||
for i, j := 0, 0; i < len(p); i, j = i+4, j+3 {
|
||||
// BMP images are stored in BGR order rather than RGB order.
|
||||
p[i+0] = b[j+2]
|
||||
p[i+1] = b[j+1]
|
||||
p[i+2] = b[j+0]
|
||||
p[i+3] = 0xFF
|
||||
}
|
||||
}
|
||||
return rgba, nil
|
||||
}
|
||||
|
||||
// decodeNRGBA reads a 32 bit-per-pixel BMP image from r.
|
||||
// If topDown is false, the image rows will be read bottom-up.
|
||||
func decodeNRGBA(r io.Reader, c image.Config, topDown, 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 8:
|
||||
return decodePaletted(r, c, topDown)
|
||||
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 8:
|
||||
if offset != fileHeaderLen+infoLen+256*4 {
|
||||
return image.Config{}, 0, false, false, ErrUnsupported
|
||||
}
|
||||
_, err = io.ReadFull(r, b[:256*4])
|
||||
if err != nil {
|
||||
return image.Config{}, 0, false, false, err
|
||||
}
|
||||
pcm := make(color.Palette, 256)
|
||||
for i := range pcm {
|
||||
// BMP images are stored in BGR order rather than RGB order.
|
||||
// Every 4th byte is padding.
|
||||
pcm[i] = color.RGBA{b[4*i+2], b[4*i+1], b[4*i+0], 0xFF}
|
||||
}
|
||||
return image.Config{ColorModel: pcm, Width: width, Height: height}, 8, topDown, 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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// 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"
|
||||
|
||||
// buffer buffers an io.Reader to satisfy io.ReaderAt.
|
||||
type buffer struct {
|
||||
r io.Reader
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// 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)
|
||||
if end > m {
|
||||
if end > cap(b.buf) {
|
||||
newcap := 1024
|
||||
for newcap < end {
|
||||
newcap *= 2
|
||||
}
|
||||
newbuf := make([]byte, end, newcap)
|
||||
copy(newbuf, b.buf)
|
||||
b.buf = newbuf
|
||||
} else {
|
||||
b.buf = b.buf[:end]
|
||||
}
|
||||
if n, err := io.ReadFull(b.r, b.buf[m:end]); err != nil {
|
||||
end = m + n
|
||||
b.buf = b.buf[:end]
|
||||
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)
|
||||
return copy(p, b.buf[o: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),
|
||||
}
|
||||
}
|
|
@ -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]...)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// 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
|
||||
// +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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,709 @@
|
|||
// 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 (
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"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")
|
||||
|
||||
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 = make([]byte, datalen)
|
||||
_, err = d.r.ReadAt(raw, 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)
|
||||
for y := ymin; y < rMaxY; y++ {
|
||||
for x := xmin; x < rMaxX; x++ {
|
||||
v, ok := d.readBits(d.bpp)
|
||||
if !ok {
|
||||
return errNoPixels
|
||||
}
|
||||
img.SetColorIndex(x, y, uint8(v))
|
||||
}
|
||||
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.
|
||||
p = make([]byte, ifdLen*numItems)
|
||||
if _, err := d.r.ReadAt(p, ifdOffset+2); 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 _, 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")
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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 = make([]byte, n)
|
||||
_, err = d.r.ReadAt(d.buf, 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 = ioutil.ReadAll(r)
|
||||
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 = ioutil.ReadAll(r)
|
||||
case cLZW:
|
||||
r := lzw.NewReader(io.NewSectionReader(d.r, offset, n), lzw.MSB, 8)
|
||||
d.buf, err = ioutil.ReadAll(r)
|
||||
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 = ioutil.ReadAll(r)
|
||||
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 init() {
|
||||
image.RegisterFormat("tiff", leHeader, Decode, DecodeConfig)
|
||||
image.RegisterFormat("tiff", beHeader, Decode, DecodeConfig)
|
||||
}
|
|
@ -0,0 +1,441 @@
|
|||
// 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()
|
||||
|
||||
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)
|
||||
}
|
|
@ -15,7 +15,11 @@ github.com/spf13/cobra
|
|||
github.com/spf13/pflag
|
||||
# golang.org/x/image v0.1.0
|
||||
## explicit; go 1.12
|
||||
golang.org/x/image/bmp
|
||||
golang.org/x/image/ccitt
|
||||
golang.org/x/image/riff
|
||||
golang.org/x/image/tiff
|
||||
golang.org/x/image/tiff/lzw
|
||||
golang.org/x/image/vp8
|
||||
golang.org/x/image/vp8l
|
||||
golang.org/x/image/webp
|
||||
|
|
Loading…
Reference in New Issue