Skip to content

Commit

Permalink
[dev] decode is now good
Browse files Browse the repository at this point in the history
  • Loading branch information
nanmu42 committed Oct 27, 2018
1 parent ad4cd3d commit ed9f48c
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 3 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,15 @@
# qrcode-api
A simple API service for QR Code generation/recognition

# Compile

Install and compile ZBar:

```bash
wget https://downloads.sourceforge.net/project/zbar/zbar/0.10/zbar-0.10.tar.bz2
tar -xf zbar-0.10.tar.bz2
cd zbar-0.10
export CFLAGS=""
./configure --disable-video --without-imagemagick --without-qt --without-python --without-gtk --without-x --disable-pthread
make install
```
5 changes: 4 additions & 1 deletion cmd/api/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
VERSION=`git describe --tags --dirty`
BUILD=`date +%FT%T%z`

go build -ldflags "-s -w -X main.Version=$VERSION -X main.BuildDate=$BUILD" -o qrcode-api
# can not build statically safely
# see https://stackoverflow.com/questions/8140439/why-would-it-be-impossible-to-fully-statically-link-an-application
export LD_LIBRARY_PATH=/usr/local/lib
go build -ldflags '-s -w -X main.Version=$VERSION -X main.BuildDate=$BUILD' -o qrcode-api
6 changes: 6 additions & 0 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ var (
BuildDate string
)

// maxDecodeFileByte is MaxDecodeFileSize's byte version
var maxDecodeFileByte int64

func init() {
w := common.NewBufferedLumberjack(&lumberjack.Logger{
Filename: "qrcode-api.log",
Expand All @@ -48,6 +51,7 @@ func main() {
defer logger.Sync()
defer func() {
if err != nil {
fmt.Println(err)
logger.Fatal("fatal error",
zap.Error(err),
)
Expand All @@ -67,6 +71,8 @@ built on %s
return
}

maxDecodeFileByte = int64(C.MaxDecodeFileSize << 10)

router := setupRouter()
startAPI(router, C.Port)
}
85 changes: 83 additions & 2 deletions cmd/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,21 @@ import (
"bytes"
"context"
"fmt"
"image"
"io"
"net/http"
"os"
"os/signal"
"sync/atomic"
"syscall"
"time"

"github.com/pkg/errors"

_ "image/gif"
_ "image/jpeg"
_ "image/png"

"github.com/nanmu42/qrcode-api"

"go.uber.org/zap"
Expand Down Expand Up @@ -47,6 +55,7 @@ func setupRouter() (router *gin.Engine) {

// setup routes
router.GET("/encode", EncodeQRCode)
router.POST("/decode", DecodeQRCode)
return
}

Expand Down Expand Up @@ -134,15 +143,15 @@ func EncodeQRCode(c *gin.Context) {
encoder, err := ParseEncodeRequest(c.Request.URL.Query())
if err != nil {
c.Error(err)
c.String(http.StatusBadRequest, "%s", err.Error())
c.String(http.StatusBadRequest, err.Error())
return
}

var buf bytes.Buffer
gotType, err := encoder.Encode(&buf)
if err != nil {
c.Error(err)
c.String(http.StatusInternalServerError, "%s", err.Error())
c.String(http.StatusInternalServerError, err.Error())
return
}

Expand All @@ -155,3 +164,75 @@ func EncodeQRCode(c *gin.Context) {

return
}

// DecodeQRCode controller to decode QR Code
func DecodeQRCode(c *gin.Context) {
var err error

// avoid too big image
if c.Request.ContentLength >= maxDecodeFileByte {
err = errors.New("request is too big(content-length)")
c.Error(err)
c.JSON(http.StatusOK, DecodeResponse{
OK: false,
Desc: "request is too big",
Content: nil,
})
return
}
var buf bytes.Buffer
_, readErr := io.CopyN(&buf, c.Request.Body, maxDecodeFileByte)
if readErr == nil {
err = errors.New("request is too big(actually read)")
c.Error(err)
c.JSON(http.StatusOK, DecodeResponse{
OK: false,
Desc: "request is too big",
Content: nil,
})
return
}
if readErr != io.EOF {
err = errors.Wrap(readErr, "body read error")
c.Error(err)
c.JSON(http.StatusOK, DecodeResponse{
OK: false,
Desc: err.Error(),
Content: nil,
})
return
}

// decode image
input, _, err := image.Decode(&buf)
if err != nil {
err = errors.Wrap(err, "file decoding error")
c.Error(err)
c.JSON(http.StatusOK, DecodeResponse{
OK: false,
Desc: err.Error(),
Content: nil,
})
return
}

contents, err := qrcode.DecodeQRCode(input)
if err != nil {
err = errors.Wrap(err, "QR Code scanning error")
c.Error(err)
c.JSON(http.StatusOK, DecodeResponse{
OK: false,
Desc: err.Error(),
Content: nil,
})
return
}

c.JSON(http.StatusOK, DecodeResponse{
OK: true,
Desc: "",
Content: contents,
})

return
}
3 changes: 3 additions & 0 deletions cmd/api/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env bash

LD_LIBRARY_PATH=/usr/local/lib ./qrcode-api
7 changes: 7 additions & 0 deletions cmd/api/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,10 @@ func ParseEncodeRequest(values url.Values) (encoder qrcode.QREncoder, err error)
encoder.Type = values.Get(typeField)
return
}

// DecodeResponse content holder for response
type DecodeResponse struct {
OK bool `json:"ok"`
Desc string `json:"desc"`
Content []string `json:"content"`
}
39 changes: 39 additions & 0 deletions decode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018 LI Zhennan
*
* Use of this work is governed by an MIT License.
* You may find a license copy in project root.
*/

package qrcode

import (
"errors"
"image"

"github.com/PeterCxy/gozbar"
)

// DecodeQRCode decodes QR Code content from image
//
// content contains multiple string if there are more than one QR Code
// got decoded.
// content and err are both nil when no QR Code found.
func DecodeQRCode(img image.Image) (content []string, err error) {
input := zbar.FromImage(img)

s := zbar.NewScanner()
s.SetConfig(zbar.QRCODE, zbar.CFG_ENABLE, 1)
result := s.Scan(input)

if result < 0 {
err = errors.New("error occurred when scanning")
return
}

input.First().Each(func(item string) {
content = append(content, item)
})

return
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/nanmu42/qrcode-api

require (
github.com/PeterCxy/gozbar v0.0.0-20151016114418-0b38584c8ebd
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
github.com/gin-gonic/gin v1.3.0
github.com/golang/protobuf v1.2.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/PeterCxy/gozbar v0.0.0-20151016114418-0b38584c8ebd h1:sokLkqqCxrUcnf+Ptl42sqBdg7z5+u/GdKOWH9WCvDY=
github.com/PeterCxy/gozbar v0.0.0-20151016114418-0b38584c8ebd/go.mod h1:zZuJKy6Ywgi7DSwgUn0UMhiaNMt2rXW5kCQESjg7YKw=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
Expand Down

0 comments on commit ed9f48c

Please sign in to comment.