1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
21 // TestDecodeProgressive tests that decoding the baseline and progressive
22 // versions of the same image result in exactly the same pixel data, in YCbCr
23 // space for color images, and Y space for grayscale images.
24 func TestDecodeProgressive(t
*testing
.T
) {
25 testCases
:= []string{
26 "../testdata/video-001",
27 "../testdata/video-001.q50.410",
28 "../testdata/video-001.q50.411",
29 "../testdata/video-001.q50.420",
30 "../testdata/video-001.q50.422",
31 "../testdata/video-001.q50.440",
32 "../testdata/video-001.q50.444",
33 "../testdata/video-005.gray.q50",
34 "../testdata/video-005.gray.q50.2x2",
35 "../testdata/video-001.separate.dc.progression",
37 for _
, tc
:= range testCases
{
38 m0
, err
:= decodeFile(tc
+ ".jpeg")
40 t
.Errorf("%s: %v", tc
+".jpeg", err
)
43 m1
, err
:= decodeFile(tc
+ ".progressive.jpeg")
45 t
.Errorf("%s: %v", tc
+".progressive.jpeg", err
)
48 if m0
.Bounds() != m1
.Bounds() {
49 t
.Errorf("%s: bounds differ: %v and %v", tc
, m0
.Bounds(), m1
.Bounds())
52 // All of the video-*.jpeg files are 150x103.
53 if m0
.Bounds() != image
.Rect(0, 0, 150, 103) {
54 t
.Errorf("%s: bad bounds: %v", tc
, m0
.Bounds())
58 switch m0
:= m0
.(type) {
60 m1
:= m1
.(*image
.YCbCr
)
61 if err
:= check(m0
.Bounds(), m0
.Y
, m1
.Y
, m0
.YStride
, m1
.YStride
); err
!= nil {
62 t
.Errorf("%s (Y): %v", tc
, err
)
65 if err
:= check(m0
.Bounds(), m0
.Cb
, m1
.Cb
, m0
.CStride
, m1
.CStride
); err
!= nil {
66 t
.Errorf("%s (Cb): %v", tc
, err
)
69 if err
:= check(m0
.Bounds(), m0
.Cr
, m1
.Cr
, m0
.CStride
, m1
.CStride
); err
!= nil {
70 t
.Errorf("%s (Cr): %v", tc
, err
)
74 m1
:= m1
.(*image
.Gray
)
75 if err
:= check(m0
.Bounds(), m0
.Pix
, m1
.Pix
, m0
.Stride
, m1
.Stride
); err
!= nil {
76 t
.Errorf("%s: %v", tc
, err
)
80 t
.Errorf("%s: unexpected image type %T", tc
, m0
)
86 func decodeFile(filename
string) (image
.Image
, error
) {
87 f
, err
:= os
.Open(filename
)
95 type eofReader
struct {
96 data
[]byte // deliver from Read without EOF
97 dataEOF
[]byte // then deliver from Read with EOF on last chunk
101 func (r
*eofReader
) Read(b
[]byte) (n
int, err error
) {
106 n
= copy(b
, r
.dataEOF
)
107 r
.dataEOF
= r
.dataEOF
[n
:]
108 if len(r
.dataEOF
) == 0 {
110 if r
.lenAtEOF
== -1 {
118 func TestDecodeEOF(t
*testing
.T
) {
119 // Check that if reader returns final data and EOF at same time, jpeg handles it.
120 data
, err
:= ioutil
.ReadFile("../testdata/video-001.jpeg")
127 r
:= &eofReader
{data
[:n
-i
], data
[n
-i
:], -1}
130 t
.Errorf("Decode with Read() = %d, EOF: %v", r
.lenAtEOF
, err
)
140 // check checks that the two pix data are equal, within the given bounds.
141 func check(bounds image
.Rectangle
, pix0
, pix1
[]byte, stride0
, stride1
int) error
{
142 if stride0
<= 0 || stride0%8
!= 0 {
143 return fmt
.Errorf("bad stride %d", stride0
)
145 if stride1
<= 0 || stride1%8
!= 0 {
146 return fmt
.Errorf("bad stride %d", stride1
)
148 // Compare the two pix data, one 8x8 block at a time.
149 for y
:= 0; y
< len(pix0
)/stride0
&& y
< len(pix1
)/stride1
; y
+= 8 {
150 for x
:= 0; x
< stride0
&& x
< stride1
; x
+= 8 {
151 if x
>= bounds
.Max
.X || y
>= bounds
.Max
.Y
{
152 // We don't care if the two pix data differ if the 8x8 block is
153 // entirely outside of the image's bounds. For example, this can
154 // occur with a 4:2:0 chroma subsampling and a 1x1 image. Baseline
155 // decoding works on the one 16x16 MCU as a whole; progressive
156 // decoding's first pass works on that 16x16 MCU as a whole but
157 // refinement passes only process one 8x8 block within the MCU.
161 for j
:= 0; j
< 8; j
++ {
162 for i
:= 0; i
< 8; i
++ {
163 index0
:= (y
+j
)*stride0
+ (x
+ i
)
164 index1
:= (y
+j
)*stride1
+ (x
+ i
)
165 if pix0
[index0
] != pix1
[index1
] {
166 return fmt
.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x
, y
,
167 pixString(pix0
, stride0
, x
, y
),
168 pixString(pix1
, stride1
, x
, y
),
178 func pixString(pix
[]byte, stride
, x
, y
int) string {
179 s
:= bytes
.NewBuffer(nil)
180 for j
:= 0; j
< 8; j
++ {
182 for i
:= 0; i
< 8; i
++ {
183 fmt
.Fprintf(s
, "%02x ", pix
[(y
+j
)*stride
+(x
+i
)])
190 func TestTruncatedSOSDataDoesntPanic(t
*testing
.T
) {
191 b
, err
:= ioutil
.ReadFile("../testdata/video-005.gray.q50.jpeg")
195 sosMarker
:= []byte{0xff, 0xda}
196 i
:= bytes
.Index(b
, sosMarker
)
198 t
.Fatal("SOS marker not found")
206 Decode(bytes
.NewReader(b
[:i
]))
210 func TestLargeImageWithShortData(t
*testing
.T
) {
211 // This input is an invalid JPEG image, based on the fuzzer-generated image
212 // in issue 10413. It is only 504 bytes, and shouldn't take long for Decode
213 // to return an error. The Start Of Frame marker gives the image dimensions
214 // as 8192 wide and 8192 high, so even if an unreadByteStuffedByte bug
215 // doesn't technically lead to an infinite loop, such a bug can still cause
216 // an unreasonably long loop for such a short input.
218 "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01" +
219 "\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10" +
220 "\x0e\x89\x0e\x12\x11\x10\x13\x18\xff\xd8\xff\xe0\x00\x10\x4a\x46" +
221 "\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43" +
222 "\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10\x13\x18" +
223 "\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\x28\x3a\x33\x3d\x3c\x39" +
224 "\x33\x38\x37\x40\x48\x5c\x4e\x40\x44\x57\x45\x37\x38\x50\x6d\x51" +
225 "\x57\x5f\x62\x67\x68\x67\x3e\x4d\x71\x79\x70\x64\x78\x5c\x65\x67" +
226 "\x63\xff\xc0\x00\x0b\x08\x20\x00\x20\x00\x01\x01\x11\x00\xff\xc4" +
227 "\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" +
228 "\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff" +
229 "\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04" +
230 "\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x01\x06" +
231 "\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\xd8\xff\xdd" +
232 "\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17" +
233 "\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a" +
234 "\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a" +
235 "\x00\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79" +
236 "\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98" +
237 "\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" +
238 "\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xff\xd8\xff\xe0\x00\x10" +
239 "\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb" +
240 "\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10" +
241 "\x13\x18\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\xc8\xc9\xca\xd2" +
242 "\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" +
243 "\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x08" +
244 "\x01\x01\x00\x00\x3f\x00\xb9\xeb\x50\xb0\xdb\xc8\xa8\xe4\x63\x80" +
245 "\xdd\x31\xd6\x9d\xbb\xf2\xc5\x42\x1f\x6c\x6f\xf4\x34\xdd\x3c\xfc" +
246 "\xac\xe7\x3d\x80\xa9\xcc\x87\x34\xb3\x37\xfa\x2b\x9f\x6a\xad\x63" +
247 "\x20\x36\x9f\x78\x64\x75\xe6\xab\x7d\xb2\xde\x29\x70\xd3\x20\x27" +
248 "\xde\xaf\xa4\xf0\xca\x9f\x24\xa8\xdf\x46\xa8\x24\x84\x96\xe3\x77" +
249 "\xf9\x2e\xe0\x0a\x62\x7f\xdf\xd9"
250 c
:= make(chan error
, 1)
252 _
, err
:= Decode(strings
.NewReader(input
))
258 t
.Fatalf("got nil error, want non-nil")
260 case <-time
.After(3 * time
.Second
):
261 t
.Fatalf("timed out")
265 func TestExtraneousData(t
*testing
.T
) {
266 // Encode a 1x1 red image.
267 src
:= image
.NewRGBA(image
.Rect(0, 0, 1, 1))
268 src
.Set(0, 0, color
.RGBA
{0xff, 0x00, 0x00, 0xff})
269 buf
:= new(bytes
.Buffer
)
270 if err
:= Encode(buf
, src
, nil); err
!= nil {
271 t
.Fatalf("encode: %v", err
)
274 // Sanity check that the encoded JPEG is long enough, that it ends in a
275 // "\xff\xd9" EOI marker, and that it contains a "\xff\xda" SOS marker
276 // somewhere in the final 64 bytes.
278 t
.Fatalf("encoded JPEG is too short: %d bytes", len(enc
))
280 if got
, want
:= enc
[len(enc
)-2:], "\xff\xd9"; got
!= want
{
281 t
.Fatalf("encoded JPEG ends with %q, want %q", got
, want
)
283 if s
:= enc
[len(enc
)-64:]; !strings
.Contains(s
, "\xff\xda") {
284 t
.Fatalf("encoded JPEG does not contain a SOS marker (ff da) near the end: % x", s
)
286 // Test that adding some random junk between the SOS marker and the
287 // EOI marker does not affect the decoding.
288 rnd
:= rand
.New(rand
.NewSource(1))
289 for i
, nerr
:= 0, 0; i
< 1000 && nerr
< 10; i
++ {
291 // Write all but the trailing "\xff\xd9" EOI marker.
292 buf
.WriteString(enc
[:len(enc
)-2])
293 // Write some random extraneous data.
294 for n
:= rnd
.Intn(10); n
> 0; n
-- {
295 if x
:= byte(rnd
.Intn(256)); x
!= 0xff {
298 // The JPEG format escapes a SOS 0xff data byte as "\xff\x00".
299 buf
.WriteString("\xff\x00")
302 // Write the "\xff\xd9" EOI marker.
303 buf
.WriteString("\xff\xd9")
305 // Check that we can still decode the resultant image.
306 got
, err
:= Decode(buf
)
308 t
.Errorf("could not decode image #%d: %v", i
, err
)
312 if got
.Bounds() != src
.Bounds() {
313 t
.Errorf("image #%d, bounds differ: %v and %v", i
, got
.Bounds(), src
.Bounds())
317 if averageDelta(got
, src
) > 2<<8 {
318 t
.Errorf("image #%d changed too much after a round trip", i
)
325 func benchmarkDecode(b
*testing
.B
, filename
string) {
327 data
, err
:= ioutil
.ReadFile(filename
)
331 cfg
, err
:= DecodeConfig(bytes
.NewReader(data
))
335 b
.SetBytes(int64(cfg
.Width
* cfg
.Height
* 4))
337 for i
:= 0; i
< b
.N
; i
++ {
338 Decode(bytes
.NewReader(data
))
342 func BenchmarkDecodeBaseline(b
*testing
.B
) {
343 benchmarkDecode(b
, "../testdata/video-001.jpeg")
346 func BenchmarkDecodeProgressive(b
*testing
.B
) {
347 benchmarkDecode(b
, "../testdata/video-001.progressive.jpeg")