From: Nigel Tao Date: Thu, 27 Feb 2014 23:37:21 +0000 (+1100) Subject: image/jpeg: fix progressive decoding when the DC components are split X-Git-Tag: go1.3beta1~538 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ea34ca768f5d2aff6ad23ec6169f5ac42db19716;p=gostls13.git 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 --- diff --git a/src/pkg/image/jpeg/reader_test.go b/src/pkg/image/jpeg/reader_test.go index e951e038c0..926bb04344 100644 --- a/src/pkg/image/jpeg/reader_test.go +++ b/src/pkg/image/jpeg/reader_test.go @@ -28,6 +28,7 @@ func TestDecodeProgressive(t *testing.T) { "../testdata/video-001.q50.444", "../testdata/video-005.gray.q50", "../testdata/video-005.gray.q50.2x2", + "../testdata/video-001.separate.dc.progression", } for _, tc := range testCases { m0, err := decodeFile(tc + ".jpeg") @@ -44,6 +45,12 @@ func TestDecodeProgressive(t *testing.T) { t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds()) continue } + // All of the video-*.jpeg files are 150x103. + if m0.Bounds() != image.Rect(0, 0, 150, 103) { + t.Errorf("%s: bad bounds: %v", tc, m0.Bounds()) + continue + } + switch m0 := m0.(type) { case *image.YCbCr: m1 := m1.(*image.YCbCr) @@ -84,18 +91,15 @@ func decodeFile(filename string) (image.Image, error) { // check checks that the two pix data are equal, within the given bounds. func check(bounds image.Rectangle, pix0, pix1 []byte, stride0, stride1 int) error { - if len(pix0) != len(pix1) { - return fmt.Errorf("len(pix) %d and %d differ", len(pix0), len(pix1)) - } - if stride0 != stride1 { - return fmt.Errorf("strides %d and %d differ", stride0, stride1) + if stride0 <= 0 || stride0%8 != 0 { + return fmt.Errorf("bad stride %d", stride0) } - if stride0%8 != 0 { - return fmt.Errorf("stride %d is not a multiple of 8", stride0) + if stride1 <= 0 || stride1%8 != 0 { + return fmt.Errorf("bad stride %d", stride1) } // Compare the two pix data, one 8x8 block at a time. - for y := 0; y < len(pix0)/stride0; y += 8 { - for x := 0; x < stride0; x += 8 { + for y := 0; y < len(pix0)/stride0 && y < len(pix1)/stride1; y += 8 { + for x := 0; x < stride0 && x < stride1; x += 8 { if x >= bounds.Max.X || y >= bounds.Max.Y { // We don't care if the two pix data differ if the 8x8 block is // 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 for j := 0; j < 8; j++ { for i := 0; i < 8; i++ { - index := (y+j)*stride0 + (x + i) - if pix0[index] != pix1[index] { + index0 := (y+j)*stride0 + (x + i) + index1 := (y+j)*stride1 + (x + i) + if pix0[index0] != pix1[index1] { return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y, pixString(pix0, stride0, x, y), pixString(pix1, stride1, x, y), diff --git a/src/pkg/image/jpeg/scan.go b/src/pkg/image/jpeg/scan.go index a69ed17489..559235d512 100644 --- a/src/pkg/image/jpeg/scan.go +++ b/src/pkg/image/jpeg/scan.go @@ -141,25 +141,30 @@ func (d *decoder) processSOS(n int) error { for j := 0; j < d.comp[compIndex].h*d.comp[compIndex].v; j++ { // The blocks are traversed one MCU at a time. For 4:2:0 chroma // subsampling, there are four Y 8x8 blocks in every 16x16 MCU. + // // For a baseline 32x16 pixel image, the Y blocks visiting order is: // 0 1 4 5 // 2 3 6 7 // - // For progressive images, the DC data blocks (zigStart == 0) are traversed - // as above, but AC data blocks are traversed left to right, top to bottom: + // For progressive images, the interleaved scans (those with nComp > 1) + // are traversed as above, but non-interleaved scans are traversed left + // to right, top to bottom: // 0 1 2 3 // 4 5 6 7 + // Only DC scans (zigStart == 0) can be interleaved. AC scans must have + // only one component. // - // To further complicate matters, there is no AC data for any blocks that - // are inside the image at the MCU level but outside the image at the pixel - // level. For example, a 24x16 pixel 4:2:0 progressive image consists of - // two 16x16 MCUs. The earlier scans will process 8 Y blocks: + // To further complicate matters, for non-interleaved scans, there is no + // data for any blocks that are inside the image at the MCU level but + // outside the image at the pixel level. For example, a 24x16 pixel 4:2:0 + // progressive image consists of two 16x16 MCUs. The interleaved scans + // will process 8 Y blocks: // 0 1 4 5 // 2 3 6 7 - // The later scans will process only 6 Y blocks: + // The non-interleaved scans will process only 6 Y blocks: // 0 1 2 // 3 4 5 - if zigStart == 0 { + if nComp != 1 { mx0, my0 = d.comp[compIndex].h*mx, d.comp[compIndex].v*my if h0 == 1 { my0 += j diff --git a/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg b/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg new file mode 100644 index 0000000000..107f0fa0cd Binary files /dev/null and b/src/pkg/image/testdata/video-001.separate.dc.progression.jpeg differ diff --git a/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg new file mode 100644 index 0000000000..a1d493ef80 Binary files /dev/null and b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg differ