]> Cypherpunks repositories - gostls13.git/commitdiff
image/jpeg: fix progressive decoding when the DC components are split
authorNigel Tao <nigeltao@golang.org>
Thu, 27 Feb 2014 23:37:21 +0000 (10:37 +1100)
committerNigel Tao <nigeltao@golang.org>
Thu, 27 Feb 2014 23:37:21 +0000 (10:37 +1100)
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

src/pkg/image/jpeg/reader_test.go
src/pkg/image/jpeg/scan.go
src/pkg/image/testdata/video-001.separate.dc.progression.jpeg [new file with mode: 0644]
src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg [new file with mode: 0644]

index e951e038c067030f209086813940ab0da366871e..926bb043448d2d9927aa099a8cee37aca8933cbd 100644 (file)
@@ -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),
index a69ed17489c6c8bce0d74b2390edbf97cb9a0ff4..559235d51272a3f0f93bc1cc1736ad6e9ebd9dfc 100644 (file)
@@ -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 (file)
index 0000000..107f0fa
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 (file)
index 0000000..a1d493e
Binary files /dev/null and b/src/pkg/image/testdata/video-001.separate.dc.progression.progressive.jpeg differ