summaryrefslogtreecommitdiff
path: root/libgo/go/image
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2012-11-21 07:03:38 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2012-11-21 07:03:38 +0000
commitfabcaa8df3d6eb852b87821ef090d31d222870b7 (patch)
tree72455aea0286937aa08cc141e5efc800e4626577 /libgo/go/image
parenta51fb17f48428e7cfc96a72a9f9f87901363bb6b (diff)
libgo: Update to current version of master library.
From-SVN: r193688
Diffstat (limited to 'libgo/go/image')
-rw-r--r--libgo/go/image/decode_test.go1
-rw-r--r--libgo/go/image/draw/draw.go33
-rw-r--r--libgo/go/image/jpeg/dct_test.go26
-rw-r--r--libgo/go/image/jpeg/huffman.go56
-rw-r--r--libgo/go/image/jpeg/idct.go2
-rw-r--r--libgo/go/image/jpeg/reader.go199
-rw-r--r--libgo/go/image/jpeg/reader_test.go156
-rw-r--r--libgo/go/image/jpeg/scan.go432
-rw-r--r--libgo/go/image/jpeg/writer.go50
-rw-r--r--libgo/go/image/jpeg/writer_test.go17
-rw-r--r--libgo/go/image/png/reader.go35
-rw-r--r--libgo/go/image/testdata/video-001.progressive.jpegbin0 -> 20732 bytes
-rw-r--r--libgo/go/image/testdata/video-001.q50.420.jpegbin0 -> 3407 bytes
-rw-r--r--libgo/go/image/testdata/video-001.q50.420.progressive.jpegbin0 -> 3279 bytes
-rw-r--r--libgo/go/image/testdata/video-001.q50.422.jpegbin0 -> 3608 bytes
-rw-r--r--libgo/go/image/testdata/video-001.q50.422.progressive.jpegbin0 -> 3506 bytes
-rw-r--r--libgo/go/image/testdata/video-001.q50.440.jpegbin0 -> 3662 bytes
-rw-r--r--libgo/go/image/testdata/video-001.q50.440.progressive.jpegbin0 -> 3529 bytes
-rw-r--r--libgo/go/image/testdata/video-001.q50.444.jpegbin0 -> 4032 bytes
-rw-r--r--libgo/go/image/testdata/video-001.q50.444.progressive.jpegbin0 -> 3935 bytes
-rw-r--r--libgo/go/image/testdata/video-005.gray.q50.jpegbin0 -> 2782 bytes
-rw-r--r--libgo/go/image/testdata/video-005.gray.q50.progressive.jpegbin0 -> 2699 bytes
22 files changed, 732 insertions, 275 deletions
diff --git a/libgo/go/image/decode_test.go b/libgo/go/image/decode_test.go
index d659867243f..8dee57ee467 100644
--- a/libgo/go/image/decode_test.go
+++ b/libgo/go/image/decode_test.go
@@ -31,6 +31,7 @@ var imageTests = []imageTest{
{"testdata/video-001.png", "testdata/video-001.5bpp.gif", 128 << 8},
// JPEG is a lossy format and hence needs a non-zero tolerance.
{"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
+ {"testdata/video-001.png", "testdata/video-001.progressive.jpeg", 8 << 8},
// Grayscale images.
{"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
{"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
diff --git a/libgo/go/image/draw/draw.go b/libgo/go/image/draw/draw.go
index bef325c0c9d..56d30dd6f82 100644
--- a/libgo/go/image/draw/draw.go
+++ b/libgo/go/image/draw/draw.go
@@ -81,8 +81,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
drawNRGBAOver(dst0, r, src0, sp)
return
case *image.YCbCr:
- drawYCbCr(dst0, r, src0, sp)
- return
+ if drawYCbCr(dst0, r, src0, sp) {
+ return
+ }
}
} else if mask0, ok := mask.(*image.Alpha); ok {
switch src0 := src.(type) {
@@ -104,8 +105,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
drawNRGBASrc(dst0, r, src0, sp)
return
case *image.YCbCr:
- drawYCbCr(dst0, r, src0, sp)
- return
+ if drawYCbCr(dst0, r, src0, sp) {
+ return
+ }
}
}
}
@@ -345,7 +347,7 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
}
}
-func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) {
+func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
// (i.e. fully opaque) then the op is effectively always Src.
x0 := (r.Min.X - dst.Rect.Min.X) * 4
@@ -353,6 +355,19 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
y0 := r.Min.Y - dst.Rect.Min.Y
y1 := r.Max.Y - dst.Rect.Min.Y
switch src.SubsampleRatio {
+ case image.YCbCrSubsampleRatio444:
+ for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+ dpix := dst.Pix[y*dst.Stride:]
+ yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+ ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
+ for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+ rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
+ dpix[x+0] = rr
+ dpix[x+1] = gg
+ dpix[x+2] = bb
+ dpix[x+3] = 255
+ }
+ }
case image.YCbCrSubsampleRatio422:
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
dpix := dst.Pix[y*dst.Stride:]
@@ -381,12 +396,11 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
dpix[x+3] = 255
}
}
- default:
- // Default to 4:4:4 subsampling.
+ case image.YCbCrSubsampleRatio440:
for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
dpix := dst.Pix[y*dst.Stride:]
yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
- ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
+ ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
dpix[x+0] = rr
@@ -395,7 +409,10 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
dpix[x+3] = 255
}
}
+ default:
+ return false
}
+ return true
}
func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
diff --git a/libgo/go/image/jpeg/dct_test.go b/libgo/go/image/jpeg/dct_test.go
index 770e274bac0..7389f7e4fe8 100644
--- a/libgo/go/image/jpeg/dct_test.go
+++ b/libgo/go/image/jpeg/dct_test.go
@@ -42,7 +42,7 @@ func TestDCT(t *testing.T) {
b := block{}
n := r.Int() % 64
for j := 0; j < n; j++ {
- b[r.Int()%len(b)] = r.Int() % 256
+ b[r.Int()%len(b)] = r.Int31() % 256
}
blocks = append(blocks, b)
}
@@ -112,6 +112,14 @@ func alpha(i int) float64 {
return math.Sqrt2
}
+var cosines [32]float64 // cosines[k] = cos(π/2 * k/8)
+
+func init() {
+ for k := range cosines {
+ cosines[k] = math.Cos(math.Pi * float64(k) / 16)
+ }
+}
+
// slowFDCT performs the 8*8 2-dimensional forward discrete cosine transform:
//
// dst[u,v] = (1/8) * Σ_x Σ_y alpha(u) * alpha(v) * src[x,y] *
@@ -129,16 +137,16 @@ func slowFDCT(b *block) {
for y := 0; y < 8; y++ {
for x := 0; x < 8; x++ {
sum += alpha(u) * alpha(v) * float64(b[8*y+x]) *
- math.Cos(math.Pi*float64((2*x+1)*u)/16) *
- math.Cos(math.Pi*float64((2*y+1)*v)/16)
+ cosines[((2*x+1)*u)%32] *
+ cosines[((2*y+1)*v)%32]
}
}
dst[8*v+u] = sum / 8
}
}
- // Convert from float64 to int.
+ // Convert from float64 to int32.
for i := range dst {
- b[i] = int(dst[i] + 0.5)
+ b[i] = int32(dst[i] + 0.5)
}
}
@@ -159,16 +167,16 @@ func slowIDCT(b *block) {
for v := 0; v < 8; v++ {
for u := 0; u < 8; u++ {
sum += alpha(u) * alpha(v) * float64(b[8*v+u]) *
- math.Cos(math.Pi*float64((2*x+1)*u)/16) *
- math.Cos(math.Pi*float64((2*y+1)*v)/16)
+ cosines[((2*x+1)*u)%32] *
+ cosines[((2*y+1)*v)%32]
}
}
dst[8*y+x] = sum / 8
}
}
- // Convert from float64 to int.
+ // Convert from float64 to int32.
for i := range dst {
- b[i] = int(dst[i] + 0.5)
+ b[i] = int32(dst[i] + 0.5)
}
}
diff --git a/libgo/go/image/jpeg/huffman.go b/libgo/go/image/jpeg/huffman.go
index d2382490f4a..2fc64ade546 100644
--- a/libgo/go/image/jpeg/huffman.go
+++ b/libgo/go/image/jpeg/huffman.go
@@ -15,9 +15,9 @@ const maxNumValues = 256
// Bit stream for the Huffman decoder.
// The n least significant bits of a form the unread bits, to be read in MSB to LSB order.
type bits struct {
- a int // accumulator.
- n int // the number of unread bits in a.
- m int // mask. m==1<<(n-1) when n>0, with m==0 when n==0.
+ a uint32 // accumulator.
+ m uint32 // mask. m==1<<(n-1) when n>0, with m==0 when n==0.
+ n int // the number of unread bits in a.
}
// Huffman table decoder, specified in section C.
@@ -39,7 +39,7 @@ func (d *decoder) ensureNBits(n int) error {
if err != nil {
return err
}
- d.b.a = d.b.a<<8 | int(c)
+ d.b.a = d.b.a<<8 | uint32(c)
d.b.n += 8
if d.b.m == 0 {
d.b.m = 1 << 7
@@ -61,15 +61,16 @@ func (d *decoder) ensureNBits(n int) error {
}
// The composition of RECEIVE and EXTEND, specified in section F.2.2.1.
-func (d *decoder) receiveExtend(t uint8) (int, error) {
- err := d.ensureNBits(int(t))
- if err != nil {
- return 0, err
+func (d *decoder) receiveExtend(t uint8) (int32, error) {
+ if d.b.n < int(t) {
+ if err := d.ensureNBits(int(t)); err != nil {
+ return 0, err
+ }
}
d.b.n -= int(t)
d.b.m >>= t
- s := 1 << t
- x := (d.b.a >> uint8(d.b.n)) & (s - 1)
+ s := int32(1) << t
+ x := int32(d.b.a>>uint8(d.b.n)) & (s - 1)
if x < s>>1 {
x += ((-1) << t) + 1
}
@@ -92,8 +93,7 @@ func (d *decoder) processDHT(n int) error {
return FormatError("bad Tc value")
}
th := d.tmp[0] & 0x0f
- const isBaseline = true // Progressive mode is not yet supported.
- if th > maxTh || isBaseline && th > 1 {
+ if th > maxTh || !d.progressive && th > 1 {
return FormatError("bad Th value")
}
h := &d.huff[tc][th]
@@ -169,9 +169,10 @@ func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
return 0, FormatError("uninitialized Huffman table")
}
for i, code := 0, 0; i < maxCodeLength; i++ {
- err := d.ensureNBits(1)
- if err != nil {
- return 0, err
+ if d.b.n == 0 {
+ if err := d.ensureNBits(1); err != nil {
+ return 0, err
+ }
}
if d.b.a&d.b.m != 0 {
code |= 1
@@ -185,3 +186,28 @@ func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
}
return 0, FormatError("bad Huffman code")
}
+
+func (d *decoder) decodeBit() (bool, error) {
+ if d.b.n == 0 {
+ if err := d.ensureNBits(1); err != nil {
+ return false, err
+ }
+ }
+ ret := d.b.a&d.b.m != 0
+ d.b.n--
+ d.b.m >>= 1
+ return ret, nil
+}
+
+func (d *decoder) decodeBits(n int) (uint32, error) {
+ if d.b.n < n {
+ if err := d.ensureNBits(n); err != nil {
+ return 0, err
+ }
+ }
+ ret := d.b.a >> uint(d.b.n-n)
+ ret &= (1 << uint(n)) - 1
+ d.b.n -= n
+ d.b.m >>= uint(n)
+ return ret, nil
+}
diff --git a/libgo/go/image/jpeg/idct.go b/libgo/go/image/jpeg/idct.go
index 92ff1e4b41d..46fcaecb798 100644
--- a/libgo/go/image/jpeg/idct.go
+++ b/libgo/go/image/jpeg/idct.go
@@ -39,7 +39,7 @@ package jpeg
const blockSize = 64 // A DCT block is 8x8.
-type block [blockSize]int
+type block [blockSize]int32
const (
w1 = 2841 // 2048*sqrt(2)*cos(1*pi/16)
diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go
index 415b093281d..24dd65defcc 100644
--- a/libgo/go/image/jpeg/reader.go
+++ b/libgo/go/image/jpeg/reader.go
@@ -98,7 +98,10 @@ type decoder struct {
img3 *image.YCbCr
ri int // Restart Interval.
nComp int
+ progressive bool
+ eobRun uint16 // End-of-Band run, specified in section G.1.2.2.
comp [nColorComponent]component
+ progCoeffs [nColorComponent][]block // Saved state between progressive-mode scans.
huff [maxTc + 1][maxTh + 1]huffman
quant [maxTq + 1]block // Quantization tables, in zig-zag order.
tmp [1024]byte
@@ -184,7 +187,7 @@ func (d *decoder) processDQT(n int) error {
return FormatError("bad Tq value")
}
for i := range d.quant[tq] {
- d.quant[tq][i] = int(d.tmp[i+1])
+ d.quant[tq][i] = int32(d.tmp[i+1])
}
}
if n != 0 {
@@ -193,187 +196,6 @@ func (d *decoder) processDQT(n int) error {
return nil
}
-// makeImg allocates and initializes the destination image.
-func (d *decoder) makeImg(h0, v0, mxx, myy int) {
- if d.nComp == nGrayComponent {
- m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy))
- d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
- return
- }
- var subsampleRatio image.YCbCrSubsampleRatio
- switch {
- case h0 == 1 && v0 == 1:
- subsampleRatio = image.YCbCrSubsampleRatio444
- case h0 == 1 && v0 == 2:
- subsampleRatio = image.YCbCrSubsampleRatio440
- case h0 == 2 && v0 == 1:
- subsampleRatio = image.YCbCrSubsampleRatio422
- case h0 == 2 && v0 == 2:
- subsampleRatio = image.YCbCrSubsampleRatio420
- default:
- panic("unreachable")
- }
- m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio)
- d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr)
-}
-
-// Specified in section B.2.3.
-func (d *decoder) processSOS(n int) error {
- if d.nComp == 0 {
- return FormatError("missing SOF marker")
- }
- if n != 4+2*d.nComp {
- return UnsupportedError("SOS has wrong length")
- }
- _, err := io.ReadFull(d.r, d.tmp[0:4+2*d.nComp])
- if err != nil {
- return err
- }
- if int(d.tmp[0]) != d.nComp {
- return UnsupportedError("SOS has wrong number of image components")
- }
- var scan [nColorComponent]struct {
- td uint8 // DC table selector.
- ta uint8 // AC table selector.
- }
- for i := 0; i < d.nComp; i++ {
- cs := d.tmp[1+2*i] // Component selector.
- if cs != d.comp[i].c {
- return UnsupportedError("scan components out of order")
- }
- scan[i].td = d.tmp[2+2*i] >> 4
- scan[i].ta = d.tmp[2+2*i] & 0x0f
- }
- // mxx and myy are the number of MCUs (Minimum Coded Units) in the image.
- h0, v0 := d.comp[0].h, d.comp[0].v // The h and v values from the Y components.
- mxx := (d.width + 8*h0 - 1) / (8 * h0)
- myy := (d.height + 8*v0 - 1) / (8 * v0)
- if d.img1 == nil && d.img3 == nil {
- d.makeImg(h0, v0, mxx, myy)
- }
-
- mcu, expectedRST := 0, uint8(rst0Marker)
- var (
- b block
- dc [nColorComponent]int
- )
- for my := 0; my < myy; my++ {
- for mx := 0; mx < mxx; mx++ {
- for i := 0; i < d.nComp; i++ {
- qt := &d.quant[d.comp[i].tq]
- for j := 0; j < d.comp[i].h*d.comp[i].v; j++ {
- // TODO(nigeltao): make this a "var b block" once the compiler's escape
- // analysis is good enough to allocate it on the stack, not the heap.
- // b is in natural (not zig-zag) order.
- b = block{}
-
- // Decode the DC coefficient, as specified in section F.2.2.1.
- value, err := d.decodeHuffman(&d.huff[dcTable][scan[i].td])
- if err != nil {
- return err
- }
- if value > 16 {
- return UnsupportedError("excessive DC component")
- }
- dcDelta, err := d.receiveExtend(value)
- if err != nil {
- return err
- }
- dc[i] += dcDelta
- b[0] = dc[i] * qt[0]
-
- // Decode the AC coefficients, as specified in section F.2.2.2.
- for zig := 1; zig < blockSize; zig++ {
- value, err := d.decodeHuffman(&d.huff[acTable][scan[i].ta])
- if err != nil {
- return err
- }
- val0 := value >> 4
- val1 := value & 0x0f
- if val1 != 0 {
- zig += int(val0)
- if zig > blockSize {
- return FormatError("bad DCT index")
- }
- ac, err := d.receiveExtend(val1)
- if err != nil {
- return err
- }
- b[unzig[zig]] = ac * qt[zig]
- } else {
- if val0 != 0x0f {
- break
- }
- zig += 0x0f
- }
- }
-
- // Perform the inverse DCT and store the MCU component to the image.
- idct(&b)
- dst, stride := []byte(nil), 0
- if d.nComp == nGrayComponent {
- dst, stride = d.img1.Pix[8*(my*d.img1.Stride+mx):], d.img1.Stride
- } else {
- switch i {
- case 0:
- mx0, my0 := h0*mx, v0*my
- if h0 == 1 {
- my0 += j
- } else {
- mx0 += j % 2
- my0 += j / 2
- }
- dst, stride = d.img3.Y[8*(my0*d.img3.YStride+mx0):], d.img3.YStride
- case 1:
- dst, stride = d.img3.Cb[8*(my*d.img3.CStride+mx):], d.img3.CStride
- case 2:
- dst, stride = d.img3.Cr[8*(my*d.img3.CStride+mx):], d.img3.CStride
- }
- }
- // Level shift by +128, clip to [0, 255], and write to dst.
- for y := 0; y < 8; y++ {
- y8 := y * 8
- yStride := y * stride
- for x := 0; x < 8; x++ {
- c := b[y8+x]
- if c < -128 {
- c = 0
- } else if c > 127 {
- c = 255
- } else {
- c += 128
- }
- dst[yStride+x] = uint8(c)
- }
- }
- } // for j
- } // for i
- mcu++
- if d.ri > 0 && mcu%d.ri == 0 && mcu < mxx*myy {
- // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
- // but this one assumes well-formed input, and hence the restart marker follows immediately.
- _, err := io.ReadFull(d.r, d.tmp[0:2])
- if err != nil {
- return err
- }
- if d.tmp[0] != 0xff || d.tmp[1] != expectedRST {
- return FormatError("bad RST marker")
- }
- expectedRST++
- if expectedRST == rst7Marker+1 {
- expectedRST = rst0Marker
- }
- // Reset the Huffman decoder.
- d.b = bits{}
- // Reset the DC components, as per section F.2.1.3.1.
- dc = [nColorComponent]int{}
- }
- } // for mx
- } // for my
-
- return nil
-}
-
// Specified in section B.2.4.4.
func (d *decoder) processDRI(n int) error {
if n != 2 {
@@ -414,6 +236,14 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
return nil, FormatError("missing 0xff marker start")
}
marker := d.tmp[1]
+ for marker == 0xff {
+ // Section B.1.1.2 says, "Any marker may optionally be preceded by any
+ // number of fill bytes, which are bytes assigned code X'FF'".
+ marker, err = d.r.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ }
if marker == eoiMarker { // End Of Image.
break
}
@@ -439,13 +269,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
}
switch {
- case marker == sof0Marker: // Start Of Frame (Baseline).
+ case marker == sof0Marker || marker == sof2Marker: // Start Of Frame.
+ d.progressive = marker == sof2Marker
err = d.processSOF(n)
if configOnly {
return nil, err
}
- case marker == sof2Marker: // Start Of Frame (Progressive).
- err = UnsupportedError("progressive mode")
case marker == dhtMarker: // Define Huffman Table.
err = d.processDHT(n)
case marker == dqtMarker: // Define Quantization Table.
diff --git a/libgo/go/image/jpeg/reader_test.go b/libgo/go/image/jpeg/reader_test.go
new file mode 100644
index 00000000000..f7fbd9a8a5e
--- /dev/null
+++ b/libgo/go/image/jpeg/reader_test.go
@@ -0,0 +1,156 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jpeg
+
+import (
+ "bytes"
+ "fmt"
+ "image"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+// TestDecodeProgressive tests that decoding the baseline and progressive
+// versions of the same image result in exactly the same pixel data, in YCbCr
+// space for color images, and Y space for grayscale images.
+func TestDecodeProgressive(t *testing.T) {
+ testCases := []string{
+ "../testdata/video-001",
+ "../testdata/video-001.q50.420",
+ "../testdata/video-001.q50.422",
+ "../testdata/video-001.q50.440",
+ "../testdata/video-001.q50.444",
+ "../testdata/video-005.gray.q50",
+ }
+ for _, tc := range testCases {
+ m0, err := decodeFile(tc + ".jpeg")
+ if err != nil {
+ t.Errorf("%s: %v", tc+".jpeg", err)
+ continue
+ }
+ m1, err := decodeFile(tc + ".progressive.jpeg")
+ if err != nil {
+ t.Errorf("%s: %v", tc+".progressive.jpeg", err)
+ continue
+ }
+ if m0.Bounds() != m1.Bounds() {
+ t.Errorf("%s: bounds differ: %v and %v", tc, m0.Bounds(), m1.Bounds())
+ continue
+ }
+ switch m0 := m0.(type) {
+ case *image.YCbCr:
+ m1 := m1.(*image.YCbCr)
+ if err := check(m0.Bounds(), m0.Y, m1.Y, m0.YStride, m1.YStride); err != nil {
+ t.Errorf("%s (Y): %v", tc, err)
+ continue
+ }
+ if err := check(m0.Bounds(), m0.Cb, m1.Cb, m0.CStride, m1.CStride); err != nil {
+ t.Errorf("%s (Cb): %v", tc, err)
+ continue
+ }
+ if err := check(m0.Bounds(), m0.Cr, m1.Cr, m0.CStride, m1.CStride); err != nil {
+ t.Errorf("%s (Cr): %v", tc, err)
+ continue
+ }
+ case *image.Gray:
+ m1 := m1.(*image.Gray)
+ if err := check(m0.Bounds(), m0.Pix, m1.Pix, m0.Stride, m1.Stride); err != nil {
+ t.Errorf("%s: %v", tc, err)
+ continue
+ }
+ default:
+ t.Errorf("%s: unexpected image type %T", tc, m0)
+ continue
+ }
+ }
+}
+
+func decodeFile(filename string) (image.Image, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return Decode(f)
+
+}
+
+// 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%8 != 0 {
+ return fmt.Errorf("stride %d is not a multiple of 8", stride0)
+ }
+ // 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 {
+ 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
+ // occur with a 4:2:0 chroma subsampling and a 1x1 image. Baseline
+ // decoding works on the one 16x16 MCU as a whole; progressive
+ // decoding's first pass works on that 16x16 MCU as a whole but
+ // refinement passes only process one 8x8 block within the MCU.
+ continue
+ }
+
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ index := (y+j)*stride0 + (x + i)
+ if pix0[index] != pix1[index] {
+ return fmt.Errorf("blocks at (%d, %d) differ:\n%sand\n%s", x, y,
+ pixString(pix0, stride0, x, y),
+ pixString(pix1, stride1, x, y),
+ )
+ }
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func pixString(pix []byte, stride, x, y int) string {
+ s := bytes.NewBuffer(nil)
+ for j := 0; j < 8; j++ {
+ fmt.Fprintf(s, "\t")
+ for i := 0; i < 8; i++ {
+ fmt.Fprintf(s, "%02x ", pix[(y+j)*stride+(x+i)])
+ }
+ fmt.Fprintf(s, "\n")
+ }
+ return s.String()
+}
+
+func benchmarkDecode(b *testing.B, filename string) {
+ b.StopTimer()
+ data, err := ioutil.ReadFile(filename)
+ if err != nil {
+ b.Fatal(err)
+ }
+ cfg, err := DecodeConfig(bytes.NewReader(data))
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.SetBytes(int64(cfg.Width * cfg.Height * 4))
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ Decode(bytes.NewReader(data))
+ }
+}
+
+func BenchmarkDecodeBaseline(b *testing.B) {
+ benchmarkDecode(b, "../testdata/video-001.jpeg")
+}
+
+func BenchmarkDecodeProgressive(b *testing.B) {
+ benchmarkDecode(b, "../testdata/video-001.progressive.jpeg")
+}
diff --git a/libgo/go/image/jpeg/scan.go b/libgo/go/image/jpeg/scan.go
new file mode 100644
index 00000000000..e3ae8ae441c
--- /dev/null
+++ b/libgo/go/image/jpeg/scan.go
@@ -0,0 +1,432 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package jpeg
+
+import (
+ "image"
+ "io"
+)
+
+// makeImg allocates and initializes the destination image.
+func (d *decoder) makeImg(h0, v0, mxx, myy int) {
+ if d.nComp == nGrayComponent {
+ m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy))
+ d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
+ return
+ }
+ var subsampleRatio image.YCbCrSubsampleRatio
+ switch {
+ case h0 == 1 && v0 == 1:
+ subsampleRatio = image.YCbCrSubsampleRatio444
+ case h0 == 1 && v0 == 2:
+ subsampleRatio = image.YCbCrSubsampleRatio440
+ case h0 == 2 && v0 == 1:
+ subsampleRatio = image.YCbCrSubsampleRatio422
+ case h0 == 2 && v0 == 2:
+ subsampleRatio = image.YCbCrSubsampleRatio420
+ default:
+ panic("unreachable")
+ }
+ m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio)
+ d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr)
+}
+
+// Specified in section B.2.3.
+func (d *decoder) processSOS(n int) error {
+ if d.nComp == 0 {
+ return FormatError("missing SOF marker")
+ }
+ if n < 6 || 4+2*d.nComp < n || n%2 != 0 {
+ return FormatError("SOS has wrong length")
+ }
+ _, err := io.ReadFull(d.r, d.tmp[:n])
+ if err != nil {
+ return err
+ }
+ nComp := int(d.tmp[0])
+ if n != 4+2*nComp {
+ return FormatError("SOS length inconsistent with number of components")
+ }
+ var scan [nColorComponent]struct {
+ compIndex uint8
+ td uint8 // DC table selector.
+ ta uint8 // AC table selector.
+ }
+ for i := 0; i < nComp; i++ {
+ cs := d.tmp[1+2*i] // Component selector.
+ compIndex := -1
+ for j, comp := range d.comp {
+ if cs == comp.c {
+ compIndex = j
+ }
+ }
+ if compIndex < 0 {
+ return FormatError("unknown component selector")
+ }
+ scan[i].compIndex = uint8(compIndex)
+ scan[i].td = d.tmp[2+2*i] >> 4
+ scan[i].ta = d.tmp[2+2*i] & 0x0f
+ }
+
+ // zigStart and zigEnd are the spectral selection bounds.
+ // ah and al are the successive approximation high and low values.
+ // The spec calls these values Ss, Se, Ah and Al.
+ //
+ // For progressive JPEGs, these are the two more-or-less independent
+ // aspects of progression. Spectral selection progression is when not
+ // all of a block's 64 DCT coefficients are transmitted in one pass.
+ // For example, three passes could transmit coefficient 0 (the DC
+ // component), coefficients 1-5, and coefficients 6-63, in zig-zag
+ // order. Successive approximation is when not all of the bits of a
+ // band of coefficients are transmitted in one pass. For example,
+ // three passes could transmit the 6 most significant bits, followed
+ // by the second-least significant bit, followed by the least
+ // significant bit.
+ //
+ // For baseline JPEGs, these parameters are hard-coded to 0/63/0/0.
+ zigStart, zigEnd, ah, al := int32(0), int32(blockSize-1), uint32(0), uint32(0)
+ if d.progressive {
+ zigStart = int32(d.tmp[1+2*nComp])
+ zigEnd = int32(d.tmp[2+2*nComp])
+ ah = uint32(d.tmp[3+2*nComp] >> 4)
+ al = uint32(d.tmp[3+2*nComp] & 0x0f)
+ if (zigStart == 0 && zigEnd != 0) || zigStart > zigEnd || blockSize <= zigEnd {
+ return FormatError("bad spectral selection bounds")
+ }
+ if zigStart != 0 && nComp != 1 {
+ return FormatError("progressive AC coefficients for more than one component")
+ }
+ if ah != 0 && ah != al+1 {
+ return FormatError("bad successive approximation values")
+ }
+ }
+
+ // mxx and myy are the number of MCUs (Minimum Coded Units) in the image.
+ h0, v0 := d.comp[0].h, d.comp[0].v // The h and v values from the Y components.
+ mxx := (d.width + 8*h0 - 1) / (8 * h0)
+ myy := (d.height + 8*v0 - 1) / (8 * v0)
+ if d.img1 == nil && d.img3 == nil {
+ d.makeImg(h0, v0, mxx, myy)
+ if d.progressive {
+ for i := 0; i < nComp; i++ {
+ compIndex := scan[i].compIndex
+ d.progCoeffs[compIndex] = make([]block, mxx*myy*d.comp[compIndex].h*d.comp[compIndex].v)
+ }
+ }
+ }
+
+ d.b = bits{}
+ mcu, expectedRST := 0, uint8(rst0Marker)
+ var (
+ // b is the decoded coefficients, in natural (not zig-zag) order.
+ b block
+ dc [nColorComponent]int32
+ // mx0 and my0 are the location of the current (in terms of 8x8 blocks).
+ // For example, with 4:2:0 chroma subsampling, the block whose top left
+ // pixel co-ordinates are (16, 8) is the third block in the first row:
+ // mx0 is 2 and my0 is 0, even though the pixel is in the second MCU.
+ // TODO(nigeltao): rename mx0 and my0 to bx and by?
+ mx0, my0 int
+ blockCount int
+ )
+ for my := 0; my < myy; my++ {
+ for mx := 0; mx < mxx; mx++ {
+ for i := 0; i < nComp; i++ {
+ compIndex := scan[i].compIndex
+ qt := &d.quant[d.comp[compIndex].tq]
+ 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:
+ // 0 1 2 3
+ // 4 5 6 7
+ //
+ // 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:
+ // 0 1 4 5
+ // 2 3 6 7
+ // The later scans will process only 6 Y blocks:
+ // 0 1 2
+ // 3 4 5
+ if zigStart == 0 {
+ mx0, my0 = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
+ if h0 == 1 {
+ my0 += j
+ } else {
+ mx0 += j % 2
+ my0 += j / 2
+ }
+ } else {
+ q := mxx * d.comp[compIndex].h
+ mx0 = blockCount % q
+ my0 = blockCount / q
+ blockCount++
+ if mx0*8 >= d.width || my0*8 >= d.height {
+ continue
+ }
+ }
+
+ // Load the previous partially decoded coefficients, if applicable.
+ if d.progressive {
+ b = d.progCoeffs[compIndex][my0*mxx*d.comp[compIndex].h+mx0]
+ } else {
+ b = block{}
+ }
+
+ if ah != 0 {
+ if err := d.refine(&b, &d.huff[acTable][scan[i].ta], zigStart, zigEnd, 1<<al); err != nil {
+ return err
+ }
+ } else {
+ zig := zigStart
+ if zig == 0 {
+ zig++
+ // Decode the DC coefficient, as specified in section F.2.2.1.
+ value, err := d.decodeHuffman(&d.huff[dcTable][scan[i].td])
+ if err != nil {
+ return err
+ }
+ if value > 16 {
+ return UnsupportedError("excessive DC component")
+ }
+ dcDelta, err := d.receiveExtend(value)
+ if err != nil {
+ return err
+ }
+ dc[compIndex] += dcDelta
+ b[0] = dc[compIndex] << al
+ }
+
+ if zig <= zigEnd && d.eobRun > 0 {
+ d.eobRun--
+ } else {
+ // Decode the AC coefficients, as specified in section F.2.2.2.
+ for ; zig <= zigEnd; zig++ {
+ value, err := d.decodeHuffman(&d.huff[acTable][scan[i].ta])
+ if err != nil {
+ return err
+ }
+ val0 := value >> 4
+ val1 := value & 0x0f
+ if val1 != 0 {
+ zig += int32(val0)
+ if zig > zigEnd {
+ break
+ }
+ ac, err := d.receiveExtend(val1)
+ if err != nil {
+ return err
+ }
+ b[unzig[zig]] = ac << al
+ } else {
+ if val0 != 0x0f {
+ d.eobRun = uint16(1 << val0)
+ if val0 != 0 {
+ bits, err := d.decodeBits(int(val0))
+ if err != nil {
+ return err
+ }
+ d.eobRun |= uint16(bits)
+ }
+ d.eobRun--
+ break
+ }
+ zig += 0x0f
+ }
+ }
+ }
+ }
+
+ if d.progressive {
+ if zigEnd != blockSize-1 || al != 0 {
+ // We haven't completely decoded this 8x8 block. Save the coefficients.
+ d.progCoeffs[compIndex][my0*mxx*d.comp[compIndex].h+mx0] = b
+ // At this point, we could execute the rest of the loop body to dequantize and
+ // perform the inverse DCT, to save early stages of a progressive image to the
+ // *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
+ // the jpeg.Decode function does not return until the entire image is decoded,
+ // so we "continue" here to avoid wasted computation.
+ continue
+ }
+ }
+
+ // Dequantize, perform the inverse DCT and store the block to the image.
+ for zig := 0; zig < blockSize; zig++ {
+ b[unzig[zig]] *= qt[zig]
+ }
+ idct(&b)
+ dst, stride := []byte(nil), 0
+ if d.nComp == nGrayComponent {
+ dst, stride = d.img1.Pix[8*(my0*d.img1.Stride+mx0):], d.img1.Stride
+ } else {
+ switch compIndex {
+ case 0:
+ dst, stride = d.img3.Y[8*(my0*d.img3.YStride+mx0):], d.img3.YStride
+ case 1:
+ dst, stride = d.img3.Cb[8*(my0*d.img3.CStride+mx0):], d.img3.CStride
+ case 2:
+ dst, stride = d.img3.Cr[8*(my0*d.img3.CStride+mx0):], d.img3.CStride
+ default:
+ return UnsupportedError("too many components")
+ }
+ }
+ // Level shift by +128, clip to [0, 255], and write to dst.
+ for y := 0; y < 8; y++ {
+ y8 := y * 8
+ yStride := y * stride
+ for x := 0; x < 8; x++ {
+ c := b[y8+x]
+ if c < -128 {
+ c = 0
+ } else if c > 127 {
+ c = 255
+ } else {
+ c += 128
+ }
+ dst[yStride+x] = uint8(c)
+ }
+ }
+ } // for j
+ } // for i
+ mcu++
+ if d.ri > 0 && mcu%d.ri == 0 && mcu < mxx*myy {
+ // A more sophisticated decoder could use RST[0-7] markers to resynchronize from corrupt input,
+ // but this one assumes well-formed input, and hence the restart marker follows immediately.
+ _, err := io.ReadFull(d.r, d.tmp[0:2])
+ if err != nil {
+ return err
+ }
+ if d.tmp[0] != 0xff || d.tmp[1] != expectedRST {
+ return FormatError("bad RST marker")
+ }
+ expectedRST++
+ if expectedRST == rst7Marker+1 {
+ expectedRST = rst0Marker
+ }
+ // Reset the Huffman decoder.
+ d.b = bits{}
+ // Reset the DC components, as per section F.2.1.3.1.
+ dc = [nColorComponent]int32{}
+ // Reset the progressive decoder state, as per section G.1.2.2.
+ d.eobRun = 0
+ }
+ } // for mx
+ } // for my
+
+ return nil
+}
+
+// refine decodes a successive approximation refinement block, as specified in
+// section G.1.2.
+func (d *decoder) refine(b *block, h *huffman, zigStart, zigEnd, delta int32) error {
+ // Refining a DC component is trivial.
+ if zigStart == 0 {
+ if zigEnd != 0 {
+ panic("unreachable")
+ }
+ bit, err := d.decodeBit()
+ if err != nil {
+ return err
+ }
+ if bit {
+ b[0] |= delta
+ }
+ return nil
+ }
+
+ // Refining AC components is more complicated; see sections G.1.2.2 and G.1.2.3.
+ zig := zigStart
+ if d.eobRun == 0 {
+ loop:
+ for ; zig <= zigEnd; zig++ {
+ z := int32(0)
+ value, err := d.decodeHuffman(h)
+ if err != nil {
+ return err
+ }
+ val0 := value >> 4
+ val1 := value & 0x0f
+
+ switch val1 {
+ case 0:
+ if val0 != 0x0f {
+ d.eobRun = uint16(1 << val0)
+ if val0 != 0 {
+ bits, err := d.decodeBits(int(val0))
+ if err != nil {
+ return err
+ }
+ d.eobRun |= uint16(bits)
+ }
+ break loop
+ }
+ case 1:
+ z = delta
+ bit, err := d.decodeBit()
+ if err != nil {
+ return err
+ }
+ if !bit {
+ z = -z
+ }
+ default:
+ return FormatError("unexpected Huffman code")
+ }
+
+ zig, err = d.refineNonZeroes(b, zig, zigEnd, int32(val0), delta)
+ if err != nil {
+ return err
+ }
+ if zig > zigEnd {
+ return FormatError("too many coefficients")
+ }
+ if z != 0 {
+ b[unzig[zig]] = z
+ }
+ }
+ }
+ if d.eobRun > 0 {
+ d.eobRun--
+ if _, err := d.refineNonZeroes(b, zig, zigEnd, -1, delta); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// refineNonZeroes refines non-zero entries of b in zig-zag order. If nz >= 0,
+// the first nz zero entries are skipped over.
+func (d *decoder) refineNonZeroes(b *block, zig, zigEnd, nz, delta int32) (int32, error) {
+ for ; zig <= zigEnd; zig++ {
+ u := unzig[zig]
+ if b[u] == 0 {
+ if nz == 0 {
+ break
+ }
+ nz--
+ continue
+ }
+ bit, err := d.decodeBit()
+ if err != nil {
+ return 0, err
+ }
+ if !bit {
+ continue
+ }
+ if b[u] >= 0 {
+ b[u] += delta
+ } else {
+ b[u] -= delta
+ }
+ }
+ return zig, nil
+}
diff --git a/libgo/go/image/jpeg/writer.go b/libgo/go/image/jpeg/writer.go
index 099298e462e..375d8a66d5a 100644
--- a/libgo/go/image/jpeg/writer.go
+++ b/libgo/go/image/jpeg/writer.go
@@ -21,7 +21,7 @@ func min(x, y int) int {
}
// div returns a/b rounded to the nearest integer, instead of rounded to zero.
-func div(a int, b int) int {
+func div(a, b int32) int32 {
if a >= 0 {
return (a + (b >> 1)) / b
}
@@ -268,14 +268,14 @@ func (e *encoder) emit(bits, nBits uint32) {
}
// emitHuff emits the given value with the given Huffman encoder.
-func (e *encoder) emitHuff(h huffIndex, value int) {
+func (e *encoder) emitHuff(h huffIndex, value int32) {
x := theHuffmanLUT[h][value]
e.emit(x&(1<<24-1), x>>24)
}
// emitHuffRLE emits a run of runLength copies of value encoded with the given
// Huffman encoder.
-func (e *encoder) emitHuffRLE(h huffIndex, runLength, value int) {
+func (e *encoder) emitHuffRLE(h huffIndex, runLength, value int32) {
a, b := value, value
if a < 0 {
a, b = -value, value-1
@@ -286,7 +286,7 @@ func (e *encoder) emitHuffRLE(h huffIndex, runLength, value int) {
} else {
nBits = 8 + uint32(bitCount[a>>8])
}
- e.emitHuff(h, runLength<<4|int(nBits))
+ e.emitHuff(h, runLength<<4|int32(nBits))
if nBits > 0 {
e.emit(uint32(b)&(1<<nBits-1), nBits)
}
@@ -347,15 +347,15 @@ func (e *encoder) writeDHT() {
// writeBlock writes a block of pixel data using the given quantization table,
// returning the post-quantized DC value of the DCT-transformed block.
// b is in natural (not zig-zag) order.
-func (e *encoder) writeBlock(b *block, q quantIndex, prevDC int) int {
+func (e *encoder) writeBlock(b *block, q quantIndex, prevDC int32) int32 {
fdct(b)
// Emit the DC delta.
- dc := div(b[0], (8 * int(e.quant[q][0])))
+ dc := div(b[0], 8*int32(e.quant[q][0]))
e.emitHuffRLE(huffIndex(2*q+0), 0, dc-prevDC)
// Emit the AC components.
- h, runLength := huffIndex(2*q+1), 0
+ h, runLength := huffIndex(2*q+1), int32(0)
for zig := 1; zig < blockSize; zig++ {
- ac := div(b[unzig[zig]], (8 * int(e.quant[q][zig])))
+ ac := div(b[unzig[zig]], 8*int32(e.quant[q][zig]))
if ac == 0 {
runLength++
} else {
@@ -383,9 +383,9 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) {
for i := 0; i < 8; i++ {
r, g, b, _ := m.At(min(p.X+i, xmax), min(p.Y+j, ymax)).RGBA()
yy, cb, cr := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
- yBlock[8*j+i] = int(yy)
- cbBlock[8*j+i] = int(cb)
- crBlock[8*j+i] = int(cr)
+ yBlock[8*j+i] = int32(yy)
+ cbBlock[8*j+i] = int32(cb)
+ crBlock[8*j+i] = int32(cr)
}
}
}
@@ -408,9 +408,9 @@ func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block)
}
pix := m.Pix[offset+sx*4:]
yy, cb, cr := color.RGBToYCbCr(pix[0], pix[1], pix[2])
- yBlock[8*j+i] = int(yy)
- cbBlock[8*j+i] = int(cb)
- crBlock[8*j+i] = int(cr)
+ yBlock[8*j+i] = int32(yy)
+ cbBlock[8*j+i] = int32(cb)
+ crBlock[8*j+i] = int32(cr)
}
}
}
@@ -450,12 +450,10 @@ func (e *encoder) writeSOS(m image.Image) {
var (
// Scratch buffers to hold the YCbCr values.
// The blocks are in natural (not zig-zag) order.
- yBlock block
- cbBlock [4]block
- crBlock [4]block
- cBlock block
+ b block
+ cb, cr [4]block
// DC components are delta-encoded.
- prevDCY, prevDCCb, prevDCCr int
+ prevDCY, prevDCCb, prevDCCr int32
)
bounds := m.Bounds()
rgba, _ := m.(*image.RGBA)
@@ -466,16 +464,16 @@ func (e *encoder) writeSOS(m image.Image) {
yOff := (i & 2) * 4
p := image.Pt(x+xOff, y+yOff)
if rgba != nil {
- rgbaToYCbCr(rgba, p, &yBlock, &cbBlock[i], &crBlock[i])
+ rgbaToYCbCr(rgba, p, &b, &cb[i], &cr[i])
} else {
- toYCbCr(m, p, &yBlock, &cbBlock[i], &crBlock[i])
+ toYCbCr(m, p, &b, &cb[i], &cr[i])
}
- prevDCY = e.writeBlock(&yBlock, 0, prevDCY)
+ prevDCY = e.writeBlock(&b, 0, prevDCY)
}
- scale(&cBlock, &cbBlock)
- prevDCCb = e.writeBlock(&cBlock, 1, prevDCCb)
- scale(&cBlock, &crBlock)
- prevDCCr = e.writeBlock(&cBlock, 1, prevDCCr)
+ scale(&b, &cb)
+ prevDCCb = e.writeBlock(&b, 1, prevDCCb)
+ scale(&b, &cr)
+ prevDCCr = e.writeBlock(&b, 1, prevDCCr)
}
}
// Pad the last byte with 1's.
diff --git a/libgo/go/image/jpeg/writer_test.go b/libgo/go/image/jpeg/writer_test.go
index 90b89a7b0f1..0b2143f5b89 100644
--- a/libgo/go/image/jpeg/writer_test.go
+++ b/libgo/go/image/jpeg/writer_test.go
@@ -171,23 +171,6 @@ func TestWriter(t *testing.T) {
}
}
-func BenchmarkDecode(b *testing.B) {
- b.StopTimer()
- data, err := ioutil.ReadFile("../testdata/video-001.jpeg")
- if err != nil {
- b.Fatal(err)
- }
- cfg, err := DecodeConfig(bytes.NewReader(data))
- if err != nil {
- b.Fatal(err)
- }
- b.SetBytes(int64(cfg.Width * cfg.Height * 4))
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- Decode(bytes.NewReader(data))
- }
-}
-
func BenchmarkEncode(b *testing.B) {
b.StopTimer()
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go
index b3901b2adf9..ff837331f81 100644
--- a/libgo/go/image/png/reader.go
+++ b/libgo/go/image/png/reader.go
@@ -193,10 +193,19 @@ func (d *decoder) parsePLTE(length uint32) error {
d.crc.Write(d.tmp[:n])
switch d.cb {
case cbP1, cbP2, cbP4, cbP8:
- d.palette = color.Palette(make([]color.Color, np))
+ d.palette = make(color.Palette, 256)
for i := 0; i < np; i++ {
d.palette[i] = color.RGBA{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
}
+ for i := np; i < 256; i++ {
+ // Initialize the rest of the palette to opaque black. The spec (section
+ // 11.2.3) says that "any out-of-range pixel value found in the image data
+ // is an error", but some real-world PNG files have out-of-range pixel
+ // values. We fall back to opaque black, the same as libpng 1.5.13;
+ // ImageMagick 6.5.7 returns an error.
+ d.palette[i] = color.RGBA{0x00, 0x00, 0x00, 0xff}
+ }
+ d.palette = d.palette[:np]
case cbTC8, cbTCA8, cbTC16, cbTCA16:
// As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
// ignorable) for the ctTrueColor and ctTrueColorAlpha color types (section 4.1.2).
@@ -221,8 +230,8 @@ func (d *decoder) parsetRNS(length uint32) error {
case cbTC8, cbTC16:
return UnsupportedError("truecolor transparency")
case cbP1, cbP2, cbP4, cbP8:
- if n > len(d.palette) {
- return FormatError("bad tRNS length")
+ if len(d.palette) < n {
+ d.palette = d.palette[:n]
}
for i := 0; i < n; i++ {
rgba := d.palette[i].(color.RGBA)
@@ -279,7 +288,6 @@ func (d *decoder) decode() (image.Image, error) {
}
defer r.Close()
bitsPerPixel := 0
- maxPalette := uint8(0)
pixOffset := 0
var (
gray *image.Gray
@@ -308,7 +316,6 @@ func (d *decoder) decode() (image.Image, error) {
bitsPerPixel = d.depth
paletted = image.NewPaletted(image.Rect(0, 0, d.width, d.height), d.palette)
img = paletted
- maxPalette = uint8(len(d.palette) - 1)
case cbTCA8:
bitsPerPixel = 32
nrgba = image.NewNRGBA(image.Rect(0, 0, d.width, d.height))
@@ -421,8 +428,8 @@ func (d *decoder) decode() (image.Image, error) {
b := cdat[x/8]
for x2 := 0; x2 < 8 && x+x2 < d.width; x2++ {
idx := b >> 7
- if idx > maxPalette {
- return nil, FormatError("palette index out of range")
+ if len(paletted.Palette) <= int(idx) {
+ paletted.Palette = paletted.Palette[:int(idx)+1]
}
paletted.SetColorIndex(x+x2, y, idx)
b <<= 1
@@ -433,8 +440,8 @@ func (d *decoder) decode() (image.Image, error) {
b := cdat[x/4]
for x2 := 0; x2 < 4 && x+x2 < d.width; x2++ {
idx := b >> 6
- if idx > maxPalette {
- return nil, FormatError("palette index out of range")
+ if len(paletted.Palette) <= int(idx) {
+ paletted.Palette = paletted.Palette[:int(idx)+1]
}
paletted.SetColorIndex(x+x2, y, idx)
b <<= 2
@@ -445,18 +452,18 @@ func (d *decoder) decode() (image.Image, error) {
b := cdat[x/2]
for x2 := 0; x2 < 2 && x+x2 < d.width; x2++ {
idx := b >> 4
- if idx > maxPalette {
- return nil, FormatError("palette index out of range")
+ if len(paletted.Palette) <= int(idx) {
+ paletted.Palette = paletted.Palette[:int(idx)+1]
}
paletted.SetColorIndex(x+x2, y, idx)
b <<= 4
}
}
case cbP8:
- if maxPalette != 255 {
+ if len(paletted.Palette) != 255 {
for x := 0; x < d.width; x++ {
- if cdat[x] > maxPalette {
- return nil, FormatError("palette index out of range")
+ if len(paletted.Palette) <= int(cdat[x]) {
+ paletted.Palette = paletted.Palette[:int(cdat[x])+1]
}
}
}
diff --git a/libgo/go/image/testdata/video-001.progressive.jpeg b/libgo/go/image/testdata/video-001.progressive.jpeg
new file mode 100644
index 00000000000..b8cae23593c
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.progressive.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.q50.420.jpeg b/libgo/go/image/testdata/video-001.q50.420.jpeg
new file mode 100644
index 00000000000..83fb0f8abd0
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.q50.420.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.q50.420.progressive.jpeg b/libgo/go/image/testdata/video-001.q50.420.progressive.jpeg
new file mode 100644
index 00000000000..b048eb205bb
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.q50.420.progressive.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.q50.422.jpeg b/libgo/go/image/testdata/video-001.q50.422.jpeg
new file mode 100644
index 00000000000..60fff4ff9fe
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.q50.422.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.q50.422.progressive.jpeg b/libgo/go/image/testdata/video-001.q50.422.progressive.jpeg
new file mode 100644
index 00000000000..926d005de97
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.q50.422.progressive.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.q50.440.jpeg b/libgo/go/image/testdata/video-001.q50.440.jpeg
new file mode 100644
index 00000000000..32eeeaef6fc
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.q50.440.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.q50.440.progressive.jpeg b/libgo/go/image/testdata/video-001.q50.440.progressive.jpeg
new file mode 100644
index 00000000000..e641a3bbbca
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.q50.440.progressive.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.q50.444.jpeg b/libgo/go/image/testdata/video-001.q50.444.jpeg
new file mode 100644
index 00000000000..7d57433827c
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.q50.444.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-001.q50.444.progressive.jpeg b/libgo/go/image/testdata/video-001.q50.444.progressive.jpeg
new file mode 100644
index 00000000000..ff7d5f9ff0a
--- /dev/null
+++ b/libgo/go/image/testdata/video-001.q50.444.progressive.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-005.gray.q50.jpeg b/libgo/go/image/testdata/video-005.gray.q50.jpeg
new file mode 100644
index 00000000000..c65b5a794a6
--- /dev/null
+++ b/libgo/go/image/testdata/video-005.gray.q50.jpeg
Binary files differ
diff --git a/libgo/go/image/testdata/video-005.gray.q50.progressive.jpeg b/libgo/go/image/testdata/video-005.gray.q50.progressive.jpeg
new file mode 100644
index 00000000000..24b70e8bff9
--- /dev/null
+++ b/libgo/go/image/testdata/video-005.gray.q50.progressive.jpeg
Binary files differ