diff options
Diffstat (limited to 'libgo/go/image/jpeg/writer.go')
-rw-r--r-- | libgo/go/image/jpeg/writer.go | 133 |
1 files changed, 97 insertions, 36 deletions
diff --git a/libgo/go/image/jpeg/writer.go b/libgo/go/image/jpeg/writer.go index c58fbf30555..91bbde3bf80 100644 --- a/libgo/go/image/jpeg/writer.go +++ b/libgo/go/image/jpeg/writer.go @@ -249,7 +249,7 @@ func (e *encoder) writeByte(b byte) { e.err = e.w.WriteByte(b) } -// emit emits the least significant nBits bits of bits to the bitstream. +// emit emits the least significant nBits bits of bits to the bit-stream. // The precondition is bits < 1<<nBits && nBits <= 16. func (e *encoder) emit(bits, nBits uint32) { nBits += e.nBits @@ -312,32 +312,44 @@ func (e *encoder) writeDQT() { } // writeSOF0 writes the Start Of Frame (Baseline) marker. -func (e *encoder) writeSOF0(size image.Point) { - const markerlen = 8 + 3*nColorComponent +func (e *encoder) writeSOF0(size image.Point, nComponent int) { + markerlen := 8 + 3*nComponent e.writeMarkerHeader(sof0Marker, markerlen) e.buf[0] = 8 // 8-bit color. e.buf[1] = uint8(size.Y >> 8) e.buf[2] = uint8(size.Y & 0xff) e.buf[3] = uint8(size.X >> 8) e.buf[4] = uint8(size.X & 0xff) - e.buf[5] = nColorComponent - for i := 0; i < nColorComponent; i++ { - e.buf[3*i+6] = uint8(i + 1) - // We use 4:2:0 chroma subsampling. - e.buf[3*i+7] = "\x22\x11\x11"[i] - e.buf[3*i+8] = "\x00\x01\x01"[i] + e.buf[5] = uint8(nComponent) + if nComponent == 1 { + e.buf[6] = 1 + // No subsampling for grayscale image. + e.buf[7] = 0x11 + e.buf[8] = 0x00 + } else { + for i := 0; i < nComponent; i++ { + e.buf[3*i+6] = uint8(i + 1) + // We use 4:2:0 chroma subsampling. + e.buf[3*i+7] = "\x22\x11\x11"[i] + e.buf[3*i+8] = "\x00\x01\x01"[i] + } } - e.write(e.buf[:3*(nColorComponent-1)+9]) + e.write(e.buf[:3*(nComponent-1)+9]) } // writeDHT writes the Define Huffman Table marker. -func (e *encoder) writeDHT() { +func (e *encoder) writeDHT(nComponent int) { markerlen := 2 - for _, s := range theHuffmanSpec { + specs := theHuffmanSpec[:] + if nComponent == 1 { + // Drop the Chrominance tables. + specs = specs[:2] + } + for _, s := range specs { markerlen += 1 + 16 + len(s.value) } e.writeMarkerHeader(dhtMarker, markerlen) - for i, s := range theHuffmanSpec { + for i, s := range specs { e.writeByte("\x00\x10\x01\x11"[i]) e.write(s.count[:]) e.write(s.value) @@ -345,8 +357,8 @@ 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. +// 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 int32) int32 { fdct(b) // Emit the DC delta. @@ -390,6 +402,20 @@ func toYCbCr(m image.Image, p image.Point, yBlock, cbBlock, crBlock *block) { } } +// grayToY stores the 8x8 region of m whose top-left corner is p in yBlock. +func grayToY(m *image.Gray, p image.Point, yBlock *block) { + b := m.Bounds() + xmax := b.Max.X - 1 + ymax := b.Max.Y - 1 + pix := m.Pix + for j := 0; j < 8; j++ { + for i := 0; i < 8; i++ { + idx := m.PixOffset(min(p.X+i, xmax), min(p.Y+j, ymax)) + yBlock[8*j+i] = int32(pix[idx]) + } + } +} + // rgbaToYCbCr is a specialized version of toYCbCr for image.RGBA images. func rgbaToYCbCr(m *image.RGBA, p image.Point, yBlock, cbBlock, crBlock *block) { b := m.Bounds() @@ -430,7 +456,18 @@ func scale(dst *block, src *[4]block) { } } -// sosHeader is the SOS marker "\xff\xda" followed by 12 bytes: +// sosHeaderY is the SOS marker "\xff\xda" followed by 8 bytes: +// - the marker length "\x00\x08", +// - the number of components "\x01", +// - component 1 uses DC table 0 and AC table 0 "\x01\x00", +// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for +// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al) +// should be 0x00, 0x3f, 0x00<<4 | 0x00. +var sosHeaderY = []byte{ + 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, +} + +// sosHeaderYCbCr is the SOS marker "\xff\xda" followed by 12 bytes: // - the marker length "\x00\x0c", // - the number of components "\x03", // - component 1 uses DC table 0 and AC table 0 "\x01\x00", @@ -439,14 +476,19 @@ func scale(dst *block, src *[4]block) { // - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for // sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al) // should be 0x00, 0x3f, 0x00<<4 | 0x00. -var sosHeader = []byte{ +var sosHeaderYCbCr = []byte{ 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, } // writeSOS writes the StartOfScan marker. func (e *encoder) writeSOS(m image.Image) { - e.write(sosHeader) + switch m.(type) { + case *image.Gray: + e.write(sosHeaderY) + default: + e.write(sosHeaderYCbCr) + } var ( // Scratch buffers to hold the YCbCr values. // The blocks are in natural (not zig-zag) order. @@ -456,24 +498,36 @@ func (e *encoder) writeSOS(m image.Image) { prevDCY, prevDCCb, prevDCCr int32 ) bounds := m.Bounds() - rgba, _ := m.(*image.RGBA) - for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 { - for x := bounds.Min.X; x < bounds.Max.X; x += 16 { - for i := 0; i < 4; i++ { - xOff := (i & 1) * 8 - yOff := (i & 2) * 4 - p := image.Pt(x+xOff, y+yOff) - if rgba != nil { - rgbaToYCbCr(rgba, p, &b, &cb[i], &cr[i]) - } else { - toYCbCr(m, p, &b, &cb[i], &cr[i]) - } + switch m := m.(type) { + // TODO(wathiede): switch on m.ColorModel() instead of type. + case *image.Gray: + for y := bounds.Min.Y; y < bounds.Max.Y; y += 8 { + for x := bounds.Min.X; x < bounds.Max.X; x += 8 { + p := image.Pt(x, y) + grayToY(m, p, &b) prevDCY = e.writeBlock(&b, 0, prevDCY) } - scale(&b, &cb) - prevDCCb = e.writeBlock(&b, 1, prevDCCb) - scale(&b, &cr) - prevDCCr = e.writeBlock(&b, 1, prevDCCr) + } + default: + rgba, _ := m.(*image.RGBA) + for y := bounds.Min.Y; y < bounds.Max.Y; y += 16 { + for x := bounds.Min.X; x < bounds.Max.X; x += 16 { + for i := 0; i < 4; i++ { + xOff := (i & 1) * 8 + yOff := (i & 2) * 4 + p := image.Pt(x+xOff, y+yOff) + if rgba != nil { + rgbaToYCbCr(rgba, p, &b, &cb[i], &cr[i]) + } else { + toYCbCr(m, p, &b, &cb[i], &cr[i]) + } + prevDCY = e.writeBlock(&b, 0, prevDCY) + } + 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. @@ -532,6 +586,13 @@ func Encode(w io.Writer, m image.Image, o *Options) error { e.quant[i][j] = uint8(x) } } + // Compute number of components based on input image type. + nComponent := 3 + switch m.(type) { + // TODO(wathiede): switch on m.ColorModel() instead of type. + case *image.Gray: + nComponent = 1 + } // Write the Start Of Image marker. e.buf[0] = 0xff e.buf[1] = 0xd8 @@ -539,9 +600,9 @@ func Encode(w io.Writer, m image.Image, o *Options) error { // Write the quantization tables. e.writeDQT() // Write the image dimensions. - e.writeSOF0(b.Size()) + e.writeSOF0(b.Size(), nComponent) // Write the Huffman tables. - e.writeDHT() + e.writeDHT(nComponent) // Write the image data. e.writeSOS(m) // Write the End Of Image marker. |