Source file src/image/jpeg/reader_test.go

     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  	"encoding/base64"
    10  	"fmt"
    11  	"image"
    12  	"image/color"
    13  	"io"
    14  	"math/rand"
    15  	"os"
    16  	"runtime/debug"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  )
    21  
    22  // TestDecodeProgressive tests that decoding the baseline and progressive
    23  // versions of the same image result in exactly the same pixel data, in YCbCr
    24  // space for color images, and Y space for grayscale images.
    25  func TestDecodeProgressive(t *testing.T) {
    26  	testCases := []string{
    27  		"../testdata/video-001",
    28  		"../testdata/video-001.q50.410",
    29  		"../testdata/video-001.q50.411",
    30  		"../testdata/video-001.q50.420",
    31  		"../testdata/video-001.q50.422",
    32  		"../testdata/video-001.q50.440",
    33  		"../testdata/video-001.q50.444",
    34  		"../testdata/video-005.gray.q50",
    35  		"../testdata/video-005.gray.q50.2x2",
    36  		"../testdata/video-001.separate.dc.progression",
    37  	}
    38  	for _, tc := range testCases {
    39  		m0, err := decodeFile(tc + ".jpeg")
    40  		if err != nil {
    41  			t.Errorf("%s: %v", tc+".jpeg", err)
    42  			continue
    43  		}
    44  		m1, err := decodeFile(tc + ".progressive.jpeg")
    45  		if err != nil {
    46  			t.Errorf("%s: %v", tc+".progressive.jpeg", err)
    47  			continue
    48  		}
    49  		if m0.Bounds() != m1.Bounds() {
    50  			t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds())
    51  			continue
    52  		}
    53  		// All of the video-*.jpeg files are 150x103.
    54  		if m0.Bounds() != image.Rect(0, 0, 150, 103) {
    55  			t.Errorf("%s: bad bounds: %v", tc, m0.Bounds())
    56  			continue
    57  		}
    58  
    59  		switch m0 := m0.(type) {
    60  		case *image.YCbCr:
    61  			m1 := m1.(*image.YCbCr)
    62  			if err := check(m0.Bounds(), m0.Y, m1.Y, m0.YStride, m1.YStride); err != nil {
    63  				t.Errorf("%s (Y): %v", tc, err)
    64  				continue
    65  			}
    66  			if err := check(m0.Bounds(), m0.Cb, m1.Cb, m0.CStride, m1.CStride); err != nil {
    67  				t.Errorf("%s (Cb): %v", tc, err)
    68  				continue
    69  			}
    70  			if err := check(m0.Bounds(), m0.Cr, m1.Cr, m0.CStride, m1.CStride); err != nil {
    71  				t.Errorf("%s (Cr): %v", tc, err)
    72  				continue
    73  			}
    74  		case *image.Gray:
    75  			m1 := m1.(*image.Gray)
    76  			if err := check(m0.Bounds(), m0.Pix, m1.Pix, m0.Stride, m1.Stride); err != nil {
    77  				t.Errorf("%s: %v", tc, err)
    78  				continue
    79  			}
    80  		default:
    81  			t.Errorf("%s: unexpected image type %T", tc, m0)
    82  			continue
    83  		}
    84  	}
    85  }
    86  
    87  func decodeFile(filename string) (image.Image, error) {
    88  	f, err := os.Open(filename)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	defer f.Close()
    93  	return Decode(f)
    94  }
    95  
    96  type eofReader struct {
    97  	data     []byte // deliver from Read without EOF
    98  	dataEOF  []byte // then deliver from Read with EOF on last chunk
    99  	lenAtEOF int
   100  }
   101  
   102  func (r *eofReader) Read(b []byte) (n int, err error) {
   103  	if len(r.data) > 0 {
   104  		n = copy(b, r.data)
   105  		r.data = r.data[n:]
   106  	} else {
   107  		n = copy(b, r.dataEOF)
   108  		r.dataEOF = r.dataEOF[n:]
   109  		if len(r.dataEOF) == 0 {
   110  			err = io.EOF
   111  			if r.lenAtEOF == -1 {
   112  				r.lenAtEOF = n
   113  			}
   114  		}
   115  	}
   116  	return
   117  }
   118  
   119  func TestDecodeEOF(t *testing.T) {
   120  	// Check that if reader returns final data and EOF at same time, jpeg handles it.
   121  	data, err := os.ReadFile("../testdata/video-001.jpeg")
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  
   126  	n := len(data)
   127  	for i := 0; i < n; {
   128  		r := &eofReader{data[:n-i], data[n-i:], -1}
   129  		_, err := Decode(r)
   130  		if err != nil {
   131  			t.Errorf("Decode with Read() = %d, EOF: %v", r.lenAtEOF, err)
   132  		}
   133  		if i == 0 {
   134  			i = 1
   135  		} else {
   136  			i *= 2
   137  		}
   138  	}
   139  }
   140  
   141  // check checks that the two pix data are equal, within the given bounds.
   142  func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error {
   143  	if stride0 <= 0 || stride0%8 != 0 {
   144  		return fmt.Errorf("bad stride %d", stride0)
   145  	}
   146  	if stride1 <= 0 || stride1%8 != 0 {
   147  		return fmt.Errorf("bad stride %d", stride1)
   148  	}
   149  	// Compare the two pix data, one 8x8 block at a time.
   150  	for y := 0; y < len(pix0)/stride0 && y < len(pix1)/stride1; y += 8 {
   151  		for x := 0; x < stride0 && x < stride1; x += 8 {
   152  			if x >= bounds.Max.X || y >= bounds.Max.Y {
   153  				// We don't care if the two pix data differ if the 8x8 block is
   154  				// entirely outside of the image's bounds. For example, this can
   155  				// occur with a 4:2:0 chroma subsampling and a 1x1 image. Baseline
   156  				// decoding works on the one 16x16 MCU as a whole; progressive
   157  				// decoding's first pass works on that 16x16 MCU as a whole but
   158  				// refinement passes only process one 8x8 block within the MCU.
   159  				continue
   160  			}
   161  
   162  			for j := 0; j < 8; j++ {
   163  				for i := 0; i < 8; i++ {
   164  					index0 := (y+j)*stride0 + (x + i)
   165  					index1 := (y+j)*stride1 + (x + i)
   166  					if pix0[index0] != pix1[index1] {
   167  						return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y,
   168  							pixString(pix0, stride0, x, y),
   169  							pixString(pix1, stride1, x, y),
   170  						)
   171  					}
   172  				}
   173  			}
   174  		}
   175  	}
   176  	return nil
   177  }
   178  
   179  func pixString(pix []byte, stride, x, y int) string {
   180  	s := &strings.Builder{}
   181  	for j := 0; j < 8; j++ {
   182  		fmt.Fprintf(s, "\t")
   183  		for i := 0; i < 8; i++ {
   184  			fmt.Fprintf(s, "%02x ", pix[(y+j)*stride+(x+i)])
   185  		}
   186  		fmt.Fprintf(s, "\n")
   187  	}
   188  	return s.String()
   189  }
   190  
   191  func TestTruncatedSOSDataDoesntPanic(t *testing.T) {
   192  	b, err := os.ReadFile("../testdata/video-005.gray.q50.jpeg")
   193  	if err != nil {
   194  		t.Fatal(err)
   195  	}
   196  	sosMarker := []byte{0xff, 0xda}
   197  	i := bytes.Index(b, sosMarker)
   198  	if i < 0 {
   199  		t.Fatal("SOS marker not found")
   200  	}
   201  	i += len(sosMarker)
   202  	j := i + 10
   203  	if j > len(b) {
   204  		j = len(b)
   205  	}
   206  	for ; i < j; i++ {
   207  		Decode(bytes.NewReader(b[:i]))
   208  	}
   209  }
   210  
   211  func TestLargeImageWithShortData(t *testing.T) {
   212  	// This input is an invalid JPEG image, based on the fuzzer-generated image
   213  	// in issue 10413. It is only 504 bytes, and shouldn't take long for Decode
   214  	// to return an error. The Start Of Frame marker gives the image dimensions
   215  	// as 8192 wide and 8192 high, so even if an unreadByteStuffedByte bug
   216  	// doesn't technically lead to an infinite loop, such a bug can still cause
   217  	// an unreasonably long loop for such a short input.
   218  	const input = "" +
   219  		"\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01" +
   220  		"\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10" +
   221  		"\x0e\x89\x0e\x12\x11\x10\x13\x18\xff\xd8\xff\xe0\x00\x10\x4a\x46" +
   222  		"\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43" +
   223  		"\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10\x13\x18" +
   224  		"\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\x28\x3a\x33\x3d\x3c\x39" +
   225  		"\x33\x38\x37\x40\x48\x5c\x4e\x40\x44\x57\x45\x37\x38\x50\x6d\x51" +
   226  		"\x57\x5f\x62\x67\x68\x67\x3e\x4d\x71\x79\x70\x64\x78\x5c\x65\x67" +
   227  		"\x63\xff\xc0\x00\x0b\x08\x20\x00\x20\x00\x01\x01\x11\x00\xff\xc4" +
   228  		"\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" +
   229  		"\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff" +
   230  		"\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04" +
   231  		"\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x01\x06" +
   232  		"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\xd8\xff\xdd" +
   233  		"\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17" +
   234  		"\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a" +
   235  		"\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a" +
   236  		"\x00\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79" +
   237  		"\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98" +
   238  		"\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" +
   239  		"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xff\xd8\xff\xe0\x00\x10" +
   240  		"\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb" +
   241  		"\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10" +
   242  		"\x13\x18\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\xc8\xc9\xca\xd2" +
   243  		"\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" +
   244  		"\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x08" +
   245  		"\x01\x01\x00\x00\x3f\x00\xb9\xeb\x50\xb0\xdb\xc8\xa8\xe4\x63\x80" +
   246  		"\xdd\x31\xd6\x9d\xbb\xf2\xc5\x42\x1f\x6c\x6f\xf4\x34\xdd\x3c\xfc" +
   247  		"\xac\xe7\x3d\x80\xa9\xcc\x87\x34\xb3\x37\xfa\x2b\x9f\x6a\xad\x63" +
   248  		"\x20\x36\x9f\x78\x64\x75\xe6\xab\x7d\xb2\xde\x29\x70\xd3\x20\x27" +
   249  		"\xde\xaf\xa4\xf0\xca\x9f\x24\xa8\xdf\x46\xa8\x24\x84\x96\xe3\x77" +
   250  		"\xf9\x2e\xe0\x0a\x62\x7f\xdf\xd9"
   251  
   252  	timer := time.AfterFunc(30*time.Second, func() {
   253  		debug.SetTraceback("all")
   254  		panic("TestLargeImageWithShortData stuck in Decode")
   255  	})
   256  	defer timer.Stop()
   257  
   258  	_, err := Decode(strings.NewReader(input))
   259  	if err == nil {
   260  		t.Fatalf("got nil error, want non-nil")
   261  	}
   262  }
   263  
   264  func TestPaddedRSTMarker(t *testing.T) {
   265  	// This test image comes from golang.org/issue/28717
   266  	const base64EncodedImage = `
   267  /9j/4AAhQVZJMQABAQEAeAB4AAAAAAAAAAAAAAAAAAAAAAAAAP/bAEMABAIDAwMCBAMDAwQEBAQGCgYG
   268  BQUGDAgJBwoODA8PDgwODxASFxMQERURDQ4UGhQVFxgZGhkPExweHBkeFxkZGP/bAEMBBAQEBgUGCwYG
   269  CxgQDhAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGP/EAaIA
   270  AAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKCxAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1Fh
   271  ByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNk
   272  ZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT
   273  1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6AQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgsRAAIB
   274  AgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBka
   275  JicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZ
   276  mqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/dAAQA
   277  Cv/gAAQAAP/AABEIALABQAMBIQACEQEDEQH/2gAMAwEAAhEDEQA/APnCFTk5BPPGKliAB718W7H2j3Ip
   278  VUuwJxzTfKXacde9VBhYRUBAyO3pTmUAbSMU5WGmybywzHGAMdelPVFC+n1qXZCuyaJADxjj2qzbBMAP
   279  xz1rKaVib6ltLcFvlIx2pLy0dwuAMMBnH1rFON9RNsszAZPFEYHldPzrOy3KewmBk9qUABugxjtTVmiW
   280  xWRcjp+VJtHXgVL3K6AgBDdM9eRTNzAZViOe1VyxaJavuf/Q8aW4mUcSGpo764AyHz+FfnnJBvVH1UsN
   281  CS1Q/wDte4Trip49ecA7g3FSqMW9zlqZandxJ4/EKADcSPqKni8QQMT865qOSUNjiqZdNbFiHWYXz84N
   282  WE1KNsfMKj2zirHHPDSj0JFvo2H36d9pUjg1sqykYOm0KbgY60omXPXmr9pFkco3zBnrQzjGcnrRzp9S
   283  bEbuOvao3fisZSXUpIYWGKGcbetTCSswsxnmACkYrtNSpJ2YNM//0fnK1BD7sDg9KmUHeOe/Svid3qfb
   284  SdmQ3AHmnr1pGBC5z19a0hohNiJkensM1J0yCKmY0yZR82e+BT1BxnpmpepN9SRCR0NSpweOoPWs6isr
   285  ijuWIZGBA/lVwzMVFY8ibuhXEfr+tOz8hIqUymhRnJGTSc5wBVRRDFPXBHJpB3qdmV0EX7vXmoyfl685
   286  p2dxWR//0vFsHZ9TQv3T618Bqz7PSwwn1phPXpSWrQEUhIx0NVXc7j0rSNwViCS4dWYpJj3BpBqVzGy7
   287  ZmHSq9kpblSpxkveQ+PX7uMf6wEDtU0fi24TAkX8jTeCjJaaHDUwFN7aFq28aL/GCMGrtr4xtHGGkA+t
   288  YTy+a+E82eAa2LsXiWzI5mXPHercOsW8hwJB+dcUqVSCOKVFxdmiwl7E2MOPzp4nQ9GH51jzNbmUoOIC
   289  TI4okOaUXoybDCevNBPHX8qIO4mf/9P52i4dix5zjp/n1qZFBCmviL6an2kt9CGcYnJznJpOBwegq4vQ
   290  L9xIUytSkfu/bv70p7j6EnQgjHSpFGVqXclkkaHb1+makUHgdazm7IFuSKOasrnjis2+oDm9qnIHlgd/
   291  es7gxqjkt1NLwH4xTTEhjkhutM3D15oGhkcnBGRTDKu3A7H1rS3cLn//1PEhJ8uM557UvmDaa/P7a3Ps
   292  xpZcZ6mo5WG45pdUC2K8ko5JIzWfcTqu7HPHrW9OLbKWhSluVLNz3wKrS3I3KfcV1Rg9CrpXK8l0F7io
   293  pLnLnJHGOldMYJGMpu5XNwuxjyRTBcAAjd1HWtfZmPORy3WAWWQDOM4PWtHRru6DFlmY88ZqKsVyXaKp
   294  QjOoa7axe28G/cWqhoHjO/n1WeJwSkS9c981wUcFCopPayFj8JC8VFbs6e38VldvmHHFaMHimAoCzDB6
   295  V5U8FKz5TlrZU4/CXYtdtnXIarEepW7jAcfnXGqEoKx5tfBzh0P/1fnqEAsc/wB6pI9owAD1618Qn3Ps
   296  35EE4UzHrx79aXaMcdaqAMWIADvj271IMeXg59KUmNLQkUDfjb1FSLxzg0pWJRLGAQAeMVIoA+uaxlaw
   297  0SoF/u1KowwwDUcwuo9wMjrUrY2ZPOKy0KY1T1NMdwG/CtBEFzMqnIPNUZ75FBJP5mtIQvYfoU21JFVs
   298  N271AurRE/e611xw73Yj/9b50GsQhOXHWnpq8JX7w4PWvjPq76H2fzHjVYCud9Q3GrRAZDUvq75kNbMz
   299  7vV0zjdjNZ82pqzMcj7tdlPDtIiVWKKct+AxwRxUbXi7VPJAIrZUdEZOsrsga8DFgelQtd98g5P6V0Qp
   300  GE6qIUut2cZ470kd2FjYc4Oce1bSpJ3Rzxq21GNcDZhSeg710ujKRbKzAg5rkxceWnqd+XtOo7bD9cl8
   301  qxLDPHasXwUvmyXU7Lgl8cegrnw2lGbZ14l3rU0bl3gMQCRgVU1y7WytUZQzMRwBXPRhzWRvVny3ZW8N
   302  6xPdXBikiZc5IOa6GG6nDsd5xnAyfaliqEacrGOHarx5pI//1/nuL754HWngEkYx1r4VWsfaMjk4mP8A
   303  OgnjPH1rRMLKwR4A2jH1FPA+TNRIa0ROvQcY4p4GF/pUskmi6+gqRACvPrWMnpca3JABjFSKCQOnFS2u
   304  o7E3XBOKcR8ucdKzUkDGSHGemKpXchVuP0rSmDMfUrl1J5rn9TvnVCc9OtelhoJtDekW0Yb6pId3zdRw
   305  RVT+0pAPvc57CvbhQVrHlTxD3P8A/9D4tbUpTH1I7cU/7ZdMnyqcdsV5vsErXPbWJbHLdXzYQDBY8c02
   306  6udQjyGVuD1FHsqfMridepZ6ED3s4IDqeD0I68VEt7J5hy3GO9aKkuhPt2BumeRjnv3pJLlgwBYE8ZqH
   307  T2GqujYLcuWYbhj0zTHm5B/vcGtVBLYzdRtEcUueoGB3FOjmBjcBhx2NNx1IhO+uwtqd93EgA5YcV32n
   308  IqwrnAz2rzMx+FI9nKldy+RmeMpfLs8DGTxTvBUKw6Csjry2WPbrXHB2wzfdnbUu8SvJF4xh1LDAJNU9
   309  UtVmDs3IiGB6CuenNx1R0yjfRGd4aRTqJdFG1ARXRgANg4/yK0xbvJehnhlaL9T/AP/R+e4x8xx609F+
   310  YZ718L6n2ju2RzqTKcYpQMjsc1pHTQWlgjUjGVH0qbkr0BqJSKRMi+uBx3p8a5HYVD8yb32JY15FSKpx
   311  nisp6RuNbj1BzUyrnkmo6FEqrz7U/advHOazvcRHIuSazNXDpbSSJjeqErnpmrp6CueeXusahO5zKi8c
   312  7VrPuGklUiSQtkd6+po0YQs0edVrTd1cqeSoJOB0xUCxpnouAecV33e558rbH//S+KdmFHTk1btywUqc
   313  YNcEnfc9SGl7DyAJ1AHIParx+YZ4/Guea2OmC1dhGjQn5kXNQtbQFiWiTlfSoTa2G0nuU5bG2aQ7V2jP
   314  JU+1RSaXC2GjuApyOorX2slYz9lF3sV/7MmViFljaoJLG6SQbkyDXQqiZzyg1Yg8i4jBJjIBpsaPyXXB
   315  Psea1TTMJJqysaeh2u/UUfP3QCBXdQJtTpivFzKV3FH0WURtCT8zmPHcrhkRSOWro7O28rRYIgOwGB3r
   316  mnph4+bOxNvEy8kWFi+ULxwKzNRkMemSPj/WMT+FckNWdLv0KPhCMmGSZl6k1ulC3zY5x2+la4r+IyKH
   317  wH//0/nuIHB9c9KevUAHk18La60PtHuRy/64+lOGBniqXcOlhUIxwB+NSrynSpndFImQc4A7d6lQccdR
   318  WcyUyWMccDnPSpVAwM1nLYaeo5BjrUyjFTugJIwd2Kfgkc59qyTs7Axkigqao3qBkYdiMVpTeugHmF7b
   319  hbhl2/dJB/OofJBTHfp9K+ppTbimeZOK5issYG5W7VWdBnHXB65rrjJs5JLof//U+LYtu7leM+lSpxIR
   320  7VwO90eskrNkqZLo3PXHoausxI4wa557o2p6JitnOCoqvI3zEkdF5qIrUuW2ogO1iWHeibazIQncHA+l
   321  DT0aCyaaZGNm8kA9PSl2qy9SB78Veq1ZCs9BkOGUrj86zdQGbllVMAe1bQdpGE1eBo+FoCbgtxkY966+
   322  E4hOeo5rycxleR72VwcaRx+t/wCmeJ7WAdDIOPpzXbSpt/dkcRr+tZ4j3aVNLzNKOteo/QjuiY7Jm6Ej
   323  ANYnitvL05YRxwOf8/WuXDK8l6nVUlaLZb8NQeXpijgZB/M1oIpyPzx74pV2nUbHTVoJH//V+fYhgnnv
   324  Txy4GBXwse59m7kMyEzkj8qkQfKatdgewIo7nIqdQAnXms52RSehMoHHPapY1wMAgVnKzFtqSwjjg4qR
   325  VJHXIzWc2rDiPVeeD+FSDqKh2sBKo54p+Pl61jbQG9RrDIPNU7teT6VpCztYDzfxGskWtXESdN5Pp15q
   326  gN2GZpB0r6ig17OL8jz535miCSPdnaxHHpVV48D7xIB7iu2LOOS7H//W+MCoeIDcc5p4VhIMDkDvXnpq
   327  +p6zu0SwZZlVm6HJFWyRg89MdawmkmrG1NtpiMcY5OevFQ7AWOT0FSkkU9UKUPmEh8jt+VMdGLDLYAIz
   328  xUtrQfLo7Mj2SHjePrSspxgEk1rdGSTGJjymLEZArOjAd5GLHk9DW0NGznqa8qOj8IRHBbrnnmugu08u
   329  1ZiSMn868LGz/eH1GAVqKOW8LR/bfG4c8rCCx46HpXZspk88jHzMf04pY7eEfIjDO7nLz/yKmqh/sjwR
   330  EFwAemcVhamkmpTRxKpyCN2RWeFsveZ01FpbubsEaRWyqhAxnH5YpxIx8rf/AFuK5W3Jts2Wisf/1/n5
   331  SSxHOM+lP7jGa+EVz7R2IpATN1IIpwB55NaJ2FuhYzx3PvU69OQaio7sEiZOvfpU0YwmMVnJ26DRJH2G
   332  DipUyR361jN6FIeq8/0qUdBxWbkCRIg/D6U8j5e9Rza3ExrA8nmqt0Dkmri9BnnfjlSmvuwGQyhulYkr
   333  yL86DANfTYRp0o3PPr3UnYbBOWU4zz7VHIGIJVjkGu1x5Tl5ro//0Pi3fhgMHJPXFWCeQwLe9ec+jPXj
   334  1JIM7gw44qy+WPUjkcVjPdGsNmgdsNkjJFQ7mMhAB5FRHuXJ6WRIw+VwCc9KbtPy5JyCKgdmxhBDNj8s
   335  U1Cyr0J/rWultDOzTuMuSiWjlT97r7HFZ1nkk4bIPXiuiD3uc00rqzOy8Lw+XBuJPQcGrXiGYJYMwJHB
   336  xXz1d89U+sw8eWmkuxi/DGP/AEm+vHycYUE/jXXu6w2vzdcfiaMw1qpLsjnwi/dt+bKCn5nlw2W5Gacw
   337  GD2wB+dcq2O4AnyADoM80QLukUsp9f0qb6XHuf/R+fkOWNSfwjnivhUz7Nq2hFJ/retPA4PWrWuwul2L
   338  FjAA6VMMFeTms5PUpbEw6/hxUyfd4as5PUETRds9KlA+Xk96ym9FcaHJgGpOv1rPUpIkXg8mnNnGaz5r
   339  aCaEPeqtx1OT0rSL2sC1OG+ISquoQuT1UjP4/wD16wGEZUYGPevo8E26UThrpc7G7ICDzg+1ROmF+91O
   340  K7VKVrHNyxWx/9L4uuVAcH371JvKqScFPU1597pHqtWbZNZnc+QxI9atv8p4z9ayqPVI1pr3WyPBLDGf
   341  qKYnExyeQKlFPQXH7zgdetSk8rgEnis29i0lqxijLEjjt1poU7iVHHpVX3uRbsZl+2IvLX+I56U/TUUA
   342  KxGSfSulu0XY5oq80drpcZSzHvjpWd47fy9O2g8kjpXz0ZJ1kvM+skrUnbsSfDm1C+HlfJ/euXIPRq3b
   343  lleQRYBCg5HrSxk+au/IxwkbUokRw0u0cBFyR70wEEbm6sc/gK5YuyZ1PzFVgVG4ZIzmpbTaJMt07+3F
   344  Q9i7n//T+foic55yTipRkYBBxXwaPtXuRyZEg4pWII4qk7C6BFwAf51MhG31+lZ1Frca2LKHn8qlDY6L
   345  UNgl1Jo+2akQ9BWVR9xpDgffrUq+wrO7tdDsSIPUUpPHvUK1xMM8HA61WmwWOB+NXENjiPiMhE1sw9WH
   346  8q5vqRnjivosD/BXzOKv8QkKgZBA6ZpV27MkDOa7ObsYI//U+MdVGxlK9zninqd1sCQM45rzYaxR68vj
   347  YtgT5h6jvV6Q5X0+lZ1n7yLofCxhOenfFMTI3cdRzWV9DWw5ARI3qPSnMSqKCOSRUy6FRurjFLjPp9KA
   348  xx06n1q1qjO70Me6YtcOOcKcH1q9oqF5l75Oea6KtowOagnKol5neWcSJaocdgRzXGfEm53ERKfvEV89
   349  gvfxCPqcXLlw8/Q6fwkph0aCEg4VB/KrsDbmcnA4PWoxFnVkxUVaml5IgR9sMj4+ZzSTuTjcOB0/CsUt
   350  zo0VrhCQiF2GcAn/AD+dWLRlYZPQ8cVEk7aF+p//1fAIuvfOakxnr+NfBJ2SsfaN6jJRiUA9RSheCMfn
   351  VXEtgjUk/wBTVgfdBwOfSs5stbE6g7unYVLGpwAazYvUmjHHanqDx061lLazKuh6DHBFSID27VEthkin
   352  5cUHOPxqLvqJiEYziq8/FaQ8hHH/ABEVvIhYYyHNcsrSZG5RyOtfQYC3slfzOPEX5tAA+amHIjO31ruu
   353  rHNa7P8A/9b411QMIwSDnNR2xYQNkjnnkV5sLctj15JqRLZjBzweeSKuycHkD8qyq6tF0rqLI2OTnK5p
   354  sGWbBHQd6zWxo3qSdXLYxTpPvLnvjrWdr2LvuNYYUnj6Uxyu4/KMrVx6ky6GOGLSOwXIYmr9n58UQeFg
   355  svbcCRXTVty2ZzYZOVRcpvDW721tv9LsBIpAHmQNn9K4zxPqSX2sK6hljDDO6uHBYWKre0i9PxPTzDFS
   356  VDkmtX9x2mm65YG0REnTccAc1rx3EJgbbIpyvUGuDE0JxleSO+hXhUj7rGK/7uNcj1P6UmSU+fHPJrlS
   357  5bnXe9mA/wBSQDxzkfh/+qp7YbIipbaOufwrN7WLR//X8DTO7I9e9SJnAIHNfBPY+ze4yQEPnGacoHof
   358  amvIELCDnnqanXoBzUSaRSRMo5J744qRBxzUSelwRPEMingdsVk7pFLckA5p44OTUXuh2HqOKRskE4qV
   359  sKQADkYqvcj8aqD0shWOV8fqDYqc4w4rj5D365Fe7lz/AHdjlxC11CNhyRnp0pqkYOc9a9G/c5bLof/Q
   360  +OdUH7sDnOeKrREgEN6V5tN+6exUT5rlm1IC9ec9qssBg5xzjNYzdpJmkNtRhJzgflSRDqD6flU7FkqZ
   361  55+holblfUVk90aLYYxJH3agvGCQPkjJ6DFaw7GMtrmdYpkcg1q6fsEwB6Ct8Q73M8DpKLZruu+3ZM43
   362  ADNctfeHt120cEjO3U7scmuDCVvZNux7GLw31iNmypLoN5byByrYzzxVfzdTtXcxzSAD3r0oYinW0Z41
   363  TB1cPrBlyy8S6nF9+QOMba1LbxepwsyFcYztrnrZdCabgb0MzlCyqGrZ+IbK4U7bgDg8E4rXtL+CQBfM
   364  VgTn9BXi1sJOno0e5SxVOqrxZ//R8DiGScip0HOAOa+CfkfaDJV+fpRjBIxT6iHRjnIHFTAYXBIqZ7lK
   365  1rEygZxUsYI68Gsm7gkSQ59PwqZRxx681lK/LYaHpjI7U8ge1ZK3Qdxw5XpijAOelGoNCDPOOaguOf8A
   366  CnFCOa8cJu0uTI6EHH41xLou3gYBr3culaLXmc2JV7DIx8pXHFNAxknGc16b0OM//9L44v8A/V5wMiqy
   367  /dbI6j1rzKb0PYq7li2C4HHHrVmT5Rx9ayqN8yLppKIwEj6+lPhAGfzNQ9rmqexKvcAYxTTjeM88isty
   368  xhI3mqWrNwqADB5ranozCo9GQaeBjByR1q2GIzjj2rasryMaErRVieK/kjwHbIGOBVrSbtZNRmlfAB+U
   369  ZP0/wrinQsnKPY9eljVJqM9zYgMTMAjoRnoRUV3ptrMrl4UY+o4rzIzcHc9Nx5kZc/hu1lUlBszWPqHh
   370  Z1lYxHJHQZr0cPmElpI87E5dCptoZl1o9zADuVhwfaqqz39tIPLeVMDoPpXqUqsKyPHr0KuGfun/0/Bo
   371  Rzlh+lToOBXwGltD7RjJQcjtSqODn9RVLyEEY96nVflzis6l3YpaEigdscCpl5XqeKiaVgJIhn/61Sgc
   372  AdOaylqkyluPXv7U8gZx/Koih9R+ML1ppHynIoRLEAqKYZ6njFVHRXBnP+Lk3aXN0yFz+tcM6j15r2cv
   373  ejOfEdLjMDb94ZHaoyvy9O/Y16mqOQ//1PjfUcBcnjJ9KqggRldo579682krxPWqO0i1AM7c59OlWJMA
   374  /lWVTdGtJaNiLg89afCMkjOOO1ZtGu5IpCs+emf6Uxug6Y45rO3UruiFmKydvrVK8ZZLogAn+ldNOPU5
   375  pvox1pH+7JzhumKlVfkOckmnNq5MI2SGScE5HTBqWDcBkMvJ6CpuraFWd+w3ULqW3gMsb4fOOO1VNP8A
   376  FGoxsyy7JFA6kYNKGDp1Y+8aSzCrh5e7qjesPE9s8eJh5eRnIrShvbG7AMUqZ+teVVwU6TbWqPaw+OpV
   377  0lezJWgV4yAVYc8GqV5pFpMMyW+O+V+lc1KtKD906q1KMlaR/9XwqPg9e9SqOQQetfnyfc+0Y2UfOKFy
   378  B25q1K+grCx564FTL93rilMaRKvXtz7U9OnfrWbtbQdyaLoOtSr/AFrOSstCl2HLnPNP5z1qNEA9s4FM
   379  7daSVhMAcZzTJlOD1prYDC8VoTpdzjP+rbH5V5w/nDkj9a9rK2mnc5sVeysQxmYMd4wDUkLM3LZFeu0u
   380  hxan/9b44v8AG35cnnNVArKM+tefS+HU9WoveuizCQCBuOT61ZcnGcgmsZrVG1N3TGrk4x3qWBQGPUHF
   381  RJspa7kjAFmwOp6Y9qSXPyDtkVgnsa9yFxhWYrj2rJUtJcFgB75rqpSvc5K0bWSRetV2Rg98c8d6UZCs
   382  M8AZPNTLWTuVFWiiIgjcBnDY5NToCsZAyDnqKUrtJDitWUfETbYI1Ixz7ZNYkXyzMAMevHSuvDfCceK3
   383  NKGIG0Ppj73pVdi0F2MMQDj7pog7uSYTXKotGxYajeQwA/aHOAeG5zV6HxJLCdk8KuvTK8dvSvNq4OFV
   384  6aM9ajmM6SSlqj//1/DIOpHGaljG4cYH4V+e62PtWEi45pvzcjIwKuLsS9RYwM9s1Jj5Md88molqUnYl
   385  Xlue1SryKlpodiWLGB6GpBWU9FcEPQd6eBgjNRYpCn7opDyM0Ru9RMQdxxzSODVR12F6mTryFrWVcfeU
   386  j9K82ctvxxXrZY7XRjiF7qEjUHgkYFQuuCeB19K9dO5xSSsf/9D44uwSmM556VXkXMJHGenFeZTvoexN
   387  Ilg4bBOTjrip5uQcY4x2qJ3ckVDSLQ6MdCPpT4uGIHGOaze1jRJbkjFgDgYpjEgqxI7dqyWhpuQ3rkQS
   388  HjpWfaR9/wCf1rqp6RZy1Peki8MGMfNx7d6jc7Yyc4ye1JptjvorjBneDw2QMVPEHBIOFwR3qbXF5ox/
   389  EDl71U4ODiqDrjJABIrsoaRSRx19ZNmrbD/RgScAjsag1CF9pcBTxWMXaTNZRbirDrF3CbSQTg9f5U+Z
   390  QJxwFBA/lRZc1yrvlsf/0fD4fvE1MnYk/nX5/wBD7R7iP1yMdaQLzRF9LCa7hGvOf0qXHy9qUtxkgXnt
   391  UqDk0pK7sCfYkUcYA6VKnIFYzWha7jhT1Hes42TsC1FIyOlNYEU4oT8hB3pGzt68U1tYVzP1IZQ56Yrz
   392  e6UC5lUrwGOB+Nepl3xNGddXiV0Y8jGPw6U1slSCec9a9m6OCx//0vji/wAiMY45qux3Rbh/KvNprRHr
   393  1N2iW3z5gHY81ZnA3AnipqfErF01aDuPhwXAPHSpME7jyOK53pKxt9kT5vmB4IPHFMkwcEnkkVPkPpqU
   394  75zt8sDBJ+tNtVCt8x59q6rWi7HKneSuTxAhCAQOcc0yQEA4br2FRfVqxfK7LUYw4weCu3n1qbdiNmOM
   395  EgY9KV9CXo2YF+VMyNx8zE5qMgsrhccdq7obK5xT3aRdtTi2VmPGMdc+lWJgr5XAGMfrWElq7G8XsmUx
   396  C8ZJjOQQcgdakVXZxv4PbjvijmTJlBr7z//T8RjIGPc1KhXqPXivzzdH2bWoSD5sg4INJwRzz9aEw2BM
   397  dM5qTjb60SdykSA88enepEOOKU31EkTREdqkH54NZT1Ra0Hd/SnHip0Q/IVjwPWmsePehPqiWC9T1pHH
   398  B5oTaFYoaiOOn415tqm4X842jiRh+tenlvxMzrfCV05JLDHTgD3ppYFCB6/Svb1aOHbc/wD/1PjnUv8A
   399  Vct3qq53IMeleZDZM9ipu0SRYDAkkewqxI24+w6VM90EL2aJYCN5AbgY/lU0R+9z+FZS0N076DZSNzc5
   400  yc0xyoUfh25qG9mU7XZnXLZuTgnaKsW4zjqRnriuiStHQ5Y/GOxgEVFuwpBA9+MVKsytUOjILcZ7daNQ
   401  ZEt3O7k8fjU3ldDbVmc/cPm4QYA/rS8gMD2zz6139EcF7tli2lVIAhVsYPap45lZiFG08DnrWLT1Ztde
   402  6kidMGMZHGD3pkqjcOcZ447cVjF6o0nZxbP/1fElB7HOD1qVQOOtfnSVj7VsRwNx60Ywp4PFOCVwvoIg
   403  HB9e1SAAjGcUpa7AiQDkf0qRRxgZGaUrWuwJYwOByalXGB6A1nOzRS3FAI70/GSOtTtuMVunemHGKUe1
   404  iRRgk0hwKqPkDZS1DkYFed+JEEWs3Q5GHz9M816GX6VPkZ1V7pQibOck8jrUbgDIA4r3epwJ6an/1vjf
   405  U9vl43YyelUwR5RGTxx0rzaauj1qrSlckiA3D5j071aYjccnHSlJXaHDZsntzkY3Z96lQjnnt9K55I3T
   406  GsRyDnI9ajfKKOemDxio7Iq+7M3JeVieSecYq7AMKF3Fj6V0zVlaxzQfvXGDpy2McdajjydwIO2h2Hd6
   407  ND41G8nAGMdD1qLV2zAFORl+R1qEtVcTdkzBl5vSCMgNwKlVG3MFJ4967r6I4bO7JY1BjJJ7Y6dDVqyQ
   408  CYkqTjvWEn7rN1unYtYQLntg9+tV2+aQBlbPTHrxWNPzNqux/9fxWMDP41IoUYr87WzPs3uEgBJ9uKAB
   409  tINCSbDoJGAMcdKkAG04/KiSXQpPQkXGcY7VINp56VLBbksYBxUgAx0rOadrDT7C45pxA4wKVkUhX7ZF
   410  NODzRG1iGAA5NIwGeB1FNLuBTvEBI7V5/wCNFP8Awkl1tIABUdP9kV35cl7VehFbWBlxbNuD8x9aY20Y
   411  xjOa96xwWstD/9D451XAhBOOTxVRlURdOa8ymrI9epu2SW23cMgDHb1qw4BcrgY9KJ25kOn8LLFsArYG
   412  McVIu3GdvOOTWLV2axeliOYgM+FzmoL1isAwME4GKVloDvqVoI9zEEAMMGrbIAmFUdcZrSbS0MqcWQBg
   413  0WMg4PalhCFCdpHWiXUFZtaDtqhywBwMY9Ko6sR5oXPTn2p09WianVIyEYebwMEnPNTL5eXBA4Hautp6
   414  WONSWt0TQMhUgjKj1q5bhQWKMDwBxWE20mbws3ElXy9pUEDqMd6hfaHUgE7B2HtWUO7NKiVrI//R8Vj4
   415  br37VMuT9TX55HY+ze+gMM5PSkzwR1AoWu4IRRg9akPC8HpSlfRFLXYeCN3TkipV60ulmBJGeR71IvTP
   416  Ws5K6Ghwp3FQkMH6elNJ461didOoq9SaRjxSjqwuVbgZkH1rzrxWwk8QXj9hIR+XFejl1nVt5EV/gM2I
   417  qCTjPTH50x+eRxya961tzzt9j//S+O9WJ+zjgDmqJYGDJYZNedSSaPXqu0tew+L7wPTvmrBO5x7Y5qZf
   418  EnYUPhZdhUZyO3pTgcOxGOR0rnbu7M6fhK9yVEvPy59O9QX75VBjnIoS+ETa95DLbdu6nnp7VYGSMk59
   419  vxrWemxlTZCvMe4BTg/nSRKHVsjGfpSe90C1VmTsG2H2x3rF1J1eVxgcHr+FVQWtyK7srFGAgOrHqDnp
   420  7VPGNzO/O3kkCut7pnGno0idCCNyt6Crca5ZiDjpgVzXsnc6X71rDyBgcbtucn8KhjBMpOfrz7VlTdtT
   421  Sqm7JH//2Q==
   422  `
   423  
   424  	data, err := base64.StdEncoding.DecodeString(base64EncodedImage)
   425  	if err != nil {
   426  		t.Fatalf("base64 DecodeString: %v", err)
   427  	}
   428  	if _, err = Decode(bytes.NewReader(data)); err != nil {
   429  		t.Fatalf("Decode: %v", err)
   430  	}
   431  }
   432  
   433  func TestExtraneousData(t *testing.T) {
   434  	// Encode a 1x1 red image.
   435  	src := image.NewRGBA(image.Rect(0, 0, 1, 1))
   436  	src.Set(0, 0, color.RGBA{0xff, 0x00, 0x00, 0xff})
   437  	buf := new(bytes.Buffer)
   438  	if err := Encode(buf, src, nil); err != nil {
   439  		t.Fatalf("encode: %v", err)
   440  	}
   441  	enc := buf.String()
   442  	// Sanity check that the encoded JPEG is long enough, that it ends in a
   443  	// "\xff\xd9" EOI marker, and that it contains a "\xff\xda" SOS marker
   444  	// somewhere in the final 64 bytes.
   445  	if len(enc) < 64 {
   446  		t.Fatalf("encoded JPEG is too short: %d bytes", len(enc))
   447  	}
   448  	if got, want := enc[len(enc)-2:], "\xff\xd9"; got != want {
   449  		t.Fatalf("encoded JPEG ends with %q, want %q", got, want)
   450  	}
   451  	if s := enc[len(enc)-64:]; !strings.Contains(s, "\xff\xda") {
   452  		t.Fatalf("encoded JPEG does not contain a SOS marker (ff da) near the end: % x", s)
   453  	}
   454  	// Test that adding some random junk between the SOS marker and the
   455  	// EOI marker does not affect the decoding.
   456  	rnd := rand.New(rand.NewSource(1))
   457  	for i, nerr := 0, 0; i < 1000 && nerr < 10; i++ {
   458  		buf.Reset()
   459  		// Write all but the trailing "\xff\xd9" EOI marker.
   460  		buf.WriteString(enc[:len(enc)-2])
   461  		// Write some random extraneous data.
   462  		for n := rnd.Intn(10); n > 0; n-- {
   463  			if x := byte(rnd.Intn(256)); x != 0xff {
   464  				buf.WriteByte(x)
   465  			} else {
   466  				// The JPEG format escapes a SOS 0xff data byte as "\xff\x00".
   467  				buf.WriteString("\xff\x00")
   468  			}
   469  		}
   470  		// Write the "\xff\xd9" EOI marker.
   471  		buf.WriteString("\xff\xd9")
   472  
   473  		// Check that we can still decode the resultant image.
   474  		got, err := Decode(buf)
   475  		if err != nil {
   476  			t.Errorf("could not decode image #%d: %v", i, err)
   477  			nerr++
   478  			continue
   479  		}
   480  		if got.Bounds() != src.Bounds() {
   481  			t.Errorf("image #%d, bounds differ: %v and %v", i, got.Bounds(), src.Bounds())
   482  			nerr++
   483  			continue
   484  		}
   485  		if averageDelta(got, src) > 2<<8 {
   486  			t.Errorf("image #%d changed too much after a round trip", i)
   487  			nerr++
   488  			continue
   489  		}
   490  	}
   491  }
   492  
   493  func TestIssue56724(t *testing.T) {
   494  	b, err := os.ReadFile("../testdata/video-001.jpeg")
   495  	if err != nil {
   496  		t.Fatal(err)
   497  	}
   498  
   499  	b = b[:24] // truncate image data
   500  
   501  	_, err = Decode(bytes.NewReader(b))
   502  	if err != io.ErrUnexpectedEOF {
   503  		t.Errorf("got: %v, want: %v", err, io.ErrUnexpectedEOF)
   504  	}
   505  }
   506  
   507  func TestIssue78368(t *testing.T) {
   508  	Decode(bytes.NewReader([]byte{
   509  		0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20,
   510  		0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   511  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0xff, 0xff, 0xff, 0xff,
   512  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   513  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   514  		0xff, 0xff, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01,
   515  		0xff, 0xff, 0xff, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   516  		0xff, 0xff, 0xff, 0xff, 0x20, 0xff, 0xff, 0x20, 0x20, 0xff, 0xff, 0xff,
   517  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   518  		0xff, 0xff, 0xff, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   519  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   520  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x00, 0x11, 0x08, 0x00,
   521  		0x20, 0x00, 0x20, 0x03, 0x01, 0x11, 0x00, 0x20, 0x21, 0x01, 0xff, 0x11,
   522  		0x01, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   523  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   524  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   525  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   526  		0x20, 0x20, 0x20, 0x20, 0xff, 0xc4, 0x00, 0x27, 0x10, 0x01, 0x00, 0x02,
   527  		0x01, 0x04, 0x01, 0x03, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
   528  		0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   529  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0xda, 0x00,
   530  		0x08, 0x01, 0x20, 0x20, 0x20, 0x20, 0xed, 0x20, 0x20, 0x20, 0x20, 0x20,
   531  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   532  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   533  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   534  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   535  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0xee, 0x00, 0x0e, 0x41,
   536  		0x64, 0x6f, 0x62, 0x65, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0xff,
   537  		0xdb, 0x00, 0x43, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   538  		0x20, 0x20, 0x20, 0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0xff, 0xff,
   539  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0xff, 0xff, 0xff,
   540  		0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   541  		0xff, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   542  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   543  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   544  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   545  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   546  		0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   547  		0xff, 0xd9, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   548  	}))
   549  }
   550  
   551  func TestBadRestartMarker(t *testing.T) {
   552  	b, err := os.ReadFile("../testdata/video-001.restart2.jpeg")
   553  	if err != nil {
   554  		t.Fatal(err)
   555  	} else if len(b) != 4855 {
   556  		t.Fatal("test image had unexpected length")
   557  	} else if (b[2816] != 0xff) || (b[2817] != 0xd1) {
   558  		t.Fatal("test image did not have FF D1 restart marker at expected offset")
   559  	}
   560  	prefix, suffix := b[:2816], b[2816:]
   561  
   562  	testCases := []string{
   563  		"PASS:",
   564  		"PASS:\x00",
   565  		"PASS:\x61",
   566  		"PASS:\x61\x62\x63\xff\x00\x64",
   567  		"PASS:\xff",
   568  		"PASS:\xff\x00",
   569  		"PASS:\xff\xff\xff\x00\xff\x00\x00\xff\xff\xff",
   570  
   571  		"FAIL:\xff\x03",
   572  		"FAIL:\xff\xd5",
   573  		"FAIL:\xff\xff\xd5",
   574  	}
   575  
   576  	for _, tc := range testCases {
   577  		want := tc[:5] == "PASS:"
   578  		infix := tc[5:]
   579  
   580  		data := []byte(nil)
   581  		data = append(data, prefix...)
   582  		data = append(data, infix...)
   583  		data = append(data, suffix...)
   584  		_, err := Decode(bytes.NewReader(data))
   585  		got := err == nil
   586  
   587  		if got != want {
   588  			t.Errorf("%q: got %v, want %v", tc, got, want)
   589  		}
   590  	}
   591  }
   592  
   593  // TestDecodeFlexSubsampling tests that decoding images with non-standard
   594  // (flex) subsampling ratios works correctly.
   595  func TestDecodeFlexSubsampling(t *testing.T) {
   596  	// These test cases have non-standard subsampling ratios where either:
   597  	// - Cb and Cr have different sampling factors, or
   598  	// - Y doesn't have the maximum sampling factors.
   599  	testCases := []struct {
   600  		name     string
   601  		filename string
   602  	}{
   603  		{"2x2,1x1,2x2", "../testdata/video-001.q50.221122.jpeg"}, // Cb differs from Cr
   604  		{"2x1,1x2,1x1", "../testdata/video-001.q50.211211.jpeg"}, // All three differ
   605  		{"2x2,2x1,1x2", "../testdata/video-001.q50.222112.jpeg"}, // All three differ
   606  		{"1x2,1x1,2x1", "../testdata/video-001.q50.121121.jpeg"}, // Y not max, all differ
   607  	}
   608  	for _, tc := range testCases {
   609  		t.Run(tc.name, func(t *testing.T) {
   610  			m, err := decodeFile(tc.filename)
   611  			if err != nil {
   612  				t.Fatalf("decodeFile(%q): %v", tc.filename, err)
   613  			}
   614  			// All video-001 images are 150x103.
   615  			if got, want := m.Bounds(), image.Rect(0, 0, 150, 103); got != want {
   616  				t.Errorf("bounds: got %v, want %v", got, want)
   617  			}
   618  			// Flex subsampling should produce YCbCr images with 4:4:4 ratio.
   619  			ycbcr, ok := m.(*image.YCbCr)
   620  			if !ok {
   621  				t.Fatalf("got %T, want *image.YCbCr", m)
   622  			}
   623  			if got, want := ycbcr.SubsampleRatio, image.YCbCrSubsampleRatio444; got != want {
   624  				t.Errorf("subsample ratio: got %v, want %v", got, want)
   625  			}
   626  		})
   627  	}
   628  }
   629  
   630  func benchmarkDecode(b *testing.B, filename string) {
   631  	data, err := os.ReadFile(filename)
   632  	if err != nil {
   633  		b.Fatal(err)
   634  	}
   635  	cfg, err := DecodeConfig(bytes.NewReader(data))
   636  	if err != nil {
   637  		b.Fatal(err)
   638  	}
   639  	b.SetBytes(int64(cfg.Width * cfg.Height * 4))
   640  	b.ReportAllocs()
   641  	b.ResetTimer()
   642  	for i := 0; i < b.N; i++ {
   643  		Decode(bytes.NewReader(data))
   644  	}
   645  }
   646  
   647  func BenchmarkDecodeBaseline(b *testing.B) {
   648  	benchmarkDecode(b, "../testdata/video-001.jpeg")
   649  }
   650  
   651  func BenchmarkDecodeProgressive(b *testing.B) {
   652  	benchmarkDecode(b, "../testdata/video-001.progressive.jpeg")
   653  }
   654  

View as plain text