Commit ea34ca76 authored by Nigel Tao's avatar Nigel Tao

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
parent e9445547
......@@ -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),
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment