image/jpeg: support 4:1:1 and 4:1:0 chroma subsampling.

The test data was generated by:
convert video-001.png tmp.tga
cjpeg -quality 50 -sample 4x2,1x1,1x1 tmp.tga > video-001.q50.410.jpeg
cjpeg -quality 50 -sample 4x1,1x1,1x1 tmp.tga > video-001.q50.411.jpeg
cjpeg -quality 50 -sample 4x2,1x1,1x1 -progressive tmp.tga > video-001.q50.410.progressive.jpeg
cjpeg -quality 50 -sample 4x1,1x1,1x1 -progressive tmp.tga > video-001.q50.411.progressive.jpeg
rm tmp.tga

Change-Id: I5570389c462360f98c3160f3c6963d9466d511de
Reviewed-on: https://go-review.googlesource.com/6041
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go
index 5d7fefc..8fcb2e0 100644
--- a/src/image/jpeg/reader.go
+++ b/src/image/jpeg/reader.go
@@ -42,12 +42,6 @@
 	maxTq   = 3
 
 	maxComponents = 4
-
-	// We only support 4:4:4, 4:4:0, 4:2:2 and 4:2:0 downsampling, and therefore the
-	// number of luma samples per chroma sample is at most 2 in the horizontal
-	// and 2 in the vertical direction.
-	maxH = 2
-	maxV = 2
 )
 
 const (
@@ -346,12 +340,13 @@
 		d.comp[i].v = int(hv & 0x0f)
 		switch d.nComp {
 		case 3:
-			// For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2 or 4:2:0 chroma
-			// downsampling ratios. This implies that the (h, v) values for the Y
-			// component are either (1, 1), (1, 2), (2, 1) or (2, 2), and the (h, v)
-			// values for the Cr and Cb components must be (1, 1).
+			// For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2, 4:2:0,
+			// 4:1:1 or 4:1:0 chroma downsampling ratios. This implies that the
+			// (h, v) values for the Y component are either (1, 1), (1, 2),
+			// (2, 1), (2, 2), (4, 1) or (4, 2), and the (h, v) values for the Cr
+			// and Cb components must be (1, 1).
 			if i == 0 {
-				if hv != 0x11 && hv != 0x21 && hv != 0x22 && hv != 0x12 {
+				if hv != 0x11 && hv != 0x21 && hv != 0x22 && hv != 0x12 && hv != 0x41 && hv != 0x42 {
 					return UnsupportedError("luma/chroma downsample ratio")
 				}
 			} else if hv != 0x11 {
diff --git a/src/image/jpeg/reader_test.go b/src/image/jpeg/reader_test.go
index 4de2e8e..c5a36cb 100644
--- a/src/image/jpeg/reader_test.go
+++ b/src/image/jpeg/reader_test.go
@@ -23,6 +23,8 @@
 func TestDecodeProgressive(t *testing.T) {
 	testCases := []string{
 		"../testdata/video-001",
+		"../testdata/video-001.q50.410",
+		"../testdata/video-001.q50.411",
 		"../testdata/video-001.q50.420",
 		"../testdata/video-001.q50.422",
 		"../testdata/video-001.q50.440",
diff --git a/src/image/jpeg/scan.go b/src/image/jpeg/scan.go
index 4168936..8fcf401 100644
--- a/src/image/jpeg/scan.go
+++ b/src/image/jpeg/scan.go
@@ -26,6 +26,10 @@
 		subsampleRatio = image.YCbCrSubsampleRatio422
 	case h0 == 2 && v0 == 2:
 		subsampleRatio = image.YCbCrSubsampleRatio420
+	case h0 == 4 && v0 == 1:
+		subsampleRatio = image.YCbCrSubsampleRatio411
+	case h0 == 4 && v0 == 2:
+		subsampleRatio = image.YCbCrSubsampleRatio410
 	default:
 		panic("unreachable")
 	}
@@ -175,13 +179,8 @@
 					//	0 1 2
 					//	3 4 5
 					if nComp != 1 {
-						bx, by = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
-						if h0 == 1 {
-							by += j
-						} else {
-							bx += j % 2
-							by += j / 2
-						}
+						bx = d.comp[compIndex].h*mx + j%h0
+						by = d.comp[compIndex].v*my + j/h0
 					} else {
 						q := mxx * d.comp[compIndex].h
 						bx = blockCount % q
diff --git a/src/image/testdata/video-001.q50.410.jpeg b/src/image/testdata/video-001.q50.410.jpeg
new file mode 100644
index 0000000..4cebd1e
--- /dev/null
+++ b/src/image/testdata/video-001.q50.410.jpeg
Binary files differ
diff --git a/src/image/testdata/video-001.q50.410.progressive.jpeg b/src/image/testdata/video-001.q50.410.progressive.jpeg
new file mode 100644
index 0000000..fb71402
--- /dev/null
+++ b/src/image/testdata/video-001.q50.410.progressive.jpeg
Binary files differ
diff --git a/src/image/testdata/video-001.q50.411.jpeg b/src/image/testdata/video-001.q50.411.jpeg
new file mode 100644
index 0000000..b90de18
--- /dev/null
+++ b/src/image/testdata/video-001.q50.411.jpeg
Binary files differ
diff --git a/src/image/testdata/video-001.q50.411.progressive.jpeg b/src/image/testdata/video-001.q50.411.progressive.jpeg
new file mode 100644
index 0000000..1ddb22b
--- /dev/null
+++ b/src/image/testdata/video-001.q50.411.progressive.jpeg
Binary files differ