package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"image"
"image/color"
"image/draw"
"image/gif"
"image/jpeg"
"image/png"
"io/ioutil"
"log"
"net/http"
"code.google.com/p/rsc/qr"
"code.google.com/p/rsc/qr/web/resize"
"github.com/golang/freetype"
"github.com/golang/freetype/truetype"
"golang.org/x/image/bmp"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
type circle struct {
p image.Point
r int
}
func (c *circle) ColorModel() color.Model {
return color.AlphaModel
}
func (c *circle) Bounds() image.Rectangle {
return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
}
func (c *circle) At(x, y int) color.Color {
xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
if xx*xx+yy*yy < rr*rr {
return color.Alpha{255}
}
return color.Alpha{0}
}
var (
// bgImage 漂亮的背景
bgImage = getNetImage("http://olcd71ai5.bkt.clouddn.com/qr/bg.png")
// fontFile 字体文件
fontFile = "config/Dengl.ttf"
// fontSize 字体尺寸
fontSize float64 = 18
// fontDPI 屏幕每英寸的分辨率
fontDPI float64 = 72
// font 字体
fontType *truetype.Font
)
func init() {
fontBytes, err := ioutil.ReadFile(fontFile)
if err != nil {
panic(err)
}
fontType, err = freetype.ParseFont(fontBytes)
if err != nil {
panic(err)
}
}
func main() {
http.HandleFunc("/qr", qrImage)
fmt.Println(http.ListenAndServe(":8080", nil))
}
func qrImage(w http.ResponseWriter, req *http.Request) {
content := req.FormValue("data")
data, err := base64.StdEncoding.DecodeString(content)
if err != nil {
log.Println(err)
return
}
v := struct {
URL string `json:"url"`
HeadURL string `json:"headurl"`
NickName string `json:"nickname"`
}{}
json.Unmarshal(data, &v)
sx, sy, width := 110, 915, 120
qrCode, _ := qr.Encode(v.URL, qr.L)
pngData := qrCode.PNG()
imgQrPng, _ := png.Decode(bytes.NewReader(pngData))
imgQrPng = resize.Resample(imgQrPng, imgQrPng.Bounds(), width, width)
qrBounds := imgQrPng.Bounds()
qrDx := qrBounds.Dx()
qrDy := qrBounds.Dy()
img := image.NewRGBA(bgImage.Bounds())
draw.Draw(img, bgImage.Bounds(), bgImage, image.Pt(0, 0), draw.Src)
for x := 0; x < qrDx; x++ {
for y := 0; y < qrDy; y++ {
qrColor := imgQrPng.At(x, y)
r, g, b, _ := qrColor.RGBA()
if r == 0 || g == 0 || b == 0 {
img.Set(sx+x, sy+y, qrColor)
}
}
}
if v.HeadURL != "" {
headImage := getNetImage(v.HeadURL)
headImage = resize.Resample(headImage, headImage.Bounds(), 100, 100)
sp := image.Pt(250, 80)
rect := headImage.Bounds().Add(sp)
draw.DrawMask(img, rect, headImage, image.ZP, &circle{image.Pt(50, 50), 50}, image.ZP, draw.Over)
}
if v.NickName != "" {
d := &font.Drawer{
Dst: img,
Src: image.NewUniform(color.RGBA{0xff, 0x00, 0x00, 0xff}),
Face: truetype.NewFace(fontType, &truetype.Options{
Size: fontSize,
DPI: fontDPI,
Hinting: font.HintingNone,
}),
}
d.Dot = fixed.Point26_6{
X: (fixed.I(600) - d.MeasureString(v.NickName)) / 2,
Y: fixed.I(205),
}
d.DrawString(v.NickName)
}
w.Header().Set("Content-Type", "image/jpeg")
jpeg.Encode(w, img, &jpeg.Options{Quality: 90})
}
func getNetImage(url string) image.Image {
resp, err := http.Get(url)
if err != nil {
log.Println(err)
return image.NewNRGBA(image.Rect(0, 0, 600, 400))
}
defer resp.Body.Close()
data, _ := ioutil.ReadAll(resp.Body)
contentType := http.DetectContentType(data)
var imgBG image.Image
if contentType == "image/png" {
imgBG, err = png.Decode(bytes.NewReader(data))
} else if contentType == "image/jpeg" {
imgBG, err = jpeg.Decode(bytes.NewReader(data))
} else if contentType == "image/gif" {
imgBG, err = gif.Decode(bytes.NewReader(data))
} else if contentType == "image/bmp" {
imgBG, err = bmp.Decode(bytes.NewReader(data))
}
if err != nil {
log.Println(err)
return image.NewNRGBA(image.Rect(0, 0, 600, 400))
}
return imgBG
}