package qr
import (
"bytes"
"encoding/binary"
"hash"
"hash/crc32"
)
func (c *Code ) PNG () []byte {
var p pngWriter
return p .encode (c )
}
type pngWriter struct {
tmp [16 ]byte
wctmp [4 ]byte
buf bytes .Buffer
zlib bitWriter
crc hash .Hash32
}
var pngHeader = []byte ("\x89PNG\r\n\x1a\n" )
func (w *pngWriter ) encode (c *Code ) []byte {
scale := c .Scale
siz := c .Size
w .buf .Reset ()
w .buf .Write (pngHeader )
binary .BigEndian .PutUint32 (w .tmp [0 :4 ], uint32 ((siz +8 )*scale ))
binary .BigEndian .PutUint32 (w .tmp [4 :8 ], uint32 ((siz +8 )*scale ))
w .tmp [8 ] = 1
w .tmp [9 ] = 0
w .tmp [10 ] = 0
w .tmp [11 ] = 0
w .tmp [12 ] = 0
w .writeChunk ("IHDR" , w .tmp [:13 ])
w .writeChunk ("tEXt" , comment )
w .zlib .writeCode (c )
w .writeChunk ("IDAT" , w .zlib .bytes .Bytes ())
w .writeChunk ("IEND" , nil )
return w .buf .Bytes ()
}
var comment = []byte ("Software\x00QR-PNG http://qr.swtch.com/" )
func (w *pngWriter ) writeChunk (name string , data []byte ) {
if w .crc == nil {
w .crc = crc32 .NewIEEE ()
}
binary .BigEndian .PutUint32 (w .wctmp [0 :4 ], uint32 (len (data )))
w .buf .Write (w .wctmp [0 :4 ])
w .crc .Reset ()
copy (w .wctmp [0 :4 ], name )
w .buf .Write (w .wctmp [0 :4 ])
w .crc .Write (w .wctmp [0 :4 ])
w .buf .Write (data )
w .crc .Write (data )
crc := w .crc .Sum32 ()
binary .BigEndian .PutUint32 (w .wctmp [0 :4 ], crc )
w .buf .Write (w .wctmp [0 :4 ])
}
func (b *bitWriter ) writeCode (c *Code ) {
const ftNone = 0
b .adler32 .Reset ()
b .bytes .Reset ()
b .nbit = 0
scale := c .Scale
siz := c .Size
b .tmp [0 ] = 0x78
b .tmp [1 ] = 0
b .tmp [1 ] += uint8 (31 - (uint16 (b .tmp [0 ])<<8 +uint16 (b .tmp [1 ]))%31 )
b .bytes .Write (b .tmp [0 :2 ])
b .writeBits (1 , 1 , false )
b .writeBits (1 , 2 , false )
b .byte (ftNone )
n := (scale *(siz +8 ) + 7 ) / 8
b .byte (255 )
b .repeat (n -1 , 1 )
b .repeat ((4 *scale -1 )*(1 +n ), 1 +n )
for i := 0 ; i < 4 *scale ; i ++ {
b .adler32 .WriteNByte (ftNone , 1 )
b .adler32 .WriteNByte (255 , n )
}
row := make ([]byte , 1 +n )
for y := 0 ; y < siz ; y ++ {
row [0 ] = ftNone
j := 1
var z uint8
nz := 0
for x := -4 ; x < siz +4 ; x ++ {
for i := 0 ; i < scale ; i ++ {
z <<= 1
if !c .Black (x , y ) {
z |= 1
}
if nz ++; nz == 8 {
row [j ] = z
j ++
nz = 0
}
}
}
if j < len (row ) {
row [j ] = z
}
for _ , z := range row {
b .byte (z )
}
b .repeat ((scale -1 )*(1 +n ), 1 +n )
b .adler32 .WriteN (row , scale )
}
b .byte (ftNone )
b .byte (255 )
b .repeat (n -1 , 1 )
b .repeat ((4 *scale -1 )*(1 +n ), 1 +n )
for i := 0 ; i < 4 *scale ; i ++ {
b .adler32 .WriteNByte (ftNone , 1 )
b .adler32 .WriteNByte (255 , n )
}
b .hcode (256 )
b .flushBits ()
binary .BigEndian .PutUint32 (b .tmp [0 :], b .adler32 .Sum32 ())
b .bytes .Write (b .tmp [0 :4 ])
}
type bitWriter struct {
bytes bytes .Buffer
bit uint32
nbit uint
tmp [4 ]byte
adler32 adigest
}
func (b *bitWriter ) writeBits (bit uint32 , nbit uint , rev bool ) {
if rev {
br := uint32 (0 )
for i := uint (0 ); i < nbit ; i ++ {
br |= ((bit >> i ) & 1 ) << (nbit - 1 - i )
}
bit = br
}
b .bit |= bit << b .nbit
b .nbit += nbit
for b .nbit >= 8 {
b .bytes .WriteByte (byte (b .bit ))
b .bit >>= 8
b .nbit -= 8
}
}
func (b *bitWriter ) flushBits () {
if b .nbit > 0 {
b .bytes .WriteByte (byte (b .bit ))
b .nbit = 0
b .bit = 0
}
}
func (b *bitWriter ) hcode (v int ) {
switch {
case v <= 143 :
b .writeBits (uint32 (v )+0x30 , 8 , true )
case v <= 255 :
b .writeBits (uint32 (v -144 )+0x190 , 9 , true )
case v <= 279 :
b .writeBits (uint32 (v -256 )+0 , 7 , true )
case v <= 287 :
b .writeBits (uint32 (v -280 )+0xc0 , 8 , true )
default :
panic ("invalid hcode" )
}
}
func (b *bitWriter ) byte (x byte ) {
b .hcode (int (x ))
}
func (b *bitWriter ) codex (c int , val int , nx uint ) {
b .hcode (c + val >>nx )
b .writeBits (uint32 (val )&(1 <<nx -1 ), nx , false )
}
func (b *bitWriter ) repeat (n , d int ) {
for ; n >= 258 +3 ; n -= 258 {
b .repeat1 (258 , d )
}
if n > 258 {
b .repeat1 (10 , d )
b .repeat1 (n -10 , d )
return
}
if n < 3 {
panic ("invalid flate repeat" )
}
b .repeat1 (n , d )
}
func (b *bitWriter ) repeat1 (n , d int ) {
switch {
case n <= 10 :
b .codex (257 , n -3 , 0 )
case n <= 18 :
b .codex (265 , n -11 , 1 )
case n <= 34 :
b .codex (269 , n -19 , 2 )
case n <= 66 :
b .codex (273 , n -35 , 3 )
case n <= 130 :
b .codex (277 , n -67 , 4 )
case n <= 257 :
b .codex (281 , n -131 , 5 )
case n == 258 :
b .hcode (285 )
default :
panic ("invalid repeat length" )
}
if d <= 4 {
b .writeBits (uint32 (d -1 ), 5 , true )
} else if d <= 32768 {
nbit := uint (16 )
for d <= 1 <<(nbit -1 ) {
nbit --
}
v := uint32 (d - 1 )
v &^= 1 << (nbit - 1 )
code := uint32 (2 *nbit - 2 )
code |= v >> (nbit - 2 )
v &^= 1 << (nbit - 2 )
b .writeBits (code , 5 , true )
b .writeBits (uint32 (v ), nbit -2 , false )
} else {
panic ("invalid repeat distance" )
}
}
func (b *bitWriter ) run (v byte , n int ) {
if n == 0 {
return
}
b .byte (v )
if n -1 < 3 {
for i := 0 ; i < n -1 ; i ++ {
b .byte (v )
}
} else {
b .repeat (n -1 , 1 )
}
}
type adigest struct {
a , b uint32
}
func (d *adigest ) Reset () { d .a , d .b = 1 , 0 }
const amod = 65521
func aupdate (a , b uint32 , pi byte , n int ) (aa , bb uint32 ) {
if pi == 0 {
b += uint32 (n %amod ) * a
b = b % amod
return a , b
}
m := uint32 (n )
b += (m % amod ) * a
b = b % amod
b += (m * (m + 1 ) / 2 ) % amod * uint32 (pi )
b = b % amod
a += (m % amod ) * uint32 (pi )
a = a % amod
return a , b
}
func afinish (a , b uint32 ) uint32 {
return b <<16 | a
}
func (d *adigest ) WriteN (p []byte , n int ) {
for i := 0 ; i < n ; i ++ {
for _ , pi := range p {
d .a , d .b = aupdate (d .a , d .b , pi , 1 )
}
}
}
func (d *adigest ) WriteNByte (pi byte , n int ) {
d .a , d .b = aupdate (d .a , d .b , pi , n )
}
func (d *adigest ) Sum32 () uint32 { return afinish (d .a , d .b ) }
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .