1package qr 2 3import ( 4 "errors" 5 "image" 6 "image/color" 7 "github.com/vitrun/qart/coding" 8) 9 10// A Level denotes a QR error correction level. 11// From least to most tolerant of errors, they are L, M, Q, H. 12type Level int 13 14const ( 15 L Level = iota // 20% redundant 16 M // 38% redundant 17 Q // 55% redundant 18 H // 65% redundant 19) 20 21// Encode returns an encoding of text at the given error correction level. 22func Encode(text string, level Level) (*Code, error) { 23 // Pick data encoding, smallest first. 24 // We could split the string and use different encodings 25 // but that seems like overkill for now. 26 var enc coding.Encoding 27 switch { 28 case coding.Num(text).Check() == nil: 29 enc = coding.Num(text) 30 case coding.Alpha(text).Check() == nil: 31 enc = coding.Alpha(text) 32 default: 33 enc = coding.String(text) 34 } 35 36 // Pick size. 37 l := coding.Level(level) 38 var v coding.Version 39 for v = coding.MinVersion; ; v++ { 40 if v > coding.MaxVersion { 41 return nil, errors.New("text too long to encode as QR") 42 } 43 if enc.Bits(v) <= v.DataBytes(l)*8 { 44 break 45 } 46 } 47 48 // Build and execute plan. 49 p, err := coding.NewPlan(v, l, 0) 50 if err != nil { 51 return nil, err 52 } 53 cc, err := p.Encode(enc) 54 if err != nil { 55 return nil, err 56 } 57 58 // TODO: Pick appropriate mask. 59 60 return &Code{cc.Bitmap, cc.Size, cc.Stride, 8}, nil 61} 62 63// A Code is a square pixel grid. 64// It implements image.Image and direct PNG encoding. 65type Code struct { 66 Bitmap []byte // 1 is black, 0 is white 67 Size int // number of pixels on a side 68 Stride int // number of bytes per row 69 Scale int // number of image pixels per QR pixel 70} 71 72// Black returns true if the pixel at (x,y) is black. 73func (c *Code) Black(x, y int) bool { 74 return 0 <= x && x < c.Size && 0 <= y && y < c.Size && 75 c.Bitmap[y*c.Stride+x/8]&(1<<uint(7-x&7)) != 0 76} 77 78// Image returns an Image displaying the code. 79func (c *Code) Image() image.Image { 80 return &codeImage{c} 81 82} 83 84// codeImage implements image.Image 85type codeImage struct { 86 *Code 87} 88 89var ( 90 whiteColor color.Color = color.Gray{0xFF} 91 blackColor color.Color = color.Gray{0x00} 92) 93 94func (c *codeImage) Bounds() image.Rectangle { 95 d := (c.Size + 8) * c.Scale 96 return image.Rect(0, 0, d, d) 97} 98 99func (c *codeImage) At(x, y int) color.Color { 100 if c.Black(x, y) { 101 return blackColor 102 } 103 return whiteColor 104} 105 106func (c *codeImage) ColorModel() color.Model { 107 return color.GrayModel 108} 109 110