~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/image/jpeg/reader_test.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

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