Skip to content

Commit

Permalink
Add code
Browse files Browse the repository at this point in the history
  • Loading branch information
MordFustang21 committed Nov 17, 2019
1 parent d68d02d commit 3065788
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 0 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
GoZBar
---
ZBar bindings for golang. Only scanner supported.

Read the ZBar documentations for explanations on constants and arguments.

The ZBar library must be installed for this to compile.
42 changes: 42 additions & 0 deletions const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Package gozbar config bindings for golang.
// Read the ZBar documents for details
package gozbar

// #cgo LDFLAGS: -lzbar
// #include <zbar.h>
import "C"

// Symbol types (Scanner.SetConfig() argument symbology)
const (
NONE = C.ZBAR_NONE
PARTIAL = C.ZBAR_PARTIAL
EAN8 = C.ZBAR_EAN8
UPCE = C.ZBAR_UPCE
ISBN10 = C.ZBAR_ISBN10
UPCA = C.ZBAR_UPCA
EAN13 = C.ZBAR_EAN13
ISBN13 = C.ZBAR_ISBN13
I25 = C.ZBAR_I25
CODE39 = C.ZBAR_CODE39
PDF417 = C.ZBAR_PDF417
QRCODE = C.ZBAR_QRCODE
CODE128 = C.ZBAR_CODE128
SYMBOL = C.ZBAR_SYMBOL
ADDON = C.ZBAR_ADDON
ADDON2 = C.ZBAR_ADDON2
ADDON5 = C.ZBAR_ADDON5
)

// Configuration keys
const (
CFG_ENABLE = C.ZBAR_CFG_ENABLE
CFG_ADD_CHECK = C.ZBAR_CFG_ADD_CHECK
CFG_EMIT_CHECK = C.ZBAR_CFG_EMIT_CHECK
CFG_ASCII = C.ZBAR_CFG_ASCII
CFG_NUM = C.ZBAR_CFG_NUM
CFG_MIN_LEN = C.ZBAR_CFG_MIN_LEN
CFG_MAX_LEN = C.ZBAR_CFG_MAX_LEN
CFG_POSITION = C.ZBAR_CFG_POSITION
CFG_X_DENSITY = C.ZBAR_CFG_X_DENSITY
CFG_Y_DENSITY = C.ZBAR_CFG_Y_DENSITY
)
71 changes: 71 additions & 0 deletions image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Package gozbar image bindings for golang.
// Read the ZBar documents for details
package gozbar

// #cgo LDFLAGS: -lzbar
// #include <zbar.h>
import "C"

import (
"image"
"runtime"
"unsafe"
)

// Image contains a zbar image and the grayscale values.
type Image struct {
image *C.zbar_image_t
gray *image.Gray
}

// FromImage will create an ZBar image object from an image.Image.
// To scan the image, call a Scanner.
func FromImage(img image.Image) *Image {
// allocate the image wrapper
ret := &Image{
image: C.zbar_image_create(),
}

// get the height and width of the given image
bounds := img.Bounds()
w := bounds.Max.X - bounds.Min.X
h := bounds.Max.Y - bounds.Min.Y

// Create a grayscale image
ret.gray = image.NewGray(bounds)

// populate all the pixels in the gray image faster than draw.Draw()
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ {
ret.gray.Set(x, y, img.At(x, y))
}
}

C.zbar_image_set_format(ret.image, C.ulong(0x30303859)) // Y800 (grayscale)
C.zbar_image_set_size(ret.image, C.uint(w), C.uint(h))
C.zbar_image_set_data(ret.image, unsafe.Pointer(&ret.gray.Pix[0]), C.ulong(len(ret.gray.Pix)), nil)

// finalizer
runtime.SetFinalizer(ret, (*Image).Destroy)

return ret
}

// First will return the first scanned symbol of this image.
// To iterate over the symbols, use Symbol.Each() function
func (i *Image) First() *Symbol {
s := C.zbar_image_first_symbol(i.image)

if s == nil {
return nil
}

return &Symbol{
symbol: s,
}
}

// Destroy this object
func (i *Image) Destroy() {
C.zbar_image_destroy(i.image)
}
56 changes: 56 additions & 0 deletions scanner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Package gozbar scanner bindings for golang.
// Read the ZBar documents for details
package gozbar

// #cgo LDFLAGS: -lzbar
// #include <zbar.h>
import "C"

import (
"errors"
"fmt"
)

// Scanner contains a reference to zbar scanner.
type Scanner struct {
scanner *C.zbar_image_scanner_t
}

// NewScanner returns a new instance of Scanner.
func NewScanner() *Scanner {
return &Scanner{
scanner: C.zbar_image_scanner_create(),
}
}

