зеркало из https://github.com/golang/image.git
tiff: Add support for CCITT group 3/4 compression
The algorithm is described at https://www.itu.int/rec/T-REC-T.6/en Fixes golang/go#19443 Change-Id: Ib8a078ab43c78d1f58d2ac849ed455b05dc209e9 Reviewed-on: https://go-review.googlesource.com/c/image/+/174139 Reviewed-by: Benny Siegert <bsiegert@gmail.com> Reviewed-by: Nigel Tao <nigeltao@golang.org> Run-TryBot: Benny Siegert <bsiegert@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Родитель
92942e4437
Коммит
7e034cad64
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 546 B |
Двоичный файл не отображается.
Двоичный файл не отображается.
|
@ -42,11 +42,16 @@ const (
|
|||
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
|
||||
|
@ -112,22 +117,33 @@ const (
|
|||
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
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"io/ioutil"
|
||||
"math"
|
||||
|
||||
"golang.org/x/image/ccitt"
|
||||
"golang.org/x/image/tiff/lzw"
|
||||
)
|
||||
|
||||
|
@ -129,7 +130,10 @@ func (d *decoder) parseIFD(p []byte) (int, error) {
|
|||
tTileOffsets,
|
||||
tTileByteCounts,
|
||||
tImageLength,
|
||||
tImageWidth:
|
||||
tImageWidth,
|
||||
tFillOrder,
|
||||
tT4Options,
|
||||
tT6Options:
|
||||
val, err := d.ifdUint(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -441,7 +445,8 @@ func newDecoder(r io.Reader) (*decoder, error) {
|
|||
d.config.Height = int(d.firstVal(tImageLength))
|
||||
|
||||
if _, ok := d.features[tBitsPerSample]; !ok {
|
||||
return nil, FormatError("BitsPerSample tag missing")
|
||||
// Default is 1 per specification.
|
||||
d.features[tBitsPerSample] = []uint{1}
|
||||
}
|
||||
d.bpp = d.firstVal(tBitsPerSample)
|
||||
switch d.bpp {
|
||||
|
@ -539,6 +544,13 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
|
|||
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) {
|
||||
|
@ -644,6 +656,16 @@ func Decode(r io.Reader) (img image.Image, err error) {
|
|||
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)
|
||||
|
|
|
@ -193,6 +193,32 @@ func TestDecodeLZW(t *testing.T) {
|
|||
compare(t, img0, img1)
|
||||
}
|
||||
|
||||
// TestDecodeCCITT tests that decoding a PNG image and a CCITT compressed TIFF
|
||||
// image result in the same pixel data.
|
||||
func TestDecodeCCITT(t *testing.T) {
|
||||
// TODO Add more tests.
|
||||
for _, fn := range []string{
|
||||
"bw-gopher",
|
||||
} {
|
||||
img0, err := load(fn + ".png")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
img1, err := load(fn + "_ccittGroup3.tiff")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
compare(t, img0, img1)
|
||||
|
||||
img2, err := load(fn + "_ccittGroup4.tiff")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
compare(t, img0, img2)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDecodeTagOrder tests that a malformed image with unsorted IFD entries is
|
||||
// correctly rejected.
|
||||
func TestDecodeTagOrder(t *testing.T) {
|
||||
|
|
|
@ -42,6 +42,7 @@ func TestRoundtrip(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
out := new(bytes.Buffer)
|
||||
err = Encode(out, img, rt.opts)
|
||||
if err != nil {
|
||||
|
|
Загрузка…
Ссылка в новой задаче