diff --git a/internal/png/stdlibwriter.go b/internal/png/stdlibwriter.go index 5e9448b2d..a34b85add 100644 --- a/internal/png/stdlibwriter.go +++ b/internal/png/stdlibwriter.go @@ -9,6 +9,7 @@ package png import ( "bufio" "compress/zlib" + "encoding/binary" "hash/crc32" "image" "image/color" @@ -64,14 +65,6 @@ const ( // compression level, although that is not implemented yet. ) -// Big-endian. -func writeUint32(b []uint8, u uint32) { - b[0] = uint8(u >> 24) - b[1] = uint8(u >> 16) - b[2] = uint8(u >> 8) - b[3] = uint8(u >> 0) -} - type opaquer interface { Opaque() bool } @@ -110,7 +103,7 @@ func (e *encoder) writeChunk(b []byte, name string) { e.err = UnsupportedError(name + " chunk is too large: " + strconv.Itoa(len(b))) return } - writeUint32(e.header[:4], n) + binary.BigEndian.PutUint32(e.header[:4], n) e.header[4] = name[0] e.header[5] = name[1] e.header[6] = name[2] @@ -118,7 +111,7 @@ func (e *encoder) writeChunk(b []byte, name string) { crc := crc32.NewIEEE() crc.Write(e.header[4:8]) crc.Write(b) - writeUint32(e.footer[:4], crc.Sum32()) + binary.BigEndian.PutUint32(e.footer[:4], crc.Sum32()) _, e.err = e.w.Write(e.header[:8]) if e.err != nil { @@ -133,8 +126,8 @@ func (e *encoder) writeChunk(b []byte, name string) { func (e *encoder) writeIHDR() { b := e.m.Bounds() - writeUint32(e.tmp[0:4], uint32(b.Dx())) - writeUint32(e.tmp[4:8], uint32(b.Dy())) + binary.BigEndian.PutUint32(e.tmp[0:4], uint32(b.Dx())) + binary.BigEndian.PutUint32(e.tmp[4:8], uint32(b.Dy())) // Set bit depth and color type. switch e.cb { case cbG8: @@ -146,6 +139,15 @@ func (e *encoder) writeIHDR() { case cbP8: e.tmp[8] = 8 e.tmp[9] = ctPaletted + case cbP4: + e.tmp[8] = 4 + e.tmp[9] = ctPaletted + case cbP2: + e.tmp[8] = 2 + e.tmp[9] = ctPaletted + case cbP1: + e.tmp[8] = 1 + e.tmp[9] = ctPaletted case cbTCA8: e.tmp[8] = 8 e.tmp[9] = ctTrueColorAlpha @@ -314,31 +316,38 @@ func (e *encoder) writeImage(w io.Writer, m image.Image, cb int, level int) erro } defer e.zw.Close() - bpp := 0 // Bytes per pixel. + bitsPerPixel := 0 switch cb { case cbG8: - bpp = 1 + bitsPerPixel = 8 case cbTC8: - bpp = 3 + bitsPerPixel = 24 case cbP8: - bpp = 1 + bitsPerPixel = 8 + case cbP4: + bitsPerPixel = 4 + case cbP2: + bitsPerPixel = 2 + case cbP1: + bitsPerPixel = 1 case cbTCA8: - bpp = 4 + bitsPerPixel = 32 case cbTC16: - bpp = 6 + bitsPerPixel = 48 case cbTCA16: - bpp = 8 + bitsPerPixel = 64 case cbG16: - bpp = 2 + bitsPerPixel = 16 } + // cr[*] and pr are the bytes for the current and previous row. // cr[0] is unfiltered (or equivalently, filtered with the ftNone filter). // cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the // other PNG filter types. These buffers are allocated once and re-used for each row. // The +1 is for the per-row filter type, which is at cr[*][0]. b := m.Bounds() - sz := 1 + bpp*b.Dx() + sz := 1 + (bitsPerPixel*b.Dx()+7)/8 for i := range e.cr { if cap(e.cr[i]) < sz { e.cr[i] = make([]uint8, sz) @@ -414,6 +423,30 @@ func (e *encoder) writeImage(w io.Writer, m image.Image, cb int, level int) erro i += 1 } } + + case cbP4, cbP2, cbP1: + pi := m.(image.PalettedImage) + + var a uint8 + var c int + for x := b.Min.X; x < b.Max.X; x++ { + a = a<