Skip to content

Commit ea34ca7

Browse files
committed
image/jpeg: fix progressive decoding when the DC components are split
over multiple scans. Previously, the Go code assumed that DC was synonymous with interleaved and AC with non-interleaved. Fixes #6767. The test files were generated with libjpeg's cjpeg program, version 9a, with the following patch, since cjpeg is hard-coded to output interleaved DC. $ diff -u jpeg-9a*/jcparam.c --- jpeg-9a-clean/jcparam.c 2013-07-01 21:13:28.000000000 +1000 +++ jpeg-9a/jcparam.c 2014-02-27 11:40:41.236889852 +1100 @@ -572,7 +572,7 @@ { int ci; - if (ncomps <= MAX_COMPS_IN_SCAN) { + if (0) { /* Single interleaved DC scan */ scanptr->comps_in_scan = ncomps; for (ci = 0; ci < ncomps; ci++) @@ -610,7 +610,7 @@ (cinfo->jpeg_color_space == JCS_YCbCr || cinfo->jpeg_color_space == JCS_BG_YCC)) { /* Custom script for YCC color images. */ - nscans = 10; + nscans = 14; } else { /* All-purpose script for other color spaces. */ if (ncomps > MAX_COMPS_IN_SCAN) LGTM=r R=r CC=golang-codereviews https://golang.org/cl/69000046
1 parent e944554 commit ea34ca7

File tree

4 files changed

+29
-19
lines changed

4 files changed

+29
-19
lines changed

src/pkg/image/jpeg/reader_test.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func TestDecodeProgressive(t *testing.T) {
2828
"../testdata/video-001.q50.444",
2929
"../testdata/video-005.gray.q50",
3030
"../testdata/video-005.gray.q50.2x2",
31+
"../testdata/video-001.separate.dc.progression",
3132
}
3233
for _, tc := range testCases {
3334
m0, err := decodeFile(tc + ".jpeg")
@@ -44,6 +45,12 @@ func TestDecodeProgressive(t *testing.T) {
4445
t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds())
4546
continue
4647
}
48+
// All of the video-*.jpeg files are 150x103.
49+
if m0.Bounds() != image.Rect(0, 0, 150, 103) {
50+
t.Errorf("%s: bad bounds: %v", tc, m0.Bounds())
51+
continue
52+
}
53+
4754
switch m0 := m0.(type) {
4855
case *image.YCbCr:
4956
m1 := m1.(*image.YCbCr)
@@ -84,18 +91,15 @@ func decodeFile(filename string) (image.Image, error) {
8491

8592
// check checks that the two pix data are equal, within the given bounds.
8693
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)
94+
if stride0 <= 0 || stride0%8 != 0 {
95+
return fmt.Errorf("bad stride %d", stride0)
9296
}
93-
if stride0%8 != 0 {
94-
return fmt.Errorf("stride %d is not a multiple of 8", stride0)
97+
if stride1 <= 0 || stride1%8 != 0 {
98+
return fmt.Errorf("bad stride %d", stride1)
9599
}
96100
// 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 {
101+
for y := 0; y < len(pix0)/stride0 && y < len(pix1)/stride1; y += 8 {
102+
for x := 0; x < stride0 && x < stride1; x += 8 {
99103
if x >= bounds.Max.X || y >= bounds.Max.Y {
100104
// We don't care if the two pix data differ if the 8x8 block is
101105
// entirely outside of the image's bounds. For example, this can
@@ -108,8 +112,9 @@ func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) erro
108112

109113
for j := 0; j < 8; j++ {
110114
for i := 0; i < 8; i++ {
111-
index := (y+j)*stride0 + (x + i)
112-
if pix0[index] != pix1[index] {
115+
index0 := (y+j)*stride0 + (x + i)
116+
index1 := (y+j)*stride1 + (x + i)
117+
if pix0[index0] != pix1[index1] {
113118
return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y,
114119
pixString(pix0, stride0, x, y),
115120
pixString(pix1, stride1, x, y),

src/pkg/image/jpeg/scan.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,25 +141,30 @@ func (d *decoder) processSOS(n int) error {
141141
for j := 0; j < d.comp[compIndex].h*d.comp[compIndex].v; j++ {
142142
// The blocks are traversed one MCU at a time. For 4:2:0 chroma
143143
// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
144+
//
144145
// For a baseline 32x16 pixel image, the Y blocks visiting order is:
145146
// 0 1 4 5
146147
// 2 3 6 7
147148
//
148-
// For progressive images, the DC data blocks (zigStart == 0) are traversed
149-
// as above, but AC data blocks are traversed left to right, top to bottom:
149+
// For progressive images, the interleaved scans (those with nComp > 1)
150+
// are traversed as above, but non-interleaved scans are traversed left
151+
// to right, top to bottom:
150152
// 0 1 2 3
151153
// 4 5 6 7
154+
// Only DC scans (zigStart == 0) can be interleaved. AC scans must have
155+
// only one component.
152156
//
153-
// To further complicate matters, there is no AC data for any blocks that
154-
// are inside the image at the MCU level but outside the image at the pixel
155-
// level. For example, a 24x16 pixel 4:2:0 progressive image consists of
156-
// two 16x16 MCUs. The earlier scans will process 8 Y blocks:
157+
// To further complicate matters, for non-interleaved scans, there is no
158+
// data for any blocks that are inside the image at the MCU level but
159+
// outside the image at the pixel level. For example, a 24x16 pixel 4:2:0
160+
// progressive image consists of two 16x16 MCUs. The interleaved scans
161+
// will process 8 Y blocks:
157162
// 0 1 4 5
158163
// 2 3 6 7
159-
// The later scans will process only 6 Y blocks:
164+
// The non-interleaved scans will process only 6 Y blocks:
160165
// 0 1 2
161166
// 3 4 5
162-
if zigStart == 0 {
167+
if nComp != 1 {
163168
mx0, my0 = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
164169
if h0 == 1 {
165170
my0 += j
Loading
Loading

0 commit comments

Comments
 (0)