// SetConfig gives the zbar scanner the configuration to run..
// Read the ZBar docs for details.
func (s *Scanner) SetConfig(symbology C.zbar_symbol_type_t, config C.zbar_config_t, value int) error {
// returns 0 for success, non-0 for failure
resp := int(C.zbar_image_scanner_set_config(s.scanner, symbology, config, C.int(value)))
if resp != 0 {
return fmt.Errorf("error encountered when setting config status: %d", resp)
}

return nil
}

// Scan parses the given image and loads the scanner.
func (s *Scanner) Scan(img *Image) error {
status := int(C.zbar_scan_image(s.scanner, img.image))
switch status {
// no symbols were found
case 0:
return errors.New("no symbols found")
// an error occurred
case -1:
return errors.New("an error was encountered during scan")
default:
return nil
}
}

// Destroy destroys the scanner.
func (s *Scanner) Destroy() {
C.zbar_image_scanner_destroy(s.scanner)
}
108 changes: 108 additions & 0 deletions scanner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package gozbar

import (
"image/jpeg"
"image/png"
"os"
"testing"
)

func TestBarcode(t *testing.T) {
const expectedVal = "9876543210128"

f, err := os.Open("testdata/barcode.png")
if err != nil {
t.Fatal(err)
}

i, err := png.Decode(f)
if err != nil {
t.Fatal(err)
}

img := FromImage(i)

s := NewScanner()
err = s.SetConfig(0, CFG_ENABLE, 1)
if err != nil {
t.Fatal("error setting config", err)
}

err = s.Scan(img)
if err != nil {
t.Fatal("error scanning", err)
}
defer s.Destroy()

img.First().Each(func(str string) {
if str != expectedVal {
t.Fatalf("expected [%s] got [%s]", expectedVal, str)
}
})
}

func TestQRCode(t *testing.T) {
const expectedVal = "ZBar big law good! ZBar螟ァ豕募・ス!"

f, err := os.Open("testdata/qr.jpg")
if err != nil {
t.Fail()
return
}

i, _ := jpeg.Decode(f)
img := FromImage(i)

s := NewScanner()
err = s.SetConfig(0, CFG_ENABLE, 1)
if err != nil {
t.Fatal("error setting config", err)
}

err = s.Scan(img)
if err != nil {
t.Fatal("error scanning", err)
}
defer s.Destroy()

img.First().Each(func(str string) {
if str != expectedVal {
t.Fatalf("expected [%s] got [%s]", expectedVal, str)
}
})
}

func TestPhoto(t *testing.T) {
const expectedStr = "http://www.searchenginestrategies.com/sanfrancisco/share.html"

f, err := os.Open("./testdata/photo.jpg")
if err != nil {
t.Fatal(err)
}

i, err := jpeg.Decode(f)
if err != nil {
t.Fatal(err)
}

img := FromImage(i)

s := NewScanner()
err = s.SetConfig(0, CFG_ENABLE, 1)
if err != nil {
t.Fatal("error setting config", err)
}

err = s.Scan(img)
if err != nil {
t.Fatal("error scanning", err)
}

defer s.Destroy()

img.First().Each(func(str string) {
if str != expectedStr {
t.Fatalf("expected [%s] got [%s]", expectedStr, str)
}
})
}
58 changes: 58 additions & 0 deletions symbol.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Package gozbar symbol bindings.
// Read the ZBar documents for details
package gozbar

// #cgo LDFLAGS: -lzbar
// #include <zbar.h>
import "C"

// Symbol is a wrapper around a zbar symbol.
type Symbol struct {
symbol *C.zbar_symbol_t
}

// Next returns the next symbol or nil if there is none.
func (s *Symbol) Next() *Symbol {
n := C.zbar_symbol_next(s.symbol)

if n == nil {
return nil
}

return &Symbol{
symbol: n,
}
}

// Data returns the scanned data for this symbol.
func (s *Symbol) Data() string {
sym := C.zbar_symbol_get_data(s.symbol)

if sym == nil {
return ""
}

return C.GoString(sym)
}

// Type returns the symbol type.
// Compare it with types in constants to get the accurate symbol type.
func (s *Symbol) Type() C.zbar_symbol_type_t {
return C.zbar_symbol_get_type(s.symbol)
}

// Each will iterate over all symbols after this symbol.
// passing them into the provided callback
func (s *Symbol) Each(f func(string)) {
t := s

for {
f(t.Data())

t = t.Next()

if t == nil {
break
}
}
}
Binary file added testdata/barcode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added testdata/photo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added testdata/qr.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3065788

Please sign in to comment.