reader_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. package jpeg
  5. import (
  6. "bytes"
  7. "fmt"
  8. "image"
  9. "image/color"
  10. "io"
  11. "io/ioutil"
  12. "math/rand"
  13. "os"
  14. "strings"
  15. "testing"
  16. )
  17. // TestDecodeProgressive tests that decoding the baseline and progressive
  18. // versions of the same image result in exactly the same pixel data, in YCbCr
  19. // space for color images, and Y space for grayscale images.
  20. func TestDecodeProgressive(t *testing.T) {
  21. testCases := []string{
  22. "../testdata/video-001",
  23. "../testdata/video-001.q50.420",
  24. "../testdata/video-001.q50.422",
  25. "../testdata/video-001.q50.440",
  26. "../testdata/video-001.q50.444",
  27. "../testdata/video-005.gray.q50",
  28. "../testdata/video-005.gray.q50.2x2",
  29. "../testdata/video-001.separate.dc.progression",
  30. }
  31. for _, tc := range testCases {
  32. m0, err := decodeFile(tc + ".jpeg")
  33. if err != nil {
  34. t.Errorf("%s: %v", tc+".jpeg", err)
  35. continue
  36. }
  37. m1, err := decodeFile(tc + ".progressive.jpeg")
  38. if err != nil {
  39. t.Errorf("%s: %v", tc+".progressive.jpeg", err)
  40. continue
  41. }
  42. if m0.Bounds() != m1.Bounds() {
  43. t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds())
  44. continue
  45. }
  46. // All of the video-*.jpeg files are 150x103.
  47. if m0.Bounds() != image.Rect(0, 0, 150, 103) {
  48. t.Errorf("%s: bad bounds: %v", tc, m0.Bounds())
  49. continue
  50. }
  51. switch m0 := m0.(type) {
  52. case *image.YCbCr:
  53. m1 := m1.(*image.YCbCr)
  54. if err := check(m0.Bounds(), m0.Y, m1.Y, m0.YStride, m1.YStride); err != nil {
  55. t.Errorf("%s (Y): %v", tc, err)
  56. continue
  57. }
  58. if err := check(m0.Bounds(), m0.Cb, m1.Cb, m0.CStride, m1.CStride); err != nil {
  59. t.Errorf("%s (Cb): %v", tc, err)
  60. continue
  61. }
  62. if err := check(m0.Bounds(), m0.Cr, m1.Cr, m0.CStride, m1.CStride); err != nil {
  63. t.Errorf("%s (Cr): %v", tc, err)
  64. continue
  65. }
  66. case *image.Gray:
  67. m1 := m1.(*image.Gray)
  68. if err := check(m0.Bounds(), m0.Pix, m1.Pix, m0.Stride, m1.Stride); err != nil {
  69. t.Errorf("%s: %v", tc, err)
  70. continue
  71. }
  72. default:
  73. t.Errorf("%s: unexpected image type %T", tc, m0)
  74. continue
  75. }
  76. }
  77. }
  78. func decodeFile(filename string) (image.Image, error) {
  79. f, err := os.Open(filename)
  80. if err != nil {
  81. return nil, err
  82. }
  83. defer f.Close()
  84. return Decode(f)
  85. }
  86. type eofReader struct {
  87. data []byte // deliver from Read without EOF
  88. dataEOF []byte // then deliver from Read with EOF on last chunk
  89. lenAtEOF int
  90. }
  91. func (r *eofReader) Read(b []byte) (n int, err error) {
  92. if len(r.data) > 0 {
  93. n = copy(b, r.data)
  94. r.data = r.data[n:]
  95. } else {
  96. n = copy(b, r.dataEOF)
  97. r.dataEOF = r.dataEOF[n:]
  98. if len(r.dataEOF) == 0 {
  99. err = io.EOF
  100. if r.lenAtEOF == -1 {
  101. r.lenAtEOF = n
  102. }
  103. }
  104. }
  105. return
  106. }
  107. func TestDecodeEOF(t *testing.T) {
  108. // Check that if reader returns final data and EOF at same time, jpeg handles it.
  109. data, err := ioutil.ReadFile("../testdata/video-001.jpeg")
  110. if err != nil {
  111. t.Fatal(err)
  112. }
  113. n := len(data)
  114. for i := 0; i < n; {
  115. r := &eofReader{data[:n-i], data[n-i:], -1}
  116. _, err := Decode(r)
  117. if err != nil {
  118. t.Errorf("Decode with Read() = %d, EOF: %v", r.lenAtEOF, err)
  119. }
  120. if i == 0 {
  121. i = 1
  122. } else {
  123. i *= 2
  124. }
  125. }
  126. }
  127. // check checks that the two pix data are equal, within the given bounds.
  128. func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error {
  129. if stride0 <= 0 || stride0%8 != 0 {
  130. return fmt.Errorf("bad stride %d", stride0)
  131. }
  132. if stride1 <= 0 || stride1%8 != 0 {
  133. return fmt.Errorf("bad stride %d", stride1)
  134. }
  135. // Compare the two pix data, one 8x8 block at a time.
  136. for y := 0; y < len(pix0)/stride0 && y < len(pix1)/stride1; y += 8 {
  137. for x := 0; x < stride0 && x < stride1; x += 8 {
  138. if x >= bounds.Max.X || y >= bounds.Max.Y {
  139. // We don't care if the two pix data differ if the 8x8 block is
  140. // entirely outside of the image's bounds. For example, this can
  141. // occur with a 4:2:0 chroma subsampling and a 1x1 image. Baseline
  142. // decoding works on the one 16x16 MCU as a whole; progressive
  143. // decoding's first pass works on that 16x16 MCU as a whole but
  144. // refinement passes only process one 8x8 block within the MCU.
  145. continue
  146. }
  147. for j := 0; j < 8; j++ {
  148. for i := 0; i < 8; i++ {
  149. index0 := (y+j)*stride0 + (x + i)
  150. index1 := (y+j)*stride1 + (x + i)
  151. if pix0[index0] != pix1[index1] {
  152. return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y,
  153. pixString(pix0, stride0, x, y),
  154. pixString(pix1, stride1, x, y),
  155. )
  156. }
  157. }
  158. }
  159. }
  160. }
  161. return nil
  162. }
  163. func pixString(pix []byte, stride, x, y int) string {
  164. s := bytes.NewBuffer(nil)
  165. for j := 0; j < 8; j++ {
  166. fmt.Fprintf(s, "\t")
  167. for i := 0; i < 8; i++ {
  168. fmt.Fprintf(s, "%02x ", pix[(y+j)*stride+(x+i)])
  169. }
  170. fmt.Fprintf(s, "\n")
  171. }
  172. return s.String()
  173. }
  174. func TestExtraneousData(t *testing.T) {
  175. // Encode a 1x1 red image.
  176. src := image.NewRGBA(image.Rect(0, 0, 1, 1))
  177. src.Set(0, 0, color.RGBA{0xff, 0x00, 0x00, 0xff})
  178. buf := new(bytes.Buffer)
  179. if err := Encode(buf, src, nil); err != nil {
  180. t.Fatalf("encode: %v", err)
  181. }
  182. enc := buf.String()
  183. // Sanity check that the encoded JPEG is long enough, that it ends in a
  184. // "\xff\xd9" EOI marker, and that it contains a "\xff\xda" SOS marker
  185. // somewhere in the final 64 bytes.
  186. if len(enc) < 64 {
  187. t.Fatalf("encoded JPEG is too short: %d bytes", len(enc))
  188. }
  189. if got, want := enc[len(enc)-2:], "\xff\xd9"; got != want {
  190. t.Fatalf("encoded JPEG ends with %q, want %q", got, want)
  191. }
  192. if s := enc[len(enc)-64:]; !strings.Contains(s, "\xff\xda") {
  193. t.Fatalf("encoded JPEG does not contain a SOS marker (ff da) near the end: % x", s)
  194. }
  195. // Test that adding some random junk between the SOS marker and the
  196. // EOI marker does not affect the decoding.
  197. rnd := rand.New(rand.NewSource(1))
  198. for i, nerr := 0, 0; i < 1000 && nerr < 10; i++ {
  199. buf.Reset()
  200. // Write all but the trailing "\xff\xd9" EOI marker.
  201. buf.WriteString(enc[:len(enc)-2])
  202. // Write some random extraneous data.
  203. for n := rnd.Intn(10); n > 0; n-- {
  204. if x := byte(rnd.Intn(256)); x != 0xff {
  205. buf.WriteByte(x)
  206. } else {
  207. // The JPEG format escapes a SOS 0xff data byte as "\xff\x00".
  208. buf.WriteString("\xff\x00")
  209. }
  210. }
  211. // Write the "\xff\xd9" EOI marker.
  212. buf.WriteString("\xff\xd9")
  213. // Check that we can still decode the resultant image.
  214. got, err := Decode(buf)
  215. if err != nil {
  216. t.Errorf("could not decode image #%d: %v", i, err)
  217. nerr++
  218. continue
  219. }
  220. if got.Bounds() != src.Bounds() {
  221. t.Errorf("image #%d, bounds differ: %v and %v", i, got.Bounds(), src.Bounds())
  222. nerr++
  223. continue
  224. }
  225. if averageDelta(got, src) > 2<<8 {
  226. t.Errorf("image #%d changed too much after a round trip", i)
  227. nerr++
  228. continue
  229. }
  230. }
  231. }
  232. func benchmarkDecode(b *testing.B, filename string) {
  233. b.StopTimer()
  234. data, err := ioutil.ReadFile(filename)
  235. if err != nil {
  236. b.Fatal(err)
  237. }
  238. cfg, err := DecodeConfig(bytes.NewReader(data))
  239. if err != nil {
  240. b.Fatal(err)
  241. }
  242. b.SetBytes(int64(cfg.Width * cfg.Height * 4))
  243. b.StartTimer()
  244. for i := 0; i < b.N; i++ {
  245. Decode(bytes.NewReader(data))
  246. }
  247. }
  248. func BenchmarkDecodeBaseline(b *testing.B) {
  249. benchmarkDecode(b, "../testdata/video-001.jpeg")
  250. }
  251. func BenchmarkDecodeProgressive(b *testing.B) {
  252. benchmarkDecode(b, "../testdata/video-001.progressive.jpeg")
  253. }