Home | History | Annotate | Download | only in jpeg
      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.
      4 
      5 package jpeg
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"image"
     11 	"image/color"
     12 	"io"
     13 	"io/ioutil"
     14 	"math/rand"
     15 	"os"
     16 	"strings"
     17 	"testing"
     18 	"time"
     19 )
     20 
     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",
     36 	}
     37 	for _, tc := range testCases {
     38 		m0, err := decodeFile(tc + ".jpeg")
     39 		if err != nil {
     40 			t.Errorf("%s: %v", tc+".jpeg", err)
     41 			continue
     42 		}
     43 		m1, err := decodeFile(tc + ".progressive.jpeg")
     44 		if err != nil {
     45 			t.Errorf("%s: %v", tc+".progressive.jpeg", err)
     46 			continue
     47 		}
     48 		if m0.Bounds() != m1.Bounds() {
     49 			t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds())
     50 			continue
     51 		}
     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())
     55 			continue
     56 		}
     57 
     58 		switch m0 := m0.(type) {
     59 		case *image.YCbCr:
     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)
     63 				continue
     64 			}
     65 			if err := check(m0.Bounds(), m0.Cb, m1.Cb, m0.CStride, m1.CStride); err != nil {
     66 				t.Errorf("%s (Cb): %v", tc, err)
     67 				continue
     68 			}
     69 			if err := check(m0.Bounds(), m0.Cr, m1.Cr, m0.CStride, m1.CStride); err != nil {
     70 				t.Errorf("%s (Cr): %v", tc, err)
     71 				continue
     72 			}
     73 		case *image.Gray:
     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)
     77 				continue
     78 			}
     79 		default:
     80 			t.Errorf("%s: unexpected image type %T", tc, m0)
     81 			continue
     82 		}
     83 	}
     84 }
     85 
     86 func decodeFile(filename string) (image.Image, error) {
     87 	f, err := os.Open(filename)
     88 	if err != nil {
     89 		return nil, err
     90 	}
     91 	defer f.Close()
     92 	return Decode(f)
     93 }
     94 
     95 type eofReader struct {
     96 	data     []byte // deliver from Read without EOF
     97 	dataEOF  []byte // then deliver from Read with EOF on last chunk
     98 	lenAtEOF int
     99 }
    100 
    101 func (r *eofReader) Read(b []byte) (n int, err error) {
    102 	if len(r.data) > 0 {
    103 		n = copy(b, r.data)
    104 		r.data = r.data[n:]
    105 	} else {
    106 		n = copy(b, r.dataEOF)
    107 		r.dataEOF = r.dataEOF[n:]
    108 		if len(r.dataEOF) == 0 {
    109 			err = io.EOF
    110 			if r.lenAtEOF == -1 {
    111 				r.lenAtEOF = n
    112 			}
    113 		}
    114 	}
    115 	return
    116 }
    117 
    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")
    121 	if err != nil {
    122 		t.Fatal(err)
    123 	}
    124 
    125 	n := len(data)
    126 	for i := 0; i < n; {
    127 		r := &eofReader{data[:n-i], data[n-i:], -1}
    128 		_, err := Decode(r)
    129 		if err != nil {
    130 			t.Errorf("Decode with Read() = %d, EOF: %v", r.lenAtEOF, err)
    131 		}
    132 		if i == 0 {
    133 			i = 1
    134 		} else {
    135 			i *= 2
    136 		}
    137 	}
    138 }
    139 
    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)
    144 	}
    145 	if stride1 <= 0 || stride1%8 != 0 {
    146 		return fmt.Errorf("bad stride %d", stride1)
    147 	}
    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.
    158 				continue
    159 			}
    160 
    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),
    169 						)
    170 					}
    171 				}
    172 			}
    173 		}
    174 	}
    175 	return nil
    176 }
    177 
    178 func pixString(pix []byte, stride, x, y int) string {
    179 	s := bytes.NewBuffer(nil)
    180 	for j := 0; j < 8; j++ {
    181 		fmt.Fprintf(s, "\t")
    182 		for i := 0; i < 8; i++ {
    183 			fmt.Fprintf(s, "%02x ", pix[(y+j)*stride+(x+i)])
    184 		}
    185 		fmt.Fprintf(s, "\n")
    186 	}
    187 	return s.String()
    188 }
    189 
    190 func TestTruncatedSOSDataDoesntPanic(t *testing.T) {
    191 	b, err := ioutil.ReadFile("../testdata/video-005.gray.q50.jpeg")
    192 	if err != nil {
    193 		t.Fatal(err)
    194 	}
    195 	sosMarker := []byte{0xff, 0xda}
    196 	i := bytes.Index(b, sosMarker)
    197 	if i < 0 {
    198 		t.Fatal("SOS marker not found")
    199 	}
    200 	i += len(sosMarker)
    201 	j := i + 10
    202 	if j > len(b) {
    203 		j = len(b)
    204 	}
    205 	for ; i < j; i++ {
    206 		Decode(bytes.NewReader(b[:i]))
    207 	}
    208 }
    209 
    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.
    217 	const 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)
    251 	go func() {
    252 		_, err := Decode(strings.NewReader(input))
    253 		c <- err
    254 	}()
    255 	select {
    256 	case err := <-c:
    257 		if err == nil {
    258 			t.Fatalf("got nil error, want non-nil")
    259 		}
    260 	case <-time.After(3 * time.Second):
    261 		t.Fatalf("timed out")
    262 	}
    263 }
    264 
    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)
    272 	}
    273 	enc := buf.String()
    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.
    277 	if len(enc) < 64 {
    278 		t.Fatalf("encoded JPEG is too short: %d bytes", len(enc))
    279 	}
    280 	if got, want := enc[len(enc)-2:], "\xff\xd9"; got != want {
    281 		t.Fatalf("encoded JPEG ends with %q, want %q", got, want)
    282 	}
    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)
    285 	}
    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++ {
    290 		buf.Reset()
    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 {
    296 				buf.WriteByte(x)
    297 			} else {
    298 				// The JPEG format escapes a SOS 0xff data byte as "\xff\x00".
    299 				buf.WriteString("\xff\x00")
    300 			}
    301 		}
    302 		// Write the "\xff\xd9" EOI marker.
    303 		buf.WriteString("\xff\xd9")
    304 
    305 		// Check that we can still decode the resultant image.
    306 		got, err := Decode(buf)
    307 		if err != nil {
    308 			t.Errorf("could not decode image #%d: %v", i, err)
    309 			nerr++
    310 			continue
    311 		}
    312 		if got.Bounds() != src.Bounds() {
    313 			t.Errorf("image #%d, bounds differ: %v and %v", i, got.Bounds(), src.Bounds())
    314 			nerr++
    315 			continue
    316 		}
    317 		if averageDelta(got, src) > 2<<8 {
    318 			t.Errorf("image #%d changed too much after a round trip", i)
    319 			nerr++
    320 			continue
    321 		}
    322 	}
    323 }
    324 
    325 func benchmarkDecode(b *testing.B, filename string) {
    326 	b.StopTimer()
    327 	data, err := ioutil.ReadFile(filename)
    328 	if err != nil {
    329 		b.Fatal(err)
    330 	}
    331 	cfg, err := DecodeConfig(bytes.NewReader(data))
    332 	if err != nil {
    333 		b.Fatal(err)
    334 	}
    335 	b.SetBytes(int64(cfg.Width * cfg.Height * 4))
    336 	b.StartTimer()
    337 	for i := 0; i < b.N; i++ {
    338 		Decode(bytes.NewReader(data))
    339 	}
    340 }
    341 
    342 func BenchmarkDecodeBaseline(b *testing.B) {
    343 	benchmarkDecode(b, "../testdata/video-001.jpeg")
    344 }
    345 
    346 func BenchmarkDecodeProgressive(b *testing.B) {
    347 	benchmarkDecode(b, "../testdata/video-001.progressive.jpeg")
    348 }
    349