-
Notifications
You must be signed in to change notification settings - Fork 1
/
compress.go
121 lines (105 loc) · 2.68 KB
/
compress.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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) {
var n int
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]...)
}
}
}
// unRLE decodes the Run-Length Encoded data in src and returns the
// uncompressed data. For LogLuv, each of four bytestreams is encoded separately per row.
// This compression is used for LogLuv anf LogL (mode: mLogLuv or LogL).
// blockWidth and blockHeight are the dimmension of the Strip or Tiles.
func unRLE(r io.Reader, mode imageMode, blockWidth, blockHeight int) (dst []byte, err error) {
br, ok := r.(byteReader)
if !ok {
br = bufio.NewReader(r)
}
bytesPerPixel := 4 // mLogLuv
if mode == mLogL {
bytesPerPixel = 2 // Luminance without chromatic u, v parts
}
var b byte
dst = make([]byte, blockWidth*blockHeight*bytesPerPixel)
var runLength int
for row := 0; row < blockHeight; row++ { // Each row (aka scanline for RLE)
rowOffest := row * blockWidth * bytesPerPixel
for channel := 0; channel < bytesPerPixel; channel++ { // planar/separate to interleaved/contiguous looping
offset := channel
nbOfPixels := blockWidth // per scanline
for nbOfPixels > 0 {
// Read RLE property
if b, err = br.ReadByte(); err != nil {
return // Never reached by an io.EOF
}
if (b & 128) != 0 {
// a run of the same value
runLength = int(b) + (2 - 128)
nbOfPixels -= runLength
if b, err = br.ReadByte(); err != nil {
return // Never reached by an io.EOF
}
for ; runLength > 0; runLength-- {
dst[rowOffest+offset] = b
offset += bytesPerPixel
}
} else {
// a non-run, copy data
runLength = int(b)
nbOfPixels -= runLength
for ; runLength > 0; runLength-- {
if b, err = br.ReadByte(); err != nil {
return // Never reached by an io.EOF
}
dst[rowOffest+offset] = b
offset += bytesPerPixel
}
}
}
}
}
return
}