From: Rob Pike Date: Mon, 16 May 2011 22:17:17 +0000 (-0700) Subject: GIF: support decoding of interlaced images. X-Git-Tag: weekly.2011-05-22~50 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ff1093852faa2515751880bb98763858f613df97;p=gostls13.git GIF: support decoding of interlaced images. R=nigeltao CC=golang-dev https://golang.org/cl/4535073 --- diff --git a/src/pkg/image/decode_test.go b/src/pkg/image/decode_test.go index e03b12deed..a0fba6fdba 100644 --- a/src/pkg/image/decode_test.go +++ b/src/pkg/image/decode_test.go @@ -29,6 +29,7 @@ var imageTests = []imageTest{ // GIF images are restricted to a 256-color palette and the conversion // to GIF loses significant image quality. {"testdata/video-001.gif", 64 << 8}, + {"testdata/video-001.interlaced.gif", 64 << 8}, // JPEG is a lossy format and hence needs a non-zero tolerance. {"testdata/video-001.jpeg", 8 << 8}, {"testdata/video-001.png", 0}, diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go index e083b87100..e27b74b64d 100644 --- a/src/pkg/image/gif/reader.go +++ b/src/pkg/image/gif/reader.go @@ -191,6 +191,10 @@ Loop: if c != 0 { return os.ErrorString("gif: extra data after image") } + + // Undo the interlacing if necessary. + d.uninterlace(m) + d.image = append(d.image, m) d.delay = append(d.delay, d.delayTime) d.delayTime = 0 // TODO: is this correct, or should we hold on to the value? @@ -321,14 +325,14 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, os.Error) { if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil { return nil, fmt.Errorf("gif: can't read image descriptor: %s", err) } + // TODO: This code (throughout) ignores the top and left values, + // and assumes (in interlacing, for example) that the images' + // widths and heights are all the same. _ = int(d.tmp[0]) + int(d.tmp[1])<<8 // TODO: honor left value _ = int(d.tmp[2]) + int(d.tmp[3])<<8 // TODO: honor top value width := int(d.tmp[4]) + int(d.tmp[5])<<8 height := int(d.tmp[6]) + int(d.tmp[7])<<8 d.imageFields = d.tmp[8] - if d.imageFields&ifInterlace != 0 { - return nil, os.ErrorString("gif: can't handle interlaced images") - } return image.NewPaletted(width, height, nil), nil } @@ -340,9 +344,42 @@ func (d *decoder) readBlock() (int, os.Error) { return io.ReadFull(d.r, d.tmp[0:n]) } +// interlaceScan defines the ordering for a pass of the interlace algorithm. +type interlaceScan struct { + skip, start int +} + +// interlacing represents the set of scans in an interlaced GIF image. +var interlacing = []interlaceScan{ + {8, 0}, // Group 1 : Every 8th. row, starting with row 0. + {8, 4}, // Group 2 : Every 8th. row, starting with row 4. + {4, 2}, // Group 3 : Every 4th. row, starting with row 2. + {2, 1}, // Group 4 : Every 2nd. row, starting with row 1. +} + +func (d *decoder) uninterlace(m *image.Paletted) { + if d.imageFields&ifInterlace == 0 { + return + } + var nPix []uint8 + dx := d.width + dy := d.height + nPix = make([]uint8, dx*dy) + offset := 0 // steps through the input by sequentical scan lines. + for _, pass := range interlacing { + nOffset := pass.start * dx // steps through the output as defined by pass. + for y := pass.start; y < dy; y += pass.skip { + copy(nPix[nOffset:nOffset+dx], m.Pix[offset:offset+dx]) + offset += dx + nOffset += dx * pass.skip + } + } + m.Pix = nPix +} + // Decode reads a GIF image from r and returns the first embedded // image as an image.Image. -// Limitation: The file must be 8 bits per pixel and have no interlacing. +// Limitation: The file must be 8 bits per pixel. func Decode(r io.Reader) (image.Image, os.Error) { var d decoder if err := d.decode(r, false); err != nil { @@ -360,7 +397,7 @@ type GIF struct { // DecodeAll reads a GIF image from r and returns the sequential frames // and timing information. -// Limitation: The file must be 8 bits per pixel and have no interlacing. +// Limitation: The file must be 8 bits per pixel. func DecodeAll(r io.Reader) (*GIF, os.Error) { var d decoder if err := d.decode(r, false); err != nil { diff --git a/src/pkg/image/testdata/video-001.interlaced.gif b/src/pkg/image/testdata/video-001.interlaced.gif new file mode 100644 index 0000000000..590594ea9a Binary files /dev/null and b/src/pkg/image/testdata/video-001.interlaced.gif differ