├── .gitignore ├── Makefile ├── README.md ├── cmd └── main.go ├── generate.go ├── goquirc.go ├── goquirc_test.go ├── internal └── quirc │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README │ ├── demo │ ├── camera.c │ ├── camera.h │ ├── convert.c │ ├── convert.h │ ├── demo.c │ ├── demoutil.c │ ├── demoutil.h │ ├── dthash.c │ ├── dthash.h │ ├── mjpeg.c │ ├── mjpeg.h │ └── scanner.c │ ├── lib │ ├── decode.c │ ├── identify.c │ ├── quirc.c │ ├── quirc.h │ ├── quirc_internal.h │ └── version_db.c │ └── tests │ ├── dbgutil.c │ ├── dbgutil.h │ ├── inspect.c │ └── qrtest.c └── testdata ├── 01-1.jpg ├── 01-2.jpg ├── 01-3.jpg ├── 01-4.jpg ├── 02-1.jpg ├── 02-2.jpg ├── 02-3.jpg ├── 02-4.jpg ├── 03-1.jpg ├── 03-2.jpg ├── 03-3.jpg ├── 03-4.jpg ├── 04-1.jpg ├── 04-2.jpg ├── 04-3.jpg ├── 04-4.jpg ├── 05-1.jpg ├── 05-2.jpg ├── 05-3.jpg ├── 05-4.jpg ├── 06-1.jpg ├── 06-2.jpg ├── 06-3.jpg ├── 06-4.jpg ├── 125.bmp ├── out.png ├── qart1.png ├── qart10.png ├── qart11.png ├── qart12.png ├── qart13.png ├── qart14.png ├── qart15.png ├── qart2.png ├── qart3.png ├── qart4.png ├── qart5.png ├── qart6.png ├── qart7.png ├── qart8.png ├── qart9.png ├── qr-bbc.png ├── qr-bbc1.png ├── qr.png └── qrcode.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.o -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | 3 | LIB_OBJ = \ 4 | internal/quirc/lib/decode.o \ 5 | internal/quirc/lib/identify.o \ 6 | internal/quirc/lib/quirc.o \ 7 | internal/quirc/lib/version_db.o 8 | 9 | libquirc.a: $(LIB_OBJ) 10 | ar cru $@ $^ 11 | ranlib $@ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | goquirc 2 | ======= 3 | 4 | This is a simple wrapper around [Quirc](https://github.com/dlbeer/quirc). 5 | 6 | [http://godoc.org/github.com/kdar/goquirc](http://godoc.org/github.com/kdar/goquirc) 7 | 8 | ### Install 9 | 10 | 1. `go get -d github.com/kdar/goquirc` 11 | 2. `go generate` and `go install` 12 | 13 | ### Notes 14 | 15 | This package isn't meant to be exhaustive, but I'll try to add something if requested and time permitting. 16 | 17 | ### Detection rate 18 | 19 | The tests in this package do not pass. [Quirc](https://github.com/dlbeer/quirc) cannot detect a lot of QR codes that I tested. As far as detection goes, I rate the following from best to worse: 20 | 21 | 1. [ZBar](https://github.com/ZBar/ZBar) 22 | 2. [Quirc](https://github.com/dlbeer/quirc) 23 | 3. [libdecodeqr](https://github.com/josephholsten/libdecodeqr) used in [qrcode](https://github.com/chai2010/qrcode) 24 | 25 | ZBar is by far the best. It could decode everything I threw at it. The problem is I couldn't get it to compile under Windows 64 MinGW in a timely manner, so I moved on. 26 | 27 | Quirc works for the purposes I needed it for, and the API is super simple. 28 | 29 | libdecodeqr could barely decode even the basic things. I'm not too sure why it has so much trouble, even with flat out crisp, generated QR codes. 30 | 31 | ### Request 32 | 33 | Anyone know of any good QR decoding libraries that can decode at a high success rate and are in C/Go? 34 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "fmt" 7 | "github.com/kdar/goquirc" 8 | "image" 9 | _ "image/gif" 10 | _ "image/jpeg" 11 | _ "image/png" 12 | "io/ioutil" 13 | "log" 14 | "os" 15 | ) 16 | 17 | func main() { 18 | flag.Parse() 19 | 20 | if len(flag.Args()) == 0 { 21 | log.Fatalf("usage: %s ", os.Args[0]) 22 | } 23 | 24 | path := flag.Arg(0) 25 | 26 | imgdata, err := ioutil.ReadFile(path) 27 | if err != nil { 28 | log.Fatal(path+":", err) 29 | } 30 | 31 | // Decode image 32 | m, _, err := image.Decode(bytes.NewReader(imgdata)) 33 | if err != nil { 34 | log.Fatal(path+":", err) 35 | } 36 | 37 | d := goquirc.New() 38 | defer d.Destroy() 39 | datas, err := d.Decode(m) 40 | if err != nil { 41 | log.Fatal(path+":", err) 42 | } 43 | 44 | for _, data := range datas { 45 | fmt.Printf("%s\n", data.Payload[:data.PayloadLen]) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /generate.go: -------------------------------------------------------------------------------- 1 | //go:generate make -f Makefile 2 | 3 | package goquirc 4 | -------------------------------------------------------------------------------- /goquirc.go: -------------------------------------------------------------------------------- 1 | package goquirc 2 | 3 | /* 4 | #cgo CFLAGS: -I./internal/quirc/lib 5 | #cgo windows LDFLAGS: ./libquirc.a 6 | #cgo linux LDFLAGS: ./libquirc.a 7 | #cgo darwin LDFLAGS: ./libquirc.a 8 | 9 | #include "internal/quirc/lib/quirc.h" 10 | */ 11 | import "C" 12 | 13 | import ( 14 | "fmt" 15 | "image" 16 | "image/color" 17 | 18 | // "image/png" 19 | "math" 20 | // "os" 21 | "unsafe" 22 | ) 23 | 24 | // type DecodeError C.quirc_decode_error_t 25 | // type Code C.struct_quirc_code 26 | // type Data C.struct_quirc_data 27 | // type Point C.struct_quirc_point 28 | 29 | const ( 30 | MaxBitmap = 3917 31 | MaxPayload = 8896 32 | 33 | /* QR-code ECC types. */ 34 | ECCLevelM = 0 35 | ECCLevelL = 1 36 | ECCLevelH = 2 37 | ECCLevelQ = 3 38 | 39 | /* QR-code data types. */ 40 | DataTypeNumeric = 1 41 | DataTypeAlpha = 2 42 | DataTypeByte = 4 43 | DataTypeKanji = 8 44 | ) 45 | 46 | // Created by cgo -godefs 47 | // cgo -godefs goquirc.go 48 | type Data struct { 49 | Version int32 50 | ECCLevel int32 51 | Mask int32 52 | DataType int32 53 | Payload [MaxPayload]uint8 54 | PayloadLen int32 55 | } 56 | 57 | type Decoder struct { 58 | decoder *C.struct_quirc 59 | } 60 | 61 | // New creates a new decoder. 62 | func New() *Decoder { 63 | return &Decoder{ 64 | decoder: C.quirc_new(), 65 | } 66 | } 67 | 68 | // Destroy frees up the memory allocated by the decoder. 69 | // Call this when you're done decoding images. 70 | func (d *Decoder) Destroy() { 71 | C.quirc_destroy(d.decoder) 72 | } 73 | 74 | // var tmptest = 0 75 | 76 | // DecodeBytes decodes the data in the passed image and returns 77 | // any bytes encoded in it. 78 | func (d *Decoder) DecodeBytes(img image.Image) ([]byte, error) { 79 | datas, err := d.Decode(img) 80 | if err != nil { 81 | return nil, err 82 | } 83 | 84 | if datas != nil && len(datas) > 0 { 85 | return []byte(datas[0].Payload[:datas[0].PayloadLen]), nil 86 | } 87 | 88 | return nil, nil 89 | } 90 | 91 | // Decode decodes the passed image and returns a slice of Data 92 | // structures of the found QR data. 93 | func (d *Decoder) Decode(img image.Image) ([]Data, error) { 94 | b := img.Bounds() 95 | cw := C.int(b.Max.X) 96 | ch := C.int(b.Max.Y) 97 | 98 | if C.quirc_resize(d.decoder, cw, ch) < 0 { 99 | return nil, fmt.Errorf("failed to resize image buffer") 100 | } 101 | 102 | mem := C.quirc_begin(d.decoder, nil, nil) 103 | if mem == nil { 104 | return nil, fmt.Errorf("could not obtain image buffer") 105 | } 106 | 107 | slice := (*[1 << 30]byte)(unsafe.Pointer(mem))[:b.Max.X*b.Max.Y : b.Max.X*b.Max.Y] 108 | 109 | grayimg := image.NewGray(b) 110 | 111 | switch m := img.(type) { 112 | case *image.Gray: 113 | off := 0 114 | for y := b.Min.Y; y < b.Max.Y; y++ { 115 | for x := b.Min.X; x < b.Max.X; x++ { 116 | gray := m.GrayAt(x, y) 117 | slice[off] = byte(gray.Y) 118 | grayimg.Set(x, y, gray) 119 | off++ 120 | } 121 | } 122 | case *image.RGBA: 123 | off := 0 124 | for y := b.Min.Y; y < b.Max.Y; y++ { 125 | for x := b.Min.X; x < b.Max.X; x++ { 126 | pix := toGrayLuminance(m.At(x, y)) 127 | slice[off] = byte(pix) 128 | 129 | // grayimg.Set(x, y, color.Gray{toGrayLuma(m.At(x, y))}) 130 | 131 | off++ 132 | } 133 | } 134 | default: 135 | off := 0 136 | for y := b.Min.Y; y < b.Max.Y; y++ { 137 | for x := b.Min.X; x < b.Max.X; x++ { 138 | rgba := color.RGBAModel.Convert(m.At(x, y)).(color.RGBA) 139 | pix := toGrayLuminance(rgba) 140 | slice[off] = byte(pix) 141 | // grayimg.Set(x, y, color.Gray{toGrayLuma(rgba)}) 142 | off++ 143 | } 144 | } 145 | } 146 | 147 | // fp, _ := os.Create(fmt.Sprintf("out/%d.png", tmptest)) 148 | // defer fp.Close() 149 | // tmptest++ 150 | // png.Encode(fp, grayimg) 151 | 152 | C.quirc_end(d.decoder) 153 | 154 | count := int(C.quirc_count(d.decoder)) 155 | if count == 0 { 156 | return nil, fmt.Errorf("no QR code found in image") 157 | } 158 | 159 | var datas []Data 160 | for i := 0; i < count; i++ { 161 | var code C.struct_quirc_code 162 | var data C.struct_quirc_data 163 | 164 | C.quirc_extract(d.decoder, C.int(i), &code) 165 | res := C.quirc_decode(&code, &data) 166 | if res == C.QUIRC_SUCCESS { 167 | datas = append(datas, *(*Data)(unsafe.Pointer(&data))) 168 | } else { 169 | str := C.GoString(C.quirc_strerror(res)) 170 | return nil, fmt.Errorf("decode failed: %s", str) 171 | } 172 | } 173 | 174 | return datas, nil 175 | 176 | // var code C.struct_quirc_code 177 | // C.quirc_extract(d.decoder, 0, &code) 178 | 179 | // //fmt.Printf("%d - %d\n", (code.size-17)%4, code.size) 180 | 181 | // var data C.struct_quirc_data 182 | // res := C.quirc_decode(&code, &data) 183 | // if res != C.QUIRC_SUCCESS { 184 | // str := C.GoString(C.quirc_strerror(res)) 185 | // return nil, fmt.Errorf("decode failed: %s", str) 186 | // } 187 | 188 | // return (*Data)(unsafe.Pointer(&data)), nil 189 | } 190 | 191 | func toGrayLuminance(c color.Color) uint8 { 192 | rr, gg, bb, _ := c.RGBA() 193 | r := math.Pow(float64(rr), 2.2) 194 | g := math.Pow(float64(gg), 2.2) 195 | b := math.Pow(float64(bb), 2.2) 196 | y := math.Pow(0.2125*r+0.7154*g+0.0721*b, 1/2.2) 197 | Y := uint16(y + 0.5) 198 | return uint8(Y >> 8) 199 | } 200 | -------------------------------------------------------------------------------- /goquirc_test.go: -------------------------------------------------------------------------------- 1 | package goquirc 2 | 3 | import ( 4 | "bytes" 5 | "image" 6 | _ "image/jpeg" 7 | _ "image/png" 8 | "io/ioutil" 9 | "os" 10 | "path/filepath" 11 | "testing" 12 | ) 13 | 14 | func TestDecode(t *testing.T) { 15 | d := New() 16 | 17 | total := 0 18 | success := 0 19 | failed := 0 20 | 21 | err := filepath.Walk("testdata/", func(path string, info os.FileInfo, err error) error { 22 | if err != nil { 23 | return err 24 | } 25 | 26 | if info.IsDir() { 27 | return nil 28 | } 29 | 30 | total++ 31 | 32 | imgdata, err := ioutil.ReadFile(path) 33 | if err != nil { 34 | t.Error(path+":", err) 35 | return nil 36 | } 37 | 38 | // Decode image 39 | m, _, err := image.Decode(bytes.NewReader(imgdata)) 40 | if err != nil { 41 | t.Error(path+":", err) 42 | return nil 43 | } 44 | 45 | datas, err := d.Decode(m) 46 | if err != nil { 47 | failed++ 48 | t.Error(path+":", err) 49 | } else if datas != nil { 50 | success++ 51 | //fmt.Printf("%s: %d\n", path, len(datas)) 52 | // for _, v := range datas { 53 | // fmt.Printf("%s[%d]: %s\n", path, v.DataType, v.Payload[:v.PayloadLen]) 54 | // } 55 | } 56 | 57 | return nil 58 | }) 59 | if err != nil { 60 | t.Fatal(err) 61 | } 62 | 63 | d.Destroy() 64 | 65 | if success != total { 66 | t.Errorf("out of %d images, %d failed and %d succeeded", total, failed, success) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /internal/quirc/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.lo 3 | quirc-demo 4 | quirc-scanner 5 | qrtest 6 | inspect 7 | libquirc.a 8 | libquirc.so 9 | .*.swp 10 | *~ 11 | -------------------------------------------------------------------------------- /internal/quirc/LICENSE: -------------------------------------------------------------------------------- 1 | quirc -- QR-code recognition library 2 | Copyright (C) 2010-2012 Daniel Beer 3 | 4 | Permission to use, copy, modify, and/or distribute this software for 5 | any purpose with or without fee is hereby granted, provided that the 6 | above copyright notice and this permission notice appear in all 7 | copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 | PERFORMANCE OF THIS SOFTWARE. 17 | -------------------------------------------------------------------------------- /internal/quirc/Makefile: -------------------------------------------------------------------------------- 1 | # quirc -- QR-code recognition library 2 | # Copyright (C) 2010-2012 Daniel Beer 3 | # 4 | # Permission to use, copy, modify, and/or distribute this software for any 5 | # purpose with or without fee is hereby granted, provided that the above 6 | # copyright notice and this permission notice appear in all copies. 7 | # 8 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | 16 | CC ?= gcc 17 | PREFIX ?= /usr/local 18 | SDL_CFLAGS := $(shell pkg-config --cflags sdl) 19 | SDL_LIBS := $(shell pkg-config --libs sdl) 20 | 21 | LIB_VERSION = 1.0 22 | LIB_SONAME = libquirc.so.1 23 | 24 | QUIRC_CFLAGS = -O3 -Wall -Ilib $(CFLAGS) $(SDL_CFLAGS) 25 | LIB_OBJ = \ 26 | lib/decode.o \ 27 | lib/identify.o \ 28 | lib/quirc.o \ 29 | lib/version_db.o 30 | LIB_SOBJ = $(subst .o,.lo,$(LIB_OBJ)) 31 | DEMO_OBJ = \ 32 | demo/camera.o \ 33 | demo/mjpeg.o \ 34 | demo/convert.o \ 35 | demo/dthash.o \ 36 | demo/demoutil.o 37 | 38 | all: libquirc.so qrtest inspect quirc-demo quirc-scanner 39 | 40 | qrtest: tests/dbgutil.o tests/qrtest.o libquirc.a 41 | $(CC) -o $@ $^ -lm -ljpeg 42 | 43 | inspect: tests/dbgutil.o tests/inspect.o libquirc.a 44 | $(CC) -o $@ $^ -lm -ljpeg $(SDL_LIBS) -lSDL_gfx 45 | 46 | quirc-demo: $(DEMO_OBJ) demo/demo.o libquirc.a 47 | $(CC) -o $@ $^ -lm -ljpeg $(SDL_LIBS) -lSDL_gfx 48 | 49 | quirc-scanner: $(DEMO_OBJ) demo/scanner.o libquirc.a 50 | $(CC) -o $@ $^ -lm -ljpeg 51 | 52 | libquirc.a: $(LIB_OBJ) 53 | rm -f $@ 54 | ar cru $@ $^ 55 | ranlib $@ 56 | 57 | libquirc.so: $(LIB_SOBJ) 58 | $(CC) -shared -Wl,-soname=$(LIB_SONAME) -o $@ $^ -lm 59 | 60 | %.o: %.c 61 | $(CC) $(QUIRC_CFLAGS) -o $*.o -c $*.c 62 | 63 | %.lo: %.c 64 | $(CC) -fPIC $(QUIRC_CFLAGS) -o $*.lo -c $*.c 65 | 66 | install: libquirc.a libquirc.so quirc-demo quirc-scanner 67 | install -o root -g root -m 0644 lib/quirc.h $(DESTDIR)$(PREFIX)/include 68 | install -o root -g root -m 0644 libquirc.a $(DESTDIR)$(PREFIX)/lib 69 | install -o root -g root -m 0755 libquirc.so \ 70 | $(DESTDIR)$(PREFIX)/lib/libquirc.so.$(LIB_VERSION) 71 | ln -sf libquirc.so.$(LIB_VERSION) $(DESTDIR)$(PREFIX)/lib/$(LIB_SONAME) 72 | ln -sf libquirc.so.$(LIB_VERSION) $(DESTDIR)$(PREFIX)/lib/libquirc.so 73 | install -o root -g root -m 0755 quirc-demo $(DESTDIR)$(PREFIX)/bin 74 | install -o root -g root -m 0755 quirc-scanner $(DESTDIR)$(PREFIX)/bin 75 | 76 | uninstall: 77 | rm -f $(DESTDIR)$(PREFIX)/include/quirc.h 78 | rm -f $(DESTDIR)$(PREFIX)/lib/libquirc.so.$(LIB_VERSION) 79 | rm -f $(DESTDIR)$(PREFIX)/lib/$(LIB_SONAME) 80 | rm -f $(DESTDIR)$(PREFIX)/lib/libquirc.so 81 | rm -f $(DESTDIR)$(PREFIX)/lib/libquirc.a 82 | rm -f $(DESTDIR)$(PREFIX)/bin/quirc-demo 83 | rm -f $(DESTDIR)$(PREFIX)/bin/quirc-scanner 84 | 85 | clean: 86 | rm -f */*.o 87 | rm -f */*.lo 88 | rm -f libquirc.a 89 | rm -f libquirc.so 90 | rm -f qrtest 91 | rm -f inspect 92 | rm -f quirc-demo 93 | rm -f quirc-scanner 94 | -------------------------------------------------------------------------------- /internal/quirc/README: -------------------------------------------------------------------------------- 1 | Quirc 2 | ===== 3 | 4 | QR codes are a type of high-density matrix barcodes, and quirc is a 5 | library for extracting and decoding them from images. It has several 6 | features which make it a good choice for this purpose: 7 | 8 | * It is fast enough to be used with realtime video: extracting and 9 | decoding from VGA frame takes about 50 ms on a modern x86 core. 10 | 11 | * It has a robust and tolerant recognition algorithm. It can 12 | correctly recognise and decode QR codes which are rotated and/or 13 | oblique to the camera. It can also distinguish and decode multiple 14 | codes within the same image. 15 | 16 | * It is easy to use, with a simple API described in a single 17 | commented header file (see below for an overview). 18 | 19 | * It is small and easily embeddable, with no dependencies other than 20 | standard C functions. 21 | 22 | * It has a very small memory footprint: one byte per image pixel, 23 | plus a few kB per decoder object. 24 | 25 | * It uses no global mutable state, and is safe to use in a 26 | multithreaded application. 27 | 28 | * BSD-licensed, with almost no restrictions regarding use and/or 29 | modification. 30 | 31 | The distribution comes with, in addition to the library, several test 32 | programs. While the core library is very portable, these programs have 33 | some additional dependencies. All of them require libjpeg, and two 34 | (``quirc-demo`` and ``inspect``) require SDL. The camera demos use 35 | Linux-specific APIs: 36 | 37 | ``quirc-demo`` 38 | 39 | ~ This is an real-time demo which requires a camera and a graphical 40 | display. The video stream is displayed on screen as it's received, 41 | and any QR codes recognised are highlighted in the image, with the 42 | decoded information both displayed on the image and printed on 43 | stdout. 44 | 45 | ``quirc-scanner`` 46 | 47 | ~ This program turns your camera into a barcode scanner. It's almost 48 | the same as the ``demo`` application, but it doesn't display the 49 | video stream, and thus doesn't require a graphical display. 50 | 51 | ``qrtest`` 52 | 53 | ~ This test is used to evaluate the performance of library. Given a 54 | directory tree containing a bunch of JPEG images, it will attempt 55 | to locate and decode QR codes in each image. Speed and success 56 | statistics are collected and printed on stdout. 57 | 58 | ``inspect`` 59 | 60 | ~ This test is used for debugging. Given a single JPEG image, it 61 | will display a diagram showing the internal state of the decoder 62 | as well as printing additional information on stdout. 63 | 64 | Installation 65 | ------------ 66 | 67 | To build the library and associated demos/tests, type ``make``. Type 68 | ``make install`` to install the library, header file and camera demos. 69 | 70 | You can specify one or several of the following targets if you don't 71 | want, or are unable to build everything: 72 | 73 | * libquirc.a 74 | * libquirc.so 75 | * qrtest 76 | * inspect 77 | * quirc-scanner 78 | * quirc-demo 79 | 80 | Library use 81 | ----------- 82 | 83 | All of the library's functionality is exposed through a single header 84 | file, which you should include: 85 | 86 | #include 87 | 88 | To decode images, you'll need to instantiate a ``struct quirc`` 89 | object, which is done with the ``quirc_new`` function. Later, when you 90 | no longer need to decode anything, you should release the allocated 91 | memory with ``quirc_destroy``: 92 | 93 | struct quirc *qr; 94 | 95 | qr = quirc_new(); 96 | if (!qr) { 97 | perror("Failed to allocate memory"); 98 | abort(); 99 | } 100 | 101 | /* ... */ 102 | 103 | quirc_destroy(qr); 104 | 105 | Having obtained a decoder object, you need to set the image size that 106 | you'll be working with, which is done using ``quirc_resize``: 107 | 108 | if (quirc_resize(qr, 640, 480) < 0) { 109 | perror("Failed to allocate video memory"); 110 | abort(); 111 | } 112 | 113 | ``quirc_resize`` and ``quirc_new`` are the only library functions 114 | which allocate memory. If you plan to process a series of frames (or a 115 | video stream), you probably want to allocate and size a single decoder 116 | and hold onto it to process each frame. 117 | 118 | Processing frames is done in two stages. The first stage is an 119 | image-recognition stage called identification, which takes a grayscale 120 | image and searches for QR codes. Using ``quirc_begin`` and 121 | ``quirc_end``, you can feed a grayscale image directly into the buffer 122 | that ``quirc`` uses for image processing: 123 | 124 | uint8_t *image; 125 | int w, h; 126 | 127 | image = quirc_begin(qr, &w, &h); 128 | 129 | /* Fill out the image buffer here. 130 | * image is a pointer to a w*h bytes. 131 | * One byte per pixel, w pixels per line, h lines in the buffer. 132 | */ 133 | 134 | quirc_end(qr); 135 | 136 | Note that ``quirc_begin`` simply returns a pointer to a previously 137 | allocated buffer. The buffer will contain uninitialized data. After 138 | the call to ``quirc_end``, the decoder holds a list of detected QR 139 | codes which can be queried via ``quirc_count`` and ``quirc_extract``. 140 | 141 | At this point, the second stage of processing occurs -- decoding. This 142 | is done via the call to ``quirc_decode``, which is not associated with 143 | a decoder object. 144 | 145 | int num_codes; 146 | int i; 147 | 148 | /* We've previously fed an image to the decoder via 149 | * quirc_begin/quirc_end. 150 | */ 151 | 152 | num_codes = quirc_count(qr); 153 | for (i = 0; i < num_codes; i++) { 154 | struct quirc_code code; 155 | struct quirc_data data; 156 | quirc_decode_error_t err; 157 | 158 | quirc_extract(qr, i, &code); 159 | 160 | /* Decoding stage */ 161 | err = quirc_decode(&code, &data); 162 | if (err) 163 | printf("DECODE FAILED: %s\n", quirc_strerror(err)); 164 | else 165 | printf("Data: %s\n", data.payload); 166 | } 167 | 168 | ``quirc_code`` and ``quirc_data`` are flat structures which don't need 169 | to be initialized or freed after use. 170 | 171 | Copyright 172 | --------- 173 | 174 | Copyright (C) 2010-2012 Daniel Beer <> 175 | 176 | Permission to use, copy, modify, and/or distribute this software for 177 | any purpose with or without fee is hereby granted, provided that the 178 | above copyright notice and this permission notice appear in all 179 | copies. 180 | 181 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 182 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 183 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 184 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 185 | DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 186 | PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 187 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 188 | PERFORMANCE OF THIS SOFTWARE. 189 | -------------------------------------------------------------------------------- /internal/quirc/demo/camera.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2014 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "camera.h" 28 | 29 | /************************************************************************ 30 | * Fraction arithmetic 31 | */ 32 | 33 | static int gcd(int a, int b) 34 | { 35 | if (a < 0) 36 | a = -a; 37 | if (b < 0) 38 | b = -b; 39 | 40 | for (;;) { 41 | if (a < b) { 42 | const int t = a; 43 | 44 | a = b; 45 | b = t; 46 | } 47 | 48 | if (!b) 49 | break; 50 | 51 | a %= b; 52 | } 53 | 54 | return a; 55 | } 56 | 57 | static void frac_reduce(const struct v4l2_fract *f, struct v4l2_fract *g) 58 | { 59 | const int x = gcd(f->numerator, f->denominator); 60 | int n = f->numerator; 61 | int d = f->denominator; 62 | 63 | if (d < 0) { 64 | n = -n; 65 | d = -d; 66 | } 67 | 68 | g->numerator = n / x; 69 | g->denominator = d / x; 70 | } 71 | 72 | static void frac_add(const struct v4l2_fract *a, const struct v4l2_fract *b, 73 | struct v4l2_fract *r) 74 | { 75 | r->numerator = a->numerator * b->denominator + 76 | b->numerator * b->denominator; 77 | r->denominator = a->denominator * b->denominator; 78 | 79 | frac_reduce(r, r); 80 | } 81 | 82 | static void frac_sub(const struct v4l2_fract *a, const struct v4l2_fract *b, 83 | struct v4l2_fract *r) 84 | { 85 | r->numerator = a->numerator * b->denominator - 86 | b->numerator * b->denominator; 87 | r->denominator = a->denominator * b->denominator; 88 | 89 | frac_reduce(r, r); 90 | } 91 | 92 | static int frac_cmp(const struct v4l2_fract *a, const struct v4l2_fract *b) 93 | { 94 | return a->numerator * b->denominator - b->numerator * b->denominator; 95 | } 96 | 97 | static void frac_mul(const struct v4l2_fract *a, const struct v4l2_fract *b, 98 | struct v4l2_fract *r) 99 | { 100 | r->numerator = a->numerator * b->numerator; 101 | r->denominator = a->denominator * b->denominator; 102 | 103 | frac_reduce(r, r); 104 | } 105 | 106 | static void frac_div(const struct v4l2_fract *a, const struct v4l2_fract *b, 107 | struct v4l2_fract *r) 108 | { 109 | r->numerator = a->numerator * b->denominator; 110 | r->denominator = a->denominator * b->numerator; 111 | 112 | frac_reduce(r, r); 113 | } 114 | 115 | static int frac_cmp_ref(const struct v4l2_fract *ref, 116 | const struct v4l2_fract *a, 117 | const struct v4l2_fract *b) 118 | { 119 | struct v4l2_fract da; 120 | struct v4l2_fract db; 121 | 122 | frac_sub(a, ref, &da); 123 | frac_sub(b, ref, &db); 124 | 125 | if (da.numerator < 0) 126 | da.numerator = -da.numerator; 127 | if (db.numerator < 0) 128 | db.numerator = -db.numerator; 129 | 130 | return frac_cmp(&da, &db); 131 | } 132 | 133 | /************************************************************************ 134 | * Parameter searching and choosing 135 | */ 136 | 137 | static camera_format_t map_fmt(uint32_t pf) 138 | { 139 | if (pf == V4L2_PIX_FMT_YUYV) 140 | return CAMERA_FORMAT_YUYV; 141 | 142 | if (pf == V4L2_PIX_FMT_MJPEG) 143 | return CAMERA_FORMAT_MJPEG; 144 | 145 | return CAMERA_FORMAT_UNKNOWN; 146 | } 147 | 148 | static int find_best_format(int fd, uint32_t *fmt_ret) 149 | { 150 | struct v4l2_fmtdesc best; 151 | int i = 1; 152 | 153 | memset(&best, 0, sizeof(best)); 154 | best.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 155 | best.index = 0; 156 | 157 | if (ioctl(fd, VIDIOC_ENUM_FMT, &best) < 0) 158 | return -1; 159 | 160 | for (;;) { 161 | struct v4l2_fmtdesc f; 162 | 163 | memset(&f, 0, sizeof(f)); 164 | f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 165 | f.index = ++i; 166 | 167 | if (ioctl(fd, VIDIOC_ENUM_FMT, &f) < 0) 168 | break; 169 | 170 | if (map_fmt(f.pixelformat) > map_fmt(best.pixelformat)) 171 | memcpy(&best, &f, sizeof(best)); 172 | } 173 | 174 | if (fmt_ret) 175 | *fmt_ret = best.pixelformat; 176 | 177 | return 0; 178 | } 179 | 180 | static int step_to_discrete(int min, int max, int step, int target) 181 | { 182 | int offset; 183 | 184 | if (target < min) 185 | return min; 186 | 187 | if (target > max) 188 | return max; 189 | 190 | offset = (target - min) % step; 191 | if ((offset * 2 > step) && (target + step <= max)) 192 | target += step; 193 | 194 | return target - offset; 195 | } 196 | 197 | static int score_discrete(const struct v4l2_frmsizeenum *f, int w, int h) 198 | { 199 | const int dw = f->discrete.width - w; 200 | const int dh = f->discrete.height - h; 201 | 202 | return dw * dw + dh * dh; 203 | } 204 | 205 | static int find_best_size(int fd, uint32_t pixel_format, 206 | int target_w, int target_h, 207 | int *ret_w, int *ret_h) 208 | { 209 | struct v4l2_frmsizeenum best; 210 | int i = 1; 211 | 212 | memset(&best, 0, sizeof(best)); 213 | best.index = 0; 214 | best.pixel_format = pixel_format; 215 | 216 | if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &best) < 0) 217 | return -1; 218 | 219 | if (best.type != V4L2_FRMSIZE_TYPE_DISCRETE) { 220 | *ret_w = step_to_discrete(best.stepwise.min_width, 221 | best.stepwise.max_width, 222 | best.stepwise.step_width, 223 | target_w); 224 | *ret_h = step_to_discrete(best.stepwise.min_height, 225 | best.stepwise.max_height, 226 | best.stepwise.step_height, 227 | target_h); 228 | return 0; 229 | } 230 | 231 | for (;;) { 232 | struct v4l2_frmsizeenum f; 233 | 234 | memset(&f, 0, sizeof(f)); 235 | f.index = ++i; 236 | f.pixel_format = pixel_format; 237 | 238 | if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &f) < 0) 239 | break; 240 | 241 | if (score_discrete(&f, target_w, target_h) < 242 | score_discrete(&best, target_w, target_h)) 243 | memcpy(&best, &f, sizeof(best)); 244 | } 245 | 246 | *ret_w = best.discrete.width; 247 | *ret_h = best.discrete.height; 248 | 249 | return 0; 250 | } 251 | 252 | static int find_best_rate(int fd, uint32_t pixel_format, 253 | int w, int h, int target_n, int target_d, 254 | int *ret_n, int *ret_d) 255 | { 256 | const struct v4l2_fract target = { 257 | .numerator = target_n, 258 | .denominator = target_d 259 | }; 260 | struct v4l2_frmivalenum best; 261 | int i = 1; 262 | 263 | memset(&best, 0, sizeof(best)); 264 | best.index = 0; 265 | best.pixel_format = pixel_format; 266 | best.width = w; 267 | best.height = h; 268 | 269 | if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &best) < 0) 270 | return -1; 271 | 272 | if (best.type != V4L2_FRMIVAL_TYPE_DISCRETE) { 273 | struct v4l2_fract t; 274 | 275 | if (frac_cmp(&target, &best.stepwise.min) < 0) { 276 | *ret_n = best.stepwise.min.numerator; 277 | *ret_d = best.stepwise.min.denominator; 278 | } 279 | 280 | if (frac_cmp(&target, &best.stepwise.max) > 0) { 281 | *ret_n = best.stepwise.max.numerator; 282 | *ret_d = best.stepwise.max.denominator; 283 | } 284 | 285 | frac_sub(&target, &best.stepwise.min, &t); 286 | frac_div(&t, &best.stepwise.step, &t); 287 | if (t.numerator * 2 >= t.denominator) 288 | t.numerator += t.denominator; 289 | t.numerator /= t.denominator; 290 | t.denominator = 1; 291 | frac_mul(&t, &best.stepwise.step, &t); 292 | frac_add(&t, &best.stepwise.max, &t); 293 | 294 | if (frac_cmp(&t, &best.stepwise.max) > 0) { 295 | *ret_n = best.stepwise.max.numerator; 296 | *ret_d = best.stepwise.max.denominator; 297 | } else { 298 | *ret_n = t.numerator; 299 | *ret_d = t.denominator; 300 | } 301 | 302 | return 0; 303 | } 304 | 305 | for (;;) { 306 | struct v4l2_frmivalenum f; 307 | 308 | memset(&f, 0, sizeof(f)); 309 | f.index = ++i; 310 | f.pixel_format = pixel_format; 311 | f.width = w; 312 | f.height = h; 313 | 314 | if (ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &f) < 0) 315 | break; 316 | 317 | if (frac_cmp_ref(&target, &f.discrete, &best.discrete) < 0) 318 | memcpy(&best, &f, sizeof(best)); 319 | } 320 | 321 | *ret_n = best.discrete.numerator; 322 | *ret_d = best.discrete.denominator; 323 | 324 | return 0; 325 | } 326 | 327 | /************************************************************************ 328 | * Public interface 329 | */ 330 | 331 | void camera_init(struct camera *c) 332 | { 333 | c->fd = -1; 334 | c->buf_count = 0; 335 | c->s_on = 0; 336 | } 337 | 338 | void camera_destroy(struct camera *c) 339 | { 340 | camera_close(c); 341 | } 342 | 343 | int camera_open(struct camera *c, const char *path, 344 | int target_w, int target_h, 345 | int tr_n, int tr_d) 346 | { 347 | struct v4l2_format fmt; 348 | struct v4l2_streamparm parm; 349 | uint32_t pf; 350 | int w, h; 351 | int n, d; 352 | 353 | if (c->fd >= 0) 354 | camera_close(c); 355 | 356 | /* Open device and get basic properties */ 357 | c->fd = open(path, O_RDWR); 358 | if (c->fd < 0) 359 | return -1; 360 | 361 | /* Find a pixel format from the list */ 362 | if (find_best_format(c->fd, &pf) < 0) 363 | goto fail; 364 | 365 | /* Find a frame size */ 366 | if (find_best_size(c->fd, pf, target_w, target_h, &w, &h) < 0) 367 | goto fail; 368 | 369 | /* Find a frame rate */ 370 | if (find_best_rate(c->fd, pf, w, h, tr_n, tr_d, &n, &d) < 0) 371 | goto fail; 372 | 373 | /* Set format */ 374 | memset(&fmt, 0, sizeof(fmt)); 375 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 376 | fmt.fmt.pix.width = w; 377 | fmt.fmt.pix.height = h; 378 | fmt.fmt.pix.pixelformat = pf; 379 | if (ioctl(c->fd, VIDIOC_S_FMT, &fmt) < 0) 380 | goto fail; 381 | 382 | memset(&fmt, 0, sizeof(fmt)); 383 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 384 | if (ioctl(c->fd, VIDIOC_G_FMT, &fmt) < 0) 385 | goto fail; 386 | 387 | /* Set frame interval */ 388 | memset(&parm, 0, sizeof(parm)); 389 | parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 390 | parm.parm.capture.timeperframe.numerator = n; 391 | parm.parm.capture.timeperframe.denominator = d; 392 | if (ioctl(c->fd, VIDIOC_S_PARM, &parm) < 0) 393 | goto fail; 394 | 395 | memset(&parm, 0, sizeof(parm)); 396 | parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 397 | if (ioctl(c->fd, VIDIOC_G_PARM, &parm) < 0) 398 | goto fail; 399 | 400 | c->parms.format = map_fmt(fmt.fmt.pix.pixelformat); 401 | c->parms.width = fmt.fmt.pix.width; 402 | c->parms.height = fmt.fmt.pix.height; 403 | c->parms.pitch_bytes = fmt.fmt.pix.bytesperline; 404 | c->parms.interval_n = parm.parm.capture.timeperframe.numerator; 405 | c->parms.interval_d = parm.parm.capture.timeperframe.denominator; 406 | 407 | return 0; 408 | 409 | fail: 410 | { 411 | const int e = errno; 412 | 413 | close(c->fd); 414 | c->fd = -1; 415 | errno = e; 416 | } 417 | 418 | return -1; 419 | } 420 | 421 | void camera_close(struct camera *c) 422 | { 423 | camera_off(c); 424 | camera_unmap(c); 425 | 426 | if (c->fd < 0) 427 | return; 428 | 429 | close(c->fd); 430 | c->fd = -1; 431 | } 432 | 433 | int camera_map(struct camera *c, int buf_count) 434 | { 435 | struct v4l2_requestbuffers reqbuf; 436 | int count; 437 | int i; 438 | 439 | if (buf_count > CAMERA_MAX_BUFFERS) 440 | buf_count = CAMERA_MAX_BUFFERS; 441 | 442 | if (buf_count <= 0) { 443 | errno = EINVAL; 444 | return -1; 445 | } 446 | 447 | if (c->fd < 0) { 448 | errno = EBADF; 449 | return -1; 450 | } 451 | 452 | if (c->buf_count) 453 | camera_unmap(c); 454 | 455 | memset(&reqbuf, 0, sizeof(reqbuf)); 456 | reqbuf.count = buf_count; 457 | reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 458 | reqbuf.memory = V4L2_MEMORY_MMAP; 459 | 460 | if (ioctl(c->fd, VIDIOC_REQBUFS, &reqbuf) < 0) 461 | return -1; 462 | 463 | count = reqbuf.count; 464 | if (count > CAMERA_MAX_BUFFERS) 465 | count = CAMERA_MAX_BUFFERS; 466 | 467 | /* Query all buffers */ 468 | for (i = 0; i < count; i++) { 469 | struct v4l2_buffer buf; 470 | struct camera_buffer *cb = &c->buf_desc[i]; 471 | 472 | memset(&buf, 0, sizeof(buf)); 473 | buf.index = i; 474 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 475 | buf.memory = V4L2_MEMORY_MMAP; 476 | if (ioctl(c->fd, VIDIOC_QUERYBUF, &buf) < 0) 477 | return -1; 478 | 479 | cb->offset = buf.m.offset; 480 | cb->size = buf.length; 481 | cb->addr = mmap(NULL, cb->size, PROT_READ, 482 | MAP_SHARED, c->fd, cb->offset); 483 | 484 | if (cb->addr == MAP_FAILED) { 485 | const int save = errno; 486 | 487 | i--; 488 | while (i >= 0) { 489 | cb = &c->buf_desc[i--]; 490 | munmap(cb->addr, cb->size); 491 | } 492 | 493 | errno = save; 494 | return -1; 495 | } 496 | } 497 | 498 | c->buf_count = count; 499 | return 0; 500 | } 501 | 502 | void camera_unmap(struct camera *c) 503 | { 504 | int i; 505 | 506 | for (i = 0; i < c->buf_count; i++) { 507 | struct camera_buffer *cb = &c->buf_desc[i]; 508 | 509 | munmap(cb->addr, cb->size); 510 | } 511 | 512 | c->buf_count = 0; 513 | } 514 | 515 | int camera_on(struct camera *c) 516 | { 517 | int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 518 | 519 | if (c->s_on) 520 | return 0; 521 | 522 | if (c->fd < 0) { 523 | errno = EBADF; 524 | return -1; 525 | } 526 | 527 | if (ioctl(c->fd, VIDIOC_STREAMON, &type) < 0) 528 | return -1; 529 | 530 | c->s_on = 1; 531 | c->s_qc = 0; 532 | c->s_qhead = 0; 533 | return 0; 534 | } 535 | 536 | void camera_off(struct camera *c) 537 | { 538 | int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 539 | 540 | if (!c->s_on) 541 | return; 542 | 543 | ioctl(c->fd, VIDIOC_STREAMOFF, &type); 544 | c->s_on = 0; 545 | } 546 | 547 | int camera_enqueue_all(struct camera *c) 548 | { 549 | while (c->s_qc < c->buf_count) { 550 | struct v4l2_buffer buf; 551 | 552 | memset(&buf, 0, sizeof(buf)); 553 | buf.index = (c->s_qc + c->s_qhead) % c->buf_count; 554 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 555 | buf.memory = V4L2_MEMORY_MMAP; 556 | 557 | if (ioctl(c->fd, VIDIOC_QBUF, &buf) < 0) 558 | return -1; 559 | 560 | c->s_qc++; 561 | } 562 | 563 | return 0; 564 | } 565 | 566 | int camera_dequeue_one(struct camera *c) 567 | { 568 | struct v4l2_buffer buf; 569 | 570 | if (!c->s_qc) { 571 | errno = EINVAL; 572 | return -1; 573 | } 574 | 575 | memset(&buf, 0, sizeof(buf)); 576 | buf.memory = V4L2_MEMORY_MMAP; 577 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 578 | 579 | if (ioctl(c->fd, VIDIOC_DQBUF, &buf) < 0) 580 | return -1; 581 | 582 | c->s_qc--; 583 | if (++c->s_qhead >= c->buf_count) 584 | c->s_qhead = 0; 585 | 586 | return 0; 587 | } 588 | -------------------------------------------------------------------------------- /internal/quirc/demo/camera.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2014 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef CAMERA_H_ 18 | #define CAMERA_H_ 19 | 20 | #include 21 | 22 | #define CAMERA_MAX_BUFFERS 32 23 | 24 | typedef enum { 25 | CAMERA_FORMAT_UNKNOWN = 0, 26 | CAMERA_FORMAT_MJPEG, 27 | CAMERA_FORMAT_YUYV 28 | } camera_format_t; 29 | 30 | struct camera_parms { 31 | camera_format_t format; 32 | int width; 33 | int height; 34 | int pitch_bytes; 35 | int interval_n; 36 | int interval_d; 37 | }; 38 | 39 | struct camera_buffer { 40 | void *addr; 41 | size_t size; 42 | unsigned long offset; 43 | }; 44 | 45 | struct camera { 46 | int fd; 47 | 48 | struct camera_parms parms; 49 | 50 | struct camera_buffer buf_desc[CAMERA_MAX_BUFFERS]; 51 | int buf_count; 52 | 53 | /* Stream state */ 54 | int s_on; 55 | int s_qc; 56 | int s_qhead; 57 | }; 58 | 59 | /* Initialize/destroy a camera. No resources are allocated. */ 60 | void camera_init(struct camera *c); 61 | void camera_destroy(struct camera *c); 62 | 63 | /* Open/close the camera device */ 64 | int camera_open(struct camera *c, const char *path, 65 | int target_w, int target_h, 66 | int tr_n, int tr_d); 67 | void camera_close(struct camera *c); 68 | 69 | static inline int camera_get_fd(const struct camera *c) 70 | { 71 | return c->fd; 72 | } 73 | 74 | static inline const struct camera_parms *camera_get_parms 75 | (const struct camera *c) 76 | { 77 | return &c->parms; 78 | } 79 | 80 | /* Map buffers */ 81 | int camera_map(struct camera *c, int buf_count); 82 | void camera_unmap(struct camera *c); 83 | 84 | static inline int camera_get_buf_count(const struct camera *c) 85 | { 86 | return c->buf_count; 87 | } 88 | 89 | /* Switch streaming on/off */ 90 | int camera_on(struct camera *c); 91 | void camera_off(struct camera *c); 92 | 93 | /* Enqueue/dequeue buffers (count = 0 means enqueue all) */ 94 | int camera_enqueue_all(struct camera *c); 95 | int camera_dequeue_one(struct camera *c); 96 | 97 | /* Fetch the oldest dequeued buffer */ 98 | static inline const struct camera_buffer *camera_get_head 99 | (const struct camera *c) 100 | { 101 | return &c->buf_desc[(c->s_qhead + c->buf_count - 1) % c->buf_count]; 102 | } 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /internal/quirc/demo/convert.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "convert.h" 18 | 19 | #define CHANNEL_CLAMP(dst, tmp, lum, chrom) \ 20 | (tmp) = ((lum) + (chrom)) >> 8; \ 21 | if ((tmp) < 0) \ 22 | (tmp) = 0; \ 23 | if ((tmp) > 255) \ 24 | (tmp) = 255; \ 25 | (dst) = (tmp); 26 | 27 | void yuyv_to_rgb32(const uint8_t *src, int src_pitch, 28 | int w, int h, 29 | uint8_t *dst, int dst_pitch) 30 | { 31 | int y; 32 | 33 | for (y = 0; y < h; y++) { 34 | int x; 35 | const uint8_t *srow = src + y * src_pitch; 36 | uint8_t *drow = dst + y * dst_pitch; 37 | 38 | for (x = 0; x < w; x += 2) { 39 | /* ITU-R colorspace assumed */ 40 | int y0 = (int)srow[0] * 256; 41 | int y1 = (int)srow[2] * 256; 42 | int cr = (int)srow[3] - 128; 43 | int cb = (int)srow[1] - 128; 44 | int r = cr * 359; 45 | int g = -cb * 88 - 128 * cr; 46 | int b = 454 * cb; 47 | int z; 48 | 49 | CHANNEL_CLAMP(drow[0], z, y0, b); 50 | CHANNEL_CLAMP(drow[1], z, y0, g); 51 | CHANNEL_CLAMP(drow[2], z, y0, r); 52 | CHANNEL_CLAMP(drow[4], z, y1, b); 53 | CHANNEL_CLAMP(drow[5], z, y1, g); 54 | CHANNEL_CLAMP(drow[6], z, y1, r); 55 | 56 | srow += 4; 57 | drow += 8; 58 | } 59 | } 60 | } 61 | 62 | void yuyv_to_luma(const uint8_t *src, int src_pitch, 63 | int w, int h, 64 | uint8_t *dst, int dst_pitch) 65 | { 66 | int y; 67 | 68 | for (y = 0; y < h; y++) { 69 | int x; 70 | const uint8_t *srow = src + y * src_pitch; 71 | uint8_t *drow = dst + y * dst_pitch; 72 | 73 | for (x = 0; x < w; x += 2) { 74 | *(drow++) = srow[0]; 75 | *(drow++) = srow[2]; 76 | srow += 4; 77 | } 78 | } 79 | } 80 | 81 | void rgb32_to_luma(const uint8_t *src, int src_pitch, 82 | int w, int h, 83 | uint8_t *dst, int dst_pitch) 84 | { 85 | int y; 86 | 87 | for (y = 0; y < h; y++) { 88 | const uint8_t *rgb32 = src + src_pitch * y; 89 | uint8_t *gray = dst + y * dst_pitch; 90 | int i; 91 | 92 | for (i = 0; i < w; i++) { 93 | /* ITU-R colorspace assumed */ 94 | int r = (int)rgb32[2]; 95 | int g = (int)rgb32[1]; 96 | int b = (int)rgb32[0]; 97 | int sum = r * 59 + g * 150 + b * 29; 98 | 99 | *(gray++) = sum >> 8; 100 | rgb32 += 4; 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /internal/quirc/demo/convert.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef CONVERT_H_ 18 | #define CONVERT_H_ 19 | 20 | #include 21 | 22 | /* Convert 4:2:2 YUYV format to RGB32 format. The source and destination 23 | * frames are expected to be the same size. 24 | */ 25 | void yuyv_to_rgb32(const uint8_t *src, int src_pitch, 26 | int w, int h, 27 | uint8_t *dst, int dst_pitch); 28 | 29 | /* Extract the luma channel from a 4:2:2 YUYV image. */ 30 | void yuyv_to_luma(const uint8_t *src, int src_pitch, 31 | int w, int h, 32 | uint8_t *dst, int dst_pitch); 33 | 34 | /* Extract the luma channel from an RGB32 image. */ 35 | void rgb32_to_luma(const uint8_t *src, int src_pitch, 36 | int w, int h, 37 | uint8_t *dst, int dst_pitch); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /internal/quirc/demo/demo.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "camera.h" 25 | #include "mjpeg.h" 26 | #include "convert.h" 27 | #include "dthash.h" 28 | #include "demoutil.h" 29 | 30 | /* Collected command-line arguments */ 31 | static const char *camera_path = "/dev/video0"; 32 | static int video_width = 640; 33 | static int video_height = 480; 34 | static int want_frame_rate = 0; 35 | static int want_verbose = 0; 36 | static int printer_timeout = 2; 37 | 38 | static void fat_text(SDL_Surface *screen, int x, int y, const char *text) 39 | { 40 | int i, j; 41 | 42 | for (i = -1; i <= 1; i++) 43 | for (j = -1; j <= 1; j++) 44 | stringColor(screen, x + i, y + j, text, 0xffffffff); 45 | stringColor(screen, x, y, text, 0x008000ff); 46 | } 47 | 48 | static void fat_text_cent(SDL_Surface *screen, int x, int y, const char *text) 49 | { 50 | x -= strlen(text) * 4; 51 | 52 | fat_text(screen, x, y, text); 53 | } 54 | 55 | static void draw_qr(SDL_Surface *screen, struct quirc *q, struct dthash *dt) 56 | { 57 | int count = quirc_count(q); 58 | int i; 59 | 60 | for (i = 0; i < count; i++) { 61 | struct quirc_code code; 62 | struct quirc_data data; 63 | quirc_decode_error_t err; 64 | int j; 65 | int xc = 0; 66 | int yc = 0; 67 | char buf[128]; 68 | 69 | quirc_extract(q, i, &code); 70 | 71 | for (j = 0; j < 4; j++) { 72 | struct quirc_point *a = &code.corners[j]; 73 | struct quirc_point *b = &code.corners[(j + 1) % 4]; 74 | 75 | xc += a->x; 76 | yc += a->y; 77 | lineColor(screen, a->x, a->y, b->x, b->y, 0x008000ff); 78 | } 79 | 80 | xc /= 4; 81 | yc /= 4; 82 | 83 | if (want_verbose) { 84 | snprintf(buf, sizeof(buf), "Code size: %d cells", 85 | code.size); 86 | fat_text_cent(screen, xc, yc - 20, buf); 87 | } 88 | 89 | err = quirc_decode(&code, &data); 90 | 91 | if (err) { 92 | if (want_verbose) 93 | fat_text_cent(screen, xc, yc, 94 | quirc_strerror(err)); 95 | } else { 96 | fat_text_cent(screen, xc, yc, (char *)data.payload); 97 | print_data(&data, dt, want_verbose); 98 | 99 | if (want_verbose) { 100 | snprintf(buf, sizeof(buf), 101 | "Ver: %d, ECC: %c, Mask: %d, Type: %d", 102 | data.version, "MLHQ"[data.ecc_level], 103 | data.mask, data.data_type); 104 | fat_text_cent(screen, xc, yc + 20, buf); 105 | } 106 | } 107 | } 108 | } 109 | 110 | static int main_loop(struct camera *cam, SDL_Surface *screen, 111 | struct quirc *q, struct mjpeg_decoder *mj) 112 | { 113 | SDL_Event ev; 114 | time_t last_rate = 0; 115 | int frame_count = 0; 116 | char rate_text[64]; 117 | struct dthash dt; 118 | 119 | rate_text[0] = 0; 120 | dthash_init(&dt, printer_timeout); 121 | 122 | for (;;) { 123 | time_t now = time(NULL); 124 | const struct camera_buffer *head; 125 | const struct camera_parms *parms = camera_get_parms(cam); 126 | 127 | if (camera_dequeue_one(cam) < 0) { 128 | perror("camera_dequeue_one"); 129 | return -1; 130 | } 131 | 132 | head = camera_get_head(cam); 133 | 134 | SDL_LockSurface(screen); 135 | switch (parms->format) { 136 | case CAMERA_FORMAT_MJPEG: 137 | mjpeg_decode_rgb32(mj, head->addr, head->size, 138 | screen->pixels, screen->pitch, 139 | screen->w, screen->h); 140 | break; 141 | 142 | case CAMERA_FORMAT_YUYV: 143 | yuyv_to_rgb32(head->addr, parms->width * 2, 144 | parms->width, parms->height, 145 | screen->pixels, screen->pitch); 146 | break; 147 | 148 | default: 149 | fprintf(stderr, "Unknown frame format\n"); 150 | return -1; 151 | } 152 | 153 | if (camera_enqueue_all(cam) < 0) { 154 | perror("camera_enqueue_all"); 155 | return -1; 156 | } 157 | 158 | rgb32_to_luma(screen->pixels, screen->pitch, 159 | screen->w, screen->h, 160 | quirc_begin(q, NULL, NULL), 161 | screen->w); 162 | quirc_end(q); 163 | SDL_UnlockSurface(screen); 164 | 165 | draw_qr(screen, q, &dt); 166 | if (want_frame_rate) 167 | fat_text(screen, 5, 5, rate_text); 168 | SDL_Flip(screen); 169 | 170 | while (SDL_PollEvent(&ev) > 0) { 171 | if (ev.type == SDL_QUIT) 172 | return 0; 173 | 174 | if (ev.type == SDL_KEYDOWN && ev.key.keysym.sym == 'q') 175 | return 0; 176 | } 177 | 178 | if (now != last_rate) { 179 | snprintf(rate_text, sizeof(rate_text), 180 | "Frame rate: %d fps", frame_count); 181 | frame_count = 0; 182 | last_rate = now; 183 | } 184 | 185 | frame_count++; 186 | } 187 | } 188 | 189 | static int run_demo(void) 190 | { 191 | struct quirc *qr; 192 | struct camera cam; 193 | struct mjpeg_decoder mj; 194 | const struct camera_parms *parms; 195 | SDL_Surface *screen; 196 | 197 | camera_init(&cam); 198 | if (camera_open(&cam, camera_path, video_width, video_height, 199 | 25, 1) < 0) { 200 | perror("camera_open"); 201 | goto fail_qr; 202 | } 203 | 204 | if (camera_map(&cam, 8) < 0) { 205 | perror("camera_map"); 206 | goto fail_qr; 207 | } 208 | 209 | if (camera_on(&cam) < 0) { 210 | perror("camera_on"); 211 | goto fail_qr; 212 | } 213 | 214 | if (camera_enqueue_all(&cam) < 0) { 215 | perror("camera_enqueue_all"); 216 | goto fail_qr; 217 | } 218 | 219 | parms = camera_get_parms(&cam); 220 | 221 | qr = quirc_new(); 222 | if (!qr) { 223 | perror("couldn't allocate QR decoder"); 224 | goto fail_qr; 225 | } 226 | 227 | if (quirc_resize(qr, parms->width, parms->height) < 0) { 228 | perror("couldn't allocate QR buffer"); 229 | goto fail_qr_resize; 230 | } 231 | 232 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { 233 | perror("couldn't init SDL"); 234 | goto fail_sdl_init; 235 | } 236 | 237 | screen = SDL_SetVideoMode(parms->width, parms->height, 32, 238 | SDL_SWSURFACE | SDL_DOUBLEBUF); 239 | if (!screen) { 240 | perror("couldn't init video mode"); 241 | goto fail_video_mode; 242 | } 243 | 244 | mjpeg_init(&mj); 245 | if (main_loop(&cam, screen, qr, &mj) < 0) 246 | goto fail_main_loop; 247 | mjpeg_free(&mj); 248 | 249 | SDL_Quit(); 250 | quirc_destroy(qr); 251 | camera_destroy(&cam); 252 | 253 | return 0; 254 | 255 | fail_main_loop: 256 | mjpeg_free(&mj); 257 | fail_video_mode: 258 | SDL_Quit(); 259 | fail_qr_resize: 260 | fail_sdl_init: 261 | quirc_destroy(qr); 262 | fail_qr: 263 | camera_destroy(&cam); 264 | 265 | return -1; 266 | } 267 | 268 | static void usage(const char *progname) 269 | { 270 | printf("Usage: %s [options]\n\n" 271 | "Valid options are:\n\n" 272 | " -f Show frame rate on screen.\n" 273 | " -v Show extra data for detected codes.\n" 274 | " -d Specify camera device path.\n" 275 | " -s Specify video dimensions.\n" 276 | " -p Set printer timeout (seconds).\n" 277 | " --help Show this information.\n" 278 | " --version Show library version information.\n", 279 | progname); 280 | } 281 | 282 | int main(int argc, char **argv) 283 | { 284 | const static struct option longopts[] = { 285 | {"help", 0, 0, 'H'}, 286 | {"version", 0, 0, 'V'}, 287 | {NULL, 0, 0, 0} 288 | }; 289 | int opt; 290 | 291 | printf("quirc demo\n"); 292 | printf("Copyright (C) 2010-2014 Daniel Beer \n"); 293 | printf("\n"); 294 | 295 | while ((opt = getopt_long(argc, argv, "d:s:fvg:p:", 296 | longopts, NULL)) >= 0) 297 | switch (opt) { 298 | case 'V': 299 | printf("Library version: %s\n", quirc_version()); 300 | return 0; 301 | 302 | case 'H': 303 | usage(argv[0]); 304 | return 0; 305 | 306 | case 'v': 307 | want_verbose = 1; 308 | break; 309 | 310 | case 'f': 311 | want_frame_rate = 1; 312 | break; 313 | 314 | case 's': 315 | if (parse_size(optarg, &video_width, &video_height) < 0) 316 | return -1; 317 | break; 318 | 319 | case 'p': 320 | printer_timeout = atoi(optarg); 321 | break; 322 | 323 | case 'd': 324 | camera_path = optarg; 325 | break; 326 | 327 | case '?': 328 | fprintf(stderr, "Try --help for usage information\n"); 329 | return -1; 330 | } 331 | 332 | return run_demo(); 333 | } 334 | -------------------------------------------------------------------------------- /internal/quirc/demo/demoutil.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #include "demoutil.h" 21 | 22 | void print_data(const struct quirc_data *data, struct dthash *dt, 23 | int want_verbose) 24 | { 25 | if (dthash_seen(dt, data)) 26 | return; 27 | 28 | printf("==> %s\n", data->payload); 29 | 30 | if (want_verbose) 31 | printf(" Version: %d, ECC: %c, Mask: %d, Type: %d\n\n", 32 | data->version, "MLHQ"[data->ecc_level], 33 | data->mask, data->data_type); 34 | } 35 | 36 | int parse_size(const char *text, int *video_width, int *video_height) 37 | { 38 | int state = 0; 39 | int w = 0, h = 0; 40 | int i; 41 | 42 | for (i = 0; text[i]; i++) { 43 | if (text[i] == 'x' || text[i] == 'X') { 44 | if (state == 0) { 45 | state = 1; 46 | } else { 47 | fprintf(stderr, "parse_size: expected WxH\n"); 48 | return -1; 49 | } 50 | } else if (isdigit(text[i])) { 51 | if (state == 0) 52 | w = w * 10 + text[i] - '0'; 53 | else 54 | h = h * 10 + text[i] - '0'; 55 | } else { 56 | fprintf(stderr, "Invalid character in size: %c\n", 57 | text[i]); 58 | return -1; 59 | } 60 | } 61 | 62 | if (w <= 0 || w >= 10000 || h <= 0 || h >= 10000) { 63 | fprintf(stderr, "Invalid size: %dx%d\n", w, h); 64 | return -1; 65 | } 66 | 67 | *video_width = w; 68 | *video_height = h; 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /internal/quirc/demo/demoutil.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DEMOUTIL_H_ 18 | #define DEMOUTIL_H_ 19 | 20 | #include "dthash.h" 21 | #include "quirc.h" 22 | 23 | /* Check if we've seen the given code, and if not, print it on stdout. 24 | * Include version info if requested. 25 | */ 26 | void print_data(const struct quirc_data *data, struct dthash *dt, 27 | int want_verbose); 28 | 29 | /* Parse a string of the form "WxH" and return width and height as 30 | * integers. Returns 0 on success or -1 if a parser error occurs. 31 | */ 32 | int parse_size(const char *text, int *video_width, int *video_height); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /internal/quirc/demo/dthash.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include "dthash.h" 19 | 20 | const static uint32_t crc32_tab[] = { 21 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 22 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 23 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 24 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 25 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 26 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 27 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 28 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 29 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 30 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 31 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 32 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 33 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 34 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 35 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 36 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 37 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 38 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 39 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 40 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 41 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 42 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 43 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 44 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 45 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 46 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 47 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 48 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 49 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 50 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 51 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 52 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 53 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 54 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 55 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 56 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 57 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 58 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 59 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 60 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 61 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 62 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 63 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 64 | }; 65 | 66 | static uint32_t calc_crc(uint32_t crc, const uint8_t *buf, int len) 67 | { 68 | while (len--) { 69 | crc = crc32_tab[(crc ^ *buf) & 0xff] ^ (crc >> 8); 70 | buf++; 71 | } 72 | 73 | return crc; 74 | } 75 | 76 | static uint32_t code_hash(const struct quirc_data *data) 77 | { 78 | uint8_t extra[4] = {data->version, data->ecc_level, 79 | data->mask, data->data_type}; 80 | uint32_t crc = calc_crc(0xffffffff, extra, 4); 81 | 82 | return calc_crc(crc, data->payload, data->payload_len); 83 | } 84 | 85 | static void flush_old(struct dthash *d, time_t now) 86 | { 87 | int i; 88 | 89 | for (i = 0; i < d->count; i++) { 90 | struct dthash_code *c = &d->codes[i]; 91 | 92 | if (c->when + d->timeout <= now) { 93 | if (i + 1 < d->count) 94 | memcpy(c, &d->codes[d->count - 1], sizeof(*c)); 95 | d->count--; 96 | } 97 | } 98 | } 99 | 100 | void dthash_init(struct dthash *d, int timeout) 101 | { 102 | d->count = 0; 103 | d->timeout = timeout; 104 | } 105 | 106 | int dthash_seen(struct dthash *d, const struct quirc_data *data) 107 | { 108 | time_t now = time(NULL); 109 | uint32_t hash = code_hash(data); 110 | struct dthash_code *c; 111 | int i; 112 | 113 | flush_old(d, now); 114 | 115 | /* If the code is already seen, update its timestamp */ 116 | for (i = 0; i < d->count; i++) { 117 | c = &d->codes[i]; 118 | if (c->hash == hash) { 119 | c->when = now; 120 | return 1; 121 | } 122 | } 123 | 124 | /* Otherwise, find a place to put it. If necessary, push the 125 | * oldset code out of the table. 126 | */ 127 | if (d->count + 1 < DTHASH_MAX_CODES) { 128 | c = &d->codes[d->count++]; 129 | } else { 130 | c = &d->codes[0]; 131 | for (i = 1; i < d->count; i++) 132 | if (d->codes[i].when < c->when) 133 | c = &d->codes[i]; 134 | } 135 | 136 | c->hash = hash; 137 | c->when = now; 138 | return 0; 139 | } 140 | -------------------------------------------------------------------------------- /internal/quirc/demo/dthash.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DTHASH_H_ 18 | #define DTHASH_H_ 19 | 20 | #include 21 | #include 22 | #include "quirc.h" 23 | 24 | /* Detector hash. 25 | * 26 | * This structure keeps track of codes that have been seen within the 27 | * last N seconds, and allows us to print out codes at a reasonable 28 | * rate as we see them. 29 | */ 30 | #define DTHASH_MAX_CODES 32 31 | 32 | struct dthash_code { 33 | uint32_t hash; 34 | time_t when; 35 | }; 36 | 37 | struct dthash { 38 | struct dthash_code codes[DTHASH_MAX_CODES]; 39 | int count; 40 | int timeout; 41 | }; 42 | 43 | /* Initialise a detector hash with the given timeout. */ 44 | void dthash_init(struct dthash *d, int timeout); 45 | 46 | /* When a code is discovered, this function should be called to see if 47 | * it should be printed. The hash will record having seen the code, and 48 | * return non-zero if it's the first time we've seen it within the 49 | * configured timeout period. 50 | */ 51 | int dthash_seen(struct dthash *d, const struct quirc_data *data); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /internal/quirc/demo/mjpeg.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "mjpeg.h" 23 | 24 | struct huffman_table { 25 | uint8_t bits[17]; 26 | uint8_t huffval[256]; 27 | }; 28 | 29 | static const struct huffman_table dc_lum = { 30 | .bits = { 31 | 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 32 | 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0x00 34 | }, 35 | .huffval = { 36 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 37 | 0x08, 0x09, 0x0a, 0x0b 38 | } 39 | }; 40 | 41 | static const struct huffman_table ac_lum = { 42 | .bits = { 43 | 0x00, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 44 | 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 45 | 0x7d 46 | }, 47 | .huffval = { 48 | 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 49 | 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 50 | 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 51 | 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 52 | 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 53 | 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 54 | 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 55 | 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 56 | 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 57 | 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 58 | 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 59 | 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 60 | 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 61 | 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 62 | 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 63 | 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 64 | 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 65 | 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 66 | 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 67 | 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 68 | 0xf9, 0xfa 69 | } 70 | }; 71 | 72 | static const struct huffman_table dc_chroma = { 73 | .bits = { 74 | 0x00, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 75 | 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 76 | 0x00 77 | }, 78 | .huffval = { 79 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 80 | 0x08, 0x09, 0x0a, 0x0b 81 | } 82 | }; 83 | 84 | static const struct huffman_table ac_chroma = { 85 | .bits = { 86 | 0x00, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 87 | 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 88 | 0x77 89 | }, 90 | .huffval = { 91 | 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 92 | 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 93 | 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 94 | 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 95 | 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 96 | 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 97 | 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 98 | 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 99 | 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 100 | 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 101 | 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 102 | 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 103 | 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 104 | 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 105 | 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 106 | 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 107 | 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 108 | 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 109 | 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 110 | 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 111 | 0xf9, 0xfa 112 | } 113 | }; 114 | 115 | static void init_source(j_decompress_ptr cinfo) 116 | { 117 | } 118 | 119 | static boolean fill_input_buffer(j_decompress_ptr cinfo) 120 | { 121 | static const uint8_t eoi_marker[] = {0xff, 0xd9}; 122 | 123 | cinfo->src->next_input_byte = eoi_marker; 124 | cinfo->src->bytes_in_buffer = 2; 125 | 126 | return TRUE; 127 | } 128 | 129 | static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) 130 | { 131 | if (num_bytes < 0) 132 | return; 133 | if (num_bytes > cinfo->src->bytes_in_buffer) 134 | num_bytes = cinfo->src->bytes_in_buffer; 135 | 136 | cinfo->src->bytes_in_buffer -= num_bytes; 137 | cinfo->src->next_input_byte += num_bytes; 138 | } 139 | 140 | static void term_source(j_decompress_ptr cinfo) 141 | { 142 | } 143 | 144 | struct my_jpeg_error { 145 | struct jpeg_error_mgr base; 146 | jmp_buf env; 147 | }; 148 | 149 | static void my_output_message(struct jpeg_common_struct *com) 150 | { 151 | struct mjpeg_decoder *mj = (struct mjpeg_decoder *)com->err; 152 | char buf[JMSG_LENGTH_MAX]; 153 | 154 | mj->err.format_message(com, buf); 155 | fprintf(stderr, "MJPEG error: %s\n", buf); 156 | } 157 | 158 | static void my_error_exit(struct jpeg_common_struct *com) 159 | { 160 | struct mjpeg_decoder *mj = (struct mjpeg_decoder *)com->err; 161 | 162 | my_output_message(com); 163 | longjmp(mj->env, 0); 164 | } 165 | 166 | static void setup_table(struct jpeg_decompress_struct *jpeg, 167 | JHUFF_TBL **tbl_ptr, const struct huffman_table *tab) 168 | { 169 | assert (*tbl_ptr == NULL); 170 | 171 | *tbl_ptr = jpeg_alloc_huff_table((j_common_ptr)jpeg); 172 | memcpy((*tbl_ptr)->bits, tab->bits, 17); 173 | memcpy((*tbl_ptr)->huffval, tab->huffval, 256); 174 | } 175 | 176 | void mjpeg_init(struct mjpeg_decoder *mj) 177 | { 178 | memset(mj, 0, sizeof(mj)); 179 | 180 | /* Set up error management */ 181 | jpeg_std_error(&mj->err); 182 | mj->err.error_exit = my_error_exit; 183 | mj->err.output_message = my_output_message; 184 | 185 | mj->src.init_source = init_source; 186 | mj->src.fill_input_buffer = fill_input_buffer; 187 | mj->src.skip_input_data = skip_input_data; 188 | mj->src.resync_to_restart = jpeg_resync_to_restart; 189 | mj->src.term_source = term_source; 190 | 191 | jpeg_create_decompress(&mj->dinfo); 192 | mj->dinfo.src = &mj->src; 193 | mj->dinfo.err = &mj->err; 194 | 195 | setup_table(&mj->dinfo, &mj->dinfo.dc_huff_tbl_ptrs[0], &dc_lum); 196 | setup_table(&mj->dinfo, &mj->dinfo.ac_huff_tbl_ptrs[0], &ac_lum); 197 | setup_table(&mj->dinfo, &mj->dinfo.dc_huff_tbl_ptrs[1], &dc_chroma); 198 | setup_table(&mj->dinfo, &mj->dinfo.ac_huff_tbl_ptrs[1], &ac_chroma); 199 | } 200 | 201 | void mjpeg_free(struct mjpeg_decoder *mj) 202 | { 203 | jpeg_destroy_decompress(&mj->dinfo); 204 | } 205 | 206 | int mjpeg_decode_rgb32(struct mjpeg_decoder *mj, 207 | const uint8_t *data, int datalen, 208 | uint8_t *out, int pitch, int max_w, int max_h) 209 | { 210 | if (setjmp(mj->env)) 211 | return -1; 212 | 213 | mj->dinfo.src->bytes_in_buffer = datalen; 214 | mj->dinfo.src->next_input_byte = data; 215 | 216 | jpeg_read_header(&mj->dinfo, TRUE); 217 | mj->dinfo.output_components = 3; 218 | mj->dinfo.out_color_space = JCS_RGB; 219 | jpeg_start_decompress(&mj->dinfo); 220 | 221 | if (mj->dinfo.image_height > max_h || 222 | mj->dinfo.image_width > max_w) { 223 | fprintf(stderr, "MJPEG: frame too big\n"); 224 | return -1; 225 | } 226 | 227 | while (mj->dinfo.output_scanline < mj->dinfo.image_height) { 228 | uint8_t rgb[mj->dinfo.image_width * 3]; 229 | uint8_t *output = rgb; 230 | uint8_t *scr = out + pitch * mj->dinfo.output_scanline; 231 | int i; 232 | 233 | jpeg_read_scanlines(&mj->dinfo, &output, 1); 234 | for (i = 0; i < mj->dinfo.image_width; i++) { 235 | scr[0] = output[2]; 236 | scr[1] = output[1]; 237 | scr[2] = output[0]; 238 | scr += 4; 239 | output += 3; 240 | } 241 | } 242 | 243 | jpeg_finish_decompress(&mj->dinfo); 244 | 245 | return 0; 246 | } 247 | 248 | int mjpeg_decode_gray(struct mjpeg_decoder *mj, 249 | const uint8_t *data, int datalen, 250 | uint8_t *out, int pitch, int max_w, int max_h) 251 | { 252 | if (setjmp(mj->env)) 253 | return -1; 254 | 255 | mj->dinfo.src->bytes_in_buffer = datalen; 256 | mj->dinfo.src->next_input_byte = data; 257 | 258 | jpeg_read_header(&mj->dinfo, TRUE); 259 | mj->dinfo.output_components = 1; 260 | mj->dinfo.out_color_space = JCS_GRAYSCALE; 261 | jpeg_start_decompress(&mj->dinfo); 262 | 263 | if (mj->dinfo.image_height > max_h || 264 | mj->dinfo.image_width > max_w) { 265 | fprintf(stderr, "MJPEG: frame too big\n"); 266 | return -1; 267 | } 268 | 269 | while (mj->dinfo.output_scanline < mj->dinfo.image_height) { 270 | uint8_t *scr = out + pitch * mj->dinfo.output_scanline; 271 | 272 | jpeg_read_scanlines(&mj->dinfo, &scr, 1); 273 | } 274 | 275 | jpeg_finish_decompress(&mj->dinfo); 276 | 277 | return 0; 278 | } 279 | -------------------------------------------------------------------------------- /internal/quirc/demo/mjpeg.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef MJPEG_H_ 18 | #define MJPEG_H_ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | struct mjpeg_decoder { 26 | /* The error manager must be the first item in this struct */ 27 | struct jpeg_error_mgr err; 28 | struct jpeg_decompress_struct dinfo; 29 | struct jpeg_source_mgr src; 30 | jmp_buf env; 31 | }; 32 | 33 | /* Construct an MJPEG decoder. */ 34 | void mjpeg_init(struct mjpeg_decoder *mj); 35 | 36 | /* Free any memory allocated while decoding MJPEG frames. */ 37 | void mjpeg_free(struct mjpeg_decoder *mj); 38 | 39 | /* Decode a single MJPEG image to the buffer given, in RGB format. 40 | * Returns 0 on success, -1 if an error occurs (bad data, or image too 41 | * big for buffer). 42 | */ 43 | int mjpeg_decode_rgb32(struct mjpeg_decoder *mj, 44 | const uint8_t *data, int datalen, 45 | uint8_t *out, int pitch, int max_w, int max_h); 46 | 47 | /* Decode a single MJPEG image to the buffer given in 8-bit grayscale. 48 | * Returns 0 on success, -1 if an error occurs. 49 | */ 50 | int mjpeg_decode_gray(struct mjpeg_decoder *mj, 51 | const uint8_t *data, int datalen, 52 | uint8_t *out, int pitch, int max_w, int max_h); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /internal/quirc/demo/scanner.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "camera.h" 25 | #include "mjpeg.h" 26 | #include "convert.h" 27 | #include "dthash.h" 28 | #include "demoutil.h" 29 | 30 | /* Collected command-line arguments */ 31 | static const char *camera_path = "/dev/video0"; 32 | static int video_width = 640; 33 | static int video_height = 480; 34 | static int want_verbose = 0; 35 | static int printer_timeout = 2; 36 | 37 | static int main_loop(struct camera *cam, 38 | struct quirc *q, struct mjpeg_decoder *mj) 39 | { 40 | struct dthash dt; 41 | 42 | dthash_init(&dt, printer_timeout); 43 | 44 | for (;;) { 45 | int w, h; 46 | int i, count; 47 | uint8_t *buf = quirc_begin(q, &w, &h); 48 | const struct camera_buffer *head; 49 | const struct camera_parms *parms = camera_get_parms(cam); 50 | 51 | if (camera_dequeue_one(cam) < 0) { 52 | perror("camera_dequeue_one"); 53 | return -1; 54 | } 55 | 56 | head = camera_get_head(cam); 57 | 58 | switch (parms->format) { 59 | case CAMERA_FORMAT_MJPEG: 60 | mjpeg_decode_gray(mj, head->addr, head->size, 61 | buf, w, w, h); 62 | break; 63 | 64 | case CAMERA_FORMAT_YUYV: 65 | yuyv_to_luma(head->addr, w * 2, w, h, buf, w); 66 | break; 67 | 68 | default: 69 | fprintf(stderr, "Unknown frame format\n"); 70 | return -1; 71 | } 72 | 73 | if (camera_enqueue_all(cam) < 0) { 74 | perror("camera_enqueue_all"); 75 | return -1; 76 | } 77 | 78 | quirc_end(q); 79 | 80 | count = quirc_count(q); 81 | for (i = 0; i < count; i++) { 82 | struct quirc_code code; 83 | struct quirc_data data; 84 | 85 | quirc_extract(q, i, &code); 86 | if (!quirc_decode(&code, &data)) 87 | print_data(&data, &dt, want_verbose); 88 | } 89 | } 90 | } 91 | 92 | static int run_scanner(void) 93 | { 94 | struct quirc *qr; 95 | struct camera cam; 96 | struct mjpeg_decoder mj; 97 | const struct camera_parms *parms; 98 | 99 | camera_init(&cam); 100 | if (camera_open(&cam, camera_path, video_width, video_height, 101 | 25, 1) < 0) { 102 | perror("camera_open"); 103 | goto fail_qr; 104 | } 105 | 106 | if (camera_map(&cam, 8) < 0) { 107 | perror("camera_map"); 108 | goto fail_qr; 109 | } 110 | 111 | if (camera_on(&cam) < 0) { 112 | perror("camera_on"); 113 | goto fail_qr; 114 | } 115 | 116 | if (camera_enqueue_all(&cam) < 0) { 117 | perror("camera_enqueue_all"); 118 | goto fail_qr; 119 | } 120 | 121 | parms = camera_get_parms(&cam); 122 | 123 | qr = quirc_new(); 124 | if (!qr) { 125 | perror("couldn't allocate QR decoder"); 126 | goto fail_qr; 127 | } 128 | 129 | if (quirc_resize(qr, parms->width, parms->height) < 0) { 130 | perror("couldn't allocate QR buffer"); 131 | goto fail_qr_resize; 132 | } 133 | 134 | mjpeg_init(&mj); 135 | if (main_loop(&cam, qr, &mj) < 0) 136 | goto fail_main_loop; 137 | mjpeg_free(&mj); 138 | 139 | quirc_destroy(qr); 140 | camera_destroy(&cam); 141 | 142 | return 0; 143 | 144 | fail_main_loop: 145 | mjpeg_free(&mj); 146 | fail_qr_resize: 147 | quirc_destroy(qr); 148 | fail_qr: 149 | camera_destroy(&cam); 150 | 151 | return -1; 152 | } 153 | 154 | static void usage(const char *progname) 155 | { 156 | printf("Usage: %s [options]\n\n" 157 | "Valid options are:\n\n" 158 | " -v Show extra data for detected codes.\n" 159 | " -d Specify camera device path.\n" 160 | " -s Specify video dimensions.\n" 161 | " -p Set printer timeout (seconds).\n" 162 | " --help Show this information.\n" 163 | " --version Show library version information.\n", 164 | progname); 165 | } 166 | 167 | int main(int argc, char **argv) 168 | { 169 | const static struct option longopts[] = { 170 | {"help", 0, 0, 'H'}, 171 | {"version", 0, 0, 'V'}, 172 | {NULL, 0, 0, 0} 173 | }; 174 | int opt; 175 | 176 | printf("quirc scanner demo\n"); 177 | printf("Copyright (C) 2010-2012 Daniel Beer \n"); 178 | printf("\n"); 179 | 180 | while ((opt = getopt_long(argc, argv, "d:s:vg:p:", 181 | longopts, NULL)) >= 0) 182 | switch (opt) { 183 | case 'V': 184 | printf("Library version: %s\n", quirc_version()); 185 | return 0; 186 | 187 | case 'H': 188 | usage(argv[0]); 189 | return 0; 190 | 191 | case 'v': 192 | want_verbose = 1; 193 | break; 194 | 195 | case 's': 196 | if (parse_size(optarg, &video_width, &video_height) < 0) 197 | return -1; 198 | break; 199 | 200 | case 'p': 201 | printer_timeout = atoi(optarg); 202 | break; 203 | 204 | case 'd': 205 | camera_path = optarg; 206 | break; 207 | 208 | case '?': 209 | fprintf(stderr, "Try --help for usage information\n"); 210 | return -1; 211 | } 212 | 213 | return run_scanner(); 214 | } 215 | -------------------------------------------------------------------------------- /internal/quirc/lib/decode.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "quirc_internal.h" 18 | 19 | #include 20 | #include 21 | 22 | #define MAX_POLY 64 23 | 24 | /************************************************************************ 25 | * Galois fields 26 | */ 27 | 28 | struct galois_field { 29 | int p; 30 | const uint8_t *log; 31 | const uint8_t *exp; 32 | }; 33 | 34 | static const uint8_t gf16_exp[16] = { 35 | 0x01, 0x02, 0x04, 0x08, 0x03, 0x06, 0x0c, 0x0b, 36 | 0x05, 0x0a, 0x07, 0x0e, 0x0f, 0x0d, 0x09, 0x01 37 | }; 38 | 39 | static const uint8_t gf16_log[16] = { 40 | 0x00, 0x0f, 0x01, 0x04, 0x02, 0x08, 0x05, 0x0a, 41 | 0x03, 0x0e, 0x09, 0x07, 0x06, 0x0d, 0x0b, 0x0c 42 | }; 43 | 44 | static const struct galois_field gf16 = { 45 | .p = 15, 46 | .log = gf16_log, 47 | .exp = gf16_exp 48 | }; 49 | 50 | static const uint8_t gf256_exp[256] = { 51 | 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 52 | 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 53 | 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 54 | 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 55 | 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 56 | 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 57 | 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 58 | 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 59 | 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 60 | 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 61 | 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 62 | 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, 63 | 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 64 | 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 65 | 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 66 | 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 67 | 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 68 | 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, 69 | 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 70 | 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 71 | 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 72 | 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 73 | 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 74 | 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, 75 | 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 76 | 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 77 | 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 78 | 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, 79 | 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 80 | 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, 81 | 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 82 | 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x01 83 | }; 84 | 85 | static const uint8_t gf256_log[256] = { 86 | 0x00, 0xff, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 87 | 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 88 | 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 89 | 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, 90 | 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 91 | 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 92 | 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 93 | 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 94 | 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 95 | 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 96 | 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 97 | 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, 98 | 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 99 | 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, 100 | 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 101 | 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 102 | 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 103 | 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, 104 | 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 105 | 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 106 | 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 107 | 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 108 | 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 109 | 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, 110 | 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 111 | 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, 112 | 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 113 | 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 114 | 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 115 | 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, 116 | 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 117 | 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf 118 | }; 119 | 120 | const static struct galois_field gf256 = { 121 | .p = 255, 122 | .log = gf256_log, 123 | .exp = gf256_exp 124 | }; 125 | 126 | /************************************************************************ 127 | * Polynomial operations 128 | */ 129 | 130 | static void poly_mult(uint8_t *r, const uint8_t *a, const uint8_t *b, 131 | const struct galois_field *gf) 132 | { 133 | int i; 134 | 135 | memset(r, 0, MAX_POLY); 136 | 137 | for (i = 0; i < MAX_POLY; i++) { 138 | int j; 139 | 140 | for (j = 0; j + i < MAX_POLY; j++) { 141 | uint8_t ca = a[i]; 142 | uint8_t cb = b[j]; 143 | 144 | if (!(ca && cb)) 145 | continue; 146 | 147 | r[i + j] ^= gf->exp[(gf->log[ca] + 148 | gf->log[cb]) % 149 | gf->p]; 150 | } 151 | } 152 | } 153 | 154 | static void poly_add(uint8_t *dst, const uint8_t *src, uint8_t c, 155 | int shift, const struct galois_field *gf) 156 | { 157 | int i; 158 | int log_c = gf->log[c]; 159 | 160 | if (!c) 161 | return; 162 | 163 | for (i = 0; i < MAX_POLY; i++) { 164 | int p = i + shift; 165 | uint8_t v = src[i]; 166 | 167 | if (p < 0 || p >= MAX_POLY) 168 | continue; 169 | if (!v) 170 | continue; 171 | 172 | dst[p] ^= gf->exp[(gf->log[v] + log_c) % gf->p]; 173 | } 174 | } 175 | 176 | static uint8_t poly_eval(const uint8_t *s, uint8_t x, 177 | const struct galois_field *gf) 178 | { 179 | int i; 180 | uint8_t sum = 0; 181 | uint8_t log_x = gf->log[x]; 182 | 183 | if (!x) 184 | return s[0]; 185 | 186 | for (i = 0; i < MAX_POLY; i++) { 187 | uint8_t c = s[i]; 188 | 189 | if (!c) 190 | continue; 191 | 192 | sum ^= gf->exp[(gf->log[c] + log_x * i) % gf->p]; 193 | } 194 | 195 | return sum; 196 | } 197 | 198 | /************************************************************************ 199 | * Berlekamp-Massey algorithm for finding error locator polynomials. 200 | */ 201 | 202 | static void berlekamp_massey(const uint8_t *s, int N, 203 | const struct galois_field *gf, 204 | uint8_t *sigma) 205 | { 206 | uint8_t C[MAX_POLY]; 207 | uint8_t B[MAX_POLY]; 208 | int L = 0; 209 | int m = 1; 210 | uint8_t b = 1; 211 | int n; 212 | 213 | memset(B, 0, sizeof(B)); 214 | memset(C, 0, sizeof(C)); 215 | B[0] = 1; 216 | C[0] = 1; 217 | 218 | for (n = 0; n < N; n++) { 219 | uint8_t d = s[n]; 220 | uint8_t mult; 221 | int i; 222 | 223 | for (i = 1; i <= L; i++) { 224 | if (!(C[i] && s[n - i])) 225 | continue; 226 | 227 | d ^= gf->exp[(gf->log[C[i]] + 228 | gf->log[s[n - i]]) % 229 | gf->p]; 230 | } 231 | 232 | mult = gf->exp[(gf->p - gf->log[b] + gf->log[d]) % gf->p]; 233 | 234 | if (!d) { 235 | m++; 236 | } else if (L * 2 <= n) { 237 | uint8_t T[MAX_POLY]; 238 | 239 | memcpy(T, C, sizeof(T)); 240 | poly_add(C, B, mult, m, gf); 241 | memcpy(B, T, sizeof(B)); 242 | L = n + 1 - L; 243 | b = d; 244 | m = 1; 245 | } else { 246 | poly_add(C, B, mult, m, gf); 247 | m++; 248 | } 249 | } 250 | 251 | memcpy(sigma, C, MAX_POLY); 252 | } 253 | 254 | /************************************************************************ 255 | * Code stream error correction 256 | * 257 | * Generator polynomial for GF(2^8) is x^8 + x^4 + x^3 + x^2 + 1 258 | */ 259 | 260 | static int block_syndromes(const uint8_t *data, int bs, int npar, uint8_t *s) 261 | { 262 | int nonzero = 0; 263 | int i; 264 | 265 | memset(s, 0, MAX_POLY); 266 | 267 | for (i = 0; i < npar; i++) { 268 | int j; 269 | 270 | for (j = 0; j < bs; j++) { 271 | uint8_t c = data[bs - j - 1]; 272 | 273 | if (!c) 274 | continue; 275 | 276 | s[i] ^= gf256_exp[((int)gf256_log[c] + 277 | (i + 1) * j) % 255]; 278 | } 279 | 280 | if (s[i]) 281 | nonzero = 1; 282 | } 283 | 284 | return nonzero; 285 | } 286 | 287 | static quirc_decode_error_t correct_block(uint8_t *data, const struct quirc_rs_params *ecc) 288 | { 289 | int npar = ecc->ce; 290 | uint8_t s[MAX_POLY]; 291 | uint8_t sigma[MAX_POLY]; 292 | uint8_t sigma_deriv[MAX_POLY]; 293 | uint8_t omega[MAX_POLY]; 294 | int i; 295 | 296 | /* Compute syndrome vector */ 297 | if (!block_syndromes(data, ecc->bs, npar, s)) 298 | return QUIRC_SUCCESS; 299 | 300 | berlekamp_massey(s, npar, &gf256, sigma); 301 | 302 | /* Compute derivative of sigma */ 303 | memset(sigma_deriv, 0, MAX_POLY); 304 | for (i = 0; i + 1 < MAX_POLY; i += 2) 305 | sigma_deriv[i] = sigma[i + 1]; 306 | 307 | /* Compute error evaluator polynomial */ 308 | poly_mult(omega, sigma, s, &gf256); 309 | memset(omega + npar, 0, MAX_POLY - npar); 310 | 311 | /* Find error locations and magnitudes */ 312 | for (i = 0; i < ecc->bs; i++) { 313 | uint8_t xinv = gf256_exp[255 - i]; 314 | 315 | if (!poly_eval(sigma, xinv, &gf256)) { 316 | uint8_t sd_x = poly_eval(sigma_deriv, xinv, &gf256); 317 | uint8_t omega_x = poly_eval(omega, xinv, &gf256); 318 | uint8_t error = gf256_exp[(255 - gf256_log[sd_x] + 319 | gf256_log[omega_x]) % 255]; 320 | 321 | data[ecc->bs - i - 1] ^= error; 322 | } 323 | } 324 | 325 | if (block_syndromes(data, ecc->bs, npar, s)) 326 | return QUIRC_ERROR_DATA_ECC; 327 | 328 | return QUIRC_SUCCESS; 329 | } 330 | 331 | /************************************************************************ 332 | * Format value error correction 333 | * 334 | * Generator polynomial for GF(2^4) is x^4 + x + 1 335 | */ 336 | 337 | #define FORMAT_MAX_ERROR 3 338 | #define FORMAT_SYNDROMES (FORMAT_MAX_ERROR * 2) 339 | #define FORMAT_BITS 15 340 | 341 | static int format_syndromes(uint16_t u, uint8_t *s) 342 | { 343 | int i; 344 | int nonzero = 0; 345 | 346 | memset(s, 0, MAX_POLY); 347 | 348 | for (i = 0; i < FORMAT_SYNDROMES; i++) { 349 | int j; 350 | 351 | s[i] = 0; 352 | for (j = 0; j < FORMAT_BITS; j++) 353 | if (u & (1 << j)) 354 | s[i] ^= gf16_exp[((i + 1) * j) % 15]; 355 | 356 | if (s[i]) 357 | nonzero = 1; 358 | } 359 | 360 | return nonzero; 361 | } 362 | 363 | static quirc_decode_error_t correct_format(uint16_t *f_ret) 364 | { 365 | uint16_t u = *f_ret; 366 | int i; 367 | uint8_t s[MAX_POLY]; 368 | uint8_t sigma[MAX_POLY]; 369 | 370 | /* Evaluate U (received codeword) at each of alpha_1 .. alpha_6 371 | * to get S_1 .. S_6 (but we index them from 0). 372 | */ 373 | if (!format_syndromes(u, s)) 374 | return QUIRC_SUCCESS; 375 | 376 | berlekamp_massey(s, FORMAT_SYNDROMES, &gf16, sigma); 377 | 378 | /* Now, find the roots of the polynomial */ 379 | for (i = 0; i < 15; i++) 380 | if (!poly_eval(sigma, gf16_exp[15 - i], &gf16)) 381 | u ^= (1 << i); 382 | 383 | if (format_syndromes(u, s)) 384 | return QUIRC_ERROR_FORMAT_ECC; 385 | 386 | *f_ret = u; 387 | return QUIRC_SUCCESS; 388 | } 389 | 390 | /************************************************************************ 391 | * Decoder algorithm 392 | */ 393 | 394 | struct datastream { 395 | uint8_t raw[QUIRC_MAX_PAYLOAD]; 396 | int data_bits; 397 | int ptr; 398 | 399 | uint8_t data[QUIRC_MAX_PAYLOAD]; 400 | }; 401 | 402 | static inline int grid_bit(const struct quirc_code *code, int x, int y) 403 | { 404 | int p = y * code->size + x; 405 | 406 | return (code->cell_bitmap[p >> 3] >> (p & 7)) & 1; 407 | } 408 | 409 | static quirc_decode_error_t read_format(const struct quirc_code *code, 410 | struct quirc_data *data, int which) 411 | { 412 | int i; 413 | uint16_t format = 0; 414 | uint16_t fdata; 415 | quirc_decode_error_t err; 416 | 417 | if (which) { 418 | for (i = 0; i < 7; i++) 419 | format = (format << 1) | 420 | grid_bit(code, 8, code->size - 1 - i); 421 | for (i = 0; i < 8; i++) 422 | format = (format << 1) | 423 | grid_bit(code, code->size - 8 + i, 8); 424 | } else { 425 | static const int xs[15] = { 426 | 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 4, 3, 2, 1, 0 427 | }; 428 | static const int ys[15] = { 429 | 0, 1, 2, 3, 4, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8 430 | }; 431 | 432 | for (i = 14; i >= 0; i--) 433 | format = (format << 1) | grid_bit(code, xs[i], ys[i]); 434 | } 435 | 436 | format ^= 0x5412; 437 | 438 | err = correct_format(&format); 439 | if (err) 440 | return err; 441 | 442 | fdata = format >> 10; 443 | data->ecc_level = fdata >> 3; 444 | data->mask = fdata & 7; 445 | 446 | return QUIRC_SUCCESS; 447 | } 448 | 449 | static int mask_bit(int mask, int i, int j) 450 | { 451 | switch (mask) { 452 | case 0: return !((i + j) % 2); 453 | case 1: return !(i % 2); 454 | case 2: return !(j % 3); 455 | case 3: return !((i + j) % 3); 456 | case 4: return !(((i / 2) + (j / 3)) % 2); 457 | case 5: return !((i * j) % 2 + (i * j) % 3); 458 | case 6: return !(((i * j) % 2 + (i * j) % 3) % 2); 459 | case 7: return !(((i * j) % 3 + (i + j) % 2) % 2); 460 | } 461 | 462 | return 0; 463 | } 464 | 465 | static int reserved_cell(int version, int i, int j) 466 | { 467 | const struct quirc_version_info *ver = &quirc_version_db[version]; 468 | int size = version * 4 + 17; 469 | int ai = -1, aj = -1, a; 470 | 471 | /* Finder + format: top left */ 472 | if (i < 9 && j < 9) 473 | return 1; 474 | 475 | /* Finder + format: bottom left */ 476 | if (i + 8 >= size && j < 9) 477 | return 1; 478 | 479 | /* Finder + format: top right */ 480 | if (i < 9 && j + 8 >= size) 481 | return 1; 482 | 483 | /* Exclude timing patterns */ 484 | if (i == 6 || j == 6) 485 | return 1; 486 | 487 | /* Exclude version info, if it exists. Version info sits adjacent to 488 | * the top-right and bottom-left finders in three rows, bounded by 489 | * the timing pattern. 490 | */ 491 | if (version >= 7) { 492 | if (i < 6 && j + 11 >= size) 493 | return 1; 494 | if (i + 11 >= size && j < 6) 495 | return 1; 496 | } 497 | 498 | /* Exclude alignment patterns */ 499 | for (a = 0; a < QUIRC_MAX_ALIGNMENT && ver->apat[a]; a++) { 500 | int p = ver->apat[a]; 501 | 502 | if (abs(p - i) < 3) 503 | ai = a; 504 | if (abs(p - j) < 3) 505 | aj = a; 506 | } 507 | 508 | if (ai >= 0 && aj >= 0) { 509 | a--; 510 | if (ai > 0 && ai < a) 511 | return 1; 512 | if (aj > 0 && aj < a) 513 | return 1; 514 | if (aj == a && ai == a) 515 | return 1; 516 | } 517 | 518 | return 0; 519 | } 520 | 521 | static void read_bit(const struct quirc_code *code, 522 | struct quirc_data *data, 523 | struct datastream *ds, int i, int j) 524 | { 525 | int bitpos = ds->data_bits & 7; 526 | int bytepos = ds->data_bits >> 3; 527 | int v = grid_bit(code, j, i); 528 | 529 | if (mask_bit(data->mask, i, j)) 530 | v ^= 1; 531 | 532 | if (v) 533 | ds->raw[bytepos] |= (0x80 >> bitpos); 534 | 535 | ds->data_bits++; 536 | } 537 | 538 | static void read_data(const struct quirc_code *code, 539 | struct quirc_data *data, 540 | struct datastream *ds) 541 | { 542 | int y = code->size - 1; 543 | int x = code->size - 1; 544 | int dir = -1; 545 | 546 | while (x > 0) { 547 | if (x == 6) 548 | x--; 549 | 550 | if (!reserved_cell(data->version, y, x)) 551 | read_bit(code, data, ds, y, x); 552 | 553 | if (!reserved_cell(data->version, y, x - 1)) 554 | read_bit(code, data, ds, y, x - 1); 555 | 556 | y += dir; 557 | if (y < 0 || y >= code->size) { 558 | dir = -dir; 559 | x -= 2; 560 | y += dir; 561 | } 562 | } 563 | } 564 | 565 | static quirc_decode_error_t codestream_ecc(struct quirc_data *data, 566 | struct datastream *ds) 567 | { 568 | const struct quirc_version_info *ver = 569 | &quirc_version_db[data->version]; 570 | const struct quirc_rs_params *sb_ecc = &ver->ecc[data->ecc_level]; 571 | struct quirc_rs_params lb_ecc; 572 | int bc = ver->data_bytes / sb_ecc->bs; 573 | int dst_offset = 0; 574 | int lb_count = ver->data_bytes - bc * sb_ecc->bs; 575 | int small_dw_total = bc * sb_ecc->dw; 576 | int i; 577 | 578 | memcpy(&lb_ecc, sb_ecc, sizeof(lb_ecc)); 579 | lb_ecc.dw++; 580 | lb_ecc.bs++; 581 | 582 | for (i = 0; i < bc; i++) { 583 | uint8_t *dst = ds->data + dst_offset; 584 | const struct quirc_rs_params *ecc = sb_ecc; 585 | quirc_decode_error_t err; 586 | int j = 0; 587 | int k; 588 | 589 | for (k = 0; k < sb_ecc->dw; k++) 590 | dst[j++] = ds->raw[k * bc + i]; 591 | 592 | if (i + lb_count >= bc) { 593 | dst[j++] = ds->raw[small_dw_total + i - lb_count]; 594 | ecc = &lb_ecc; 595 | } 596 | 597 | for (k = 0; k < sb_ecc->bs - sb_ecc->dw; k++) 598 | dst[j++] = ds->raw[small_dw_total + lb_count + i + 599 | k * bc]; 600 | 601 | err = correct_block(dst, ecc); 602 | if (err) 603 | return err; 604 | 605 | dst_offset += ecc->dw; 606 | } 607 | 608 | ds->data_bits = dst_offset * 8; 609 | 610 | return QUIRC_SUCCESS; 611 | } 612 | 613 | static inline int bits_remaining(const struct datastream *ds) 614 | { 615 | return ds->data_bits - ds->ptr; 616 | } 617 | 618 | static int take_bits(struct datastream *ds, int len) 619 | { 620 | int ret = 0; 621 | 622 | while (len && (ds->ptr < ds->data_bits)) { 623 | uint8_t b = ds->data[ds->ptr >> 3]; 624 | int bitpos = ds->ptr & 7; 625 | 626 | ret <<= 1; 627 | if ((b << bitpos) & 0x80) 628 | ret |= 1; 629 | 630 | ds->ptr++; 631 | len--; 632 | } 633 | 634 | return ret; 635 | } 636 | 637 | static int numeric_tuple(struct quirc_data *data, 638 | struct datastream *ds, 639 | int bits, int digits) 640 | { 641 | int tuple; 642 | int i; 643 | 644 | if (bits_remaining(ds) < bits) 645 | return -1; 646 | 647 | tuple = take_bits(ds, bits); 648 | 649 | for (i = digits - 1; i >= 0; i--) { 650 | data->payload[data->payload_len + i] = tuple % 10 + '0'; 651 | tuple /= 10; 652 | } 653 | 654 | data->payload_len += digits; 655 | return 0; 656 | } 657 | 658 | static quirc_decode_error_t decode_numeric(struct quirc_data *data, 659 | struct datastream *ds) 660 | { 661 | int bits = 14; 662 | int count; 663 | 664 | if (data->version < 10) 665 | bits = 10; 666 | else if (data->version < 27) 667 | bits = 12; 668 | 669 | count = take_bits(ds, bits); 670 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 671 | return QUIRC_ERROR_DATA_OVERFLOW; 672 | 673 | while (count >= 3) { 674 | if (numeric_tuple(data, ds, 10, 3) < 0) 675 | return QUIRC_ERROR_DATA_UNDERFLOW; 676 | count -= 3; 677 | } 678 | 679 | if (count >= 2) { 680 | if (numeric_tuple(data, ds, 7, 2) < 0) 681 | return QUIRC_ERROR_DATA_UNDERFLOW; 682 | count -= 2; 683 | } 684 | 685 | if (count) { 686 | if (numeric_tuple(data, ds, 4, 1) < 0) 687 | return QUIRC_ERROR_DATA_UNDERFLOW; 688 | count--; 689 | } 690 | 691 | return QUIRC_SUCCESS; 692 | } 693 | 694 | static int alpha_tuple(struct quirc_data *data, 695 | struct datastream *ds, 696 | int bits, int digits) 697 | { 698 | int tuple; 699 | int i; 700 | 701 | if (bits_remaining(ds) < bits) 702 | return -1; 703 | 704 | tuple = take_bits(ds, bits); 705 | 706 | for (i = 0; i < digits; i++) { 707 | static const char *alpha_map = 708 | "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; 709 | 710 | data->payload[data->payload_len + digits - i - 1] = 711 | alpha_map[tuple % 45]; 712 | tuple /= 45; 713 | } 714 | 715 | data->payload_len += digits; 716 | return 0; 717 | } 718 | 719 | static quirc_decode_error_t decode_alpha(struct quirc_data *data, 720 | struct datastream *ds) 721 | { 722 | int bits = 13; 723 | int count; 724 | 725 | if (data->version < 7) 726 | bits = 9; 727 | else if (data->version < 11) 728 | bits = 10; 729 | 730 | count = take_bits(ds, bits); 731 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 732 | return QUIRC_ERROR_DATA_OVERFLOW; 733 | 734 | while (count >= 2) { 735 | if (alpha_tuple(data, ds, 11, 2) < 0) 736 | return QUIRC_ERROR_DATA_UNDERFLOW; 737 | count -= 2; 738 | } 739 | 740 | if (count) { 741 | if (alpha_tuple(data, ds, 6, 1) < 0) 742 | return QUIRC_ERROR_DATA_UNDERFLOW; 743 | count--; 744 | } 745 | 746 | return QUIRC_SUCCESS; 747 | } 748 | 749 | static quirc_decode_error_t decode_byte(struct quirc_data *data, 750 | struct datastream *ds) 751 | { 752 | int bits = 16; 753 | int count; 754 | int i; 755 | 756 | if (data->version < 10) 757 | bits = 8; 758 | 759 | count = take_bits(ds, bits); 760 | if (data->payload_len + count + 1 > QUIRC_MAX_PAYLOAD) 761 | return QUIRC_ERROR_DATA_OVERFLOW; 762 | if (bits_remaining(ds) < count * 8) 763 | return QUIRC_ERROR_DATA_UNDERFLOW; 764 | 765 | for (i = 0; i < count; i++) 766 | data->payload[data->payload_len++] = take_bits(ds, 8); 767 | 768 | return QUIRC_SUCCESS; 769 | } 770 | 771 | static quirc_decode_error_t decode_kanji(struct quirc_data *data, 772 | struct datastream *ds) 773 | { 774 | int bits = 12; 775 | int count; 776 | int i; 777 | 778 | if (data->version < 10) 779 | bits = 8; 780 | else if (data->version < 27) 781 | bits = 10; 782 | 783 | count = take_bits(ds, bits); 784 | if (data->payload_len + count * 2 + 1 > QUIRC_MAX_PAYLOAD) 785 | return QUIRC_ERROR_DATA_OVERFLOW; 786 | if (bits_remaining(ds) < count * 13) 787 | return QUIRC_ERROR_DATA_UNDERFLOW; 788 | 789 | for (i = 0; i < count; i++) { 790 | int d = take_bits(ds, 13); 791 | uint16_t sjw; 792 | 793 | if (d + 0x8140 >= 0x9ffc) 794 | sjw = d + 0x8140; 795 | else 796 | sjw = d + 0xc140; 797 | 798 | data->payload[data->payload_len++] = sjw >> 8; 799 | data->payload[data->payload_len++] = sjw & 0xff; 800 | } 801 | 802 | return QUIRC_SUCCESS; 803 | } 804 | 805 | static quirc_decode_error_t decode_payload(struct quirc_data *data, 806 | struct datastream *ds) 807 | { 808 | while (bits_remaining(ds) >= 4) { 809 | quirc_decode_error_t err = QUIRC_SUCCESS; 810 | int type = take_bits(ds, 4); 811 | 812 | switch (type) { 813 | case QUIRC_DATA_TYPE_NUMERIC: 814 | err = decode_numeric(data, ds); 815 | break; 816 | 817 | case QUIRC_DATA_TYPE_ALPHA: 818 | err = decode_alpha(data, ds); 819 | break; 820 | 821 | case QUIRC_DATA_TYPE_BYTE: 822 | err = decode_byte(data, ds); 823 | break; 824 | 825 | case QUIRC_DATA_TYPE_KANJI: 826 | err = decode_kanji(data, ds); 827 | break; 828 | 829 | default: 830 | goto done; 831 | } 832 | 833 | if (err) 834 | return err; 835 | 836 | if (type > data->data_type) 837 | data->data_type = type; 838 | } 839 | done: 840 | 841 | /* Add nul terminator to all payloads */ 842 | if (data->payload_len >= sizeof(data->payload)) 843 | data->payload_len--; 844 | data->payload[data->payload_len] = 0; 845 | 846 | return QUIRC_SUCCESS; 847 | } 848 | 849 | quirc_decode_error_t quirc_decode(const struct quirc_code *code, 850 | struct quirc_data *data) 851 | { 852 | quirc_decode_error_t err; 853 | struct datastream ds; 854 | 855 | if ((code->size - 17) % 4) 856 | return QUIRC_ERROR_INVALID_GRID_SIZE; 857 | 858 | memset(data, 0, sizeof(*data)); 859 | memset(&ds, 0, sizeof(ds)); 860 | 861 | data->version = (code->size - 17) / 4; 862 | 863 | if (data->version < 1 || 864 | data->version > QUIRC_MAX_VERSION) 865 | return QUIRC_ERROR_INVALID_VERSION; 866 | 867 | /* Read format information -- try both locations */ 868 | err = read_format(code, data, 0); 869 | if (err) 870 | err = read_format(code, data, 1); 871 | if (err) 872 | return err; 873 | 874 | read_data(code, data, &ds); 875 | err = codestream_ecc(data, &ds); 876 | if (err) 877 | return err; 878 | 879 | err = decode_payload(data, &ds); 880 | if (err) 881 | return err; 882 | 883 | return QUIRC_SUCCESS; 884 | } 885 | -------------------------------------------------------------------------------- /internal/quirc/lib/identify.c: -------------------------------------------------------------------------------- 1 | /* quirc - QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include "quirc_internal.h" 21 | 22 | /************************************************************************ 23 | * Linear algebra routines 24 | */ 25 | 26 | static int line_intersect(const struct quirc_point *p0, 27 | const struct quirc_point *p1, 28 | const struct quirc_point *q0, 29 | const struct quirc_point *q1, 30 | struct quirc_point *r) 31 | { 32 | /* (a, b) is perpendicular to line p */ 33 | int a = -(p1->y - p0->y); 34 | int b = p1->x - p0->x; 35 | 36 | /* (c, d) is perpendicular to line q */ 37 | int c = -(q1->y - q0->y); 38 | int d = q1->x - q0->x; 39 | 40 | /* e and f are dot products of the respective vectors with p and q */ 41 | int e = a * p1->x + b * p1->y; 42 | int f = c * q1->x + d * q1->y; 43 | 44 | /* Now we need to solve: 45 | * [a b] [rx] [e] 46 | * [c d] [ry] = [f] 47 | * 48 | * We do this by inverting the matrix and applying it to (e, f): 49 | * [ d -b] [e] [rx] 50 | * 1/det [-c a] [f] = [ry] 51 | */ 52 | int det = (a * d) - (b * c); 53 | 54 | if (!det) 55 | return 0; 56 | 57 | r->x = (d * e - b * f) / det; 58 | r->y = (-c * e + a * f) / det; 59 | 60 | return 1; 61 | } 62 | 63 | static void perspective_setup(double *c, 64 | const struct quirc_point *rect, 65 | double w, double h) 66 | { 67 | double x0 = rect[0].x; 68 | double y0 = rect[0].y; 69 | double x1 = rect[1].x; 70 | double y1 = rect[1].y; 71 | double x2 = rect[2].x; 72 | double y2 = rect[2].y; 73 | double x3 = rect[3].x; 74 | double y3 = rect[3].y; 75 | 76 | double wden = w * (x2*y3 - x3*y2 + (x3-x2)*y1 + x1*(y2-y3)); 77 | double hden = h * (x2*y3 + x1*(y2-y3) - x3*y2 + (x3-x2)*y1); 78 | 79 | c[0] = (x1*(x2*y3-x3*y2) + x0*(-x2*y3+x3*y2+(x2-x3)*y1) + 80 | x1*(x3-x2)*y0) / wden; 81 | c[1] = -(x0*(x2*y3+x1*(y2-y3)-x2*y1) - x1*x3*y2 + x2*x3*y1 82 | + (x1*x3-x2*x3)*y0) / hden; 83 | c[2] = x0; 84 | c[3] = (y0*(x1*(y3-y2)-x2*y3+x3*y2) + y1*(x2*y3-x3*y2) + 85 | x0*y1*(y2-y3)) / wden; 86 | c[4] = (x0*(y1*y3-y2*y3) + x1*y2*y3 - x2*y1*y3 + 87 | y0*(x3*y2-x1*y2+(x2-x3)*y1)) / hden; 88 | c[5] = y0; 89 | c[6] = (x1*(y3-y2) + x0*(y2-y3) + (x2-x3)*y1 + (x3-x2)*y0) / wden; 90 | c[7] = (-x2*y3 + x1*y3 + x3*y2 + x0*(y1-y2) - x3*y1 + (x2-x1)*y0) / 91 | hden; 92 | } 93 | 94 | static void perspective_map(const double *c, 95 | double u, double v, struct quirc_point *ret) 96 | { 97 | double den = c[6]*u + c[7]*v + 1.0; 98 | double x = (c[0]*u + c[1]*v + c[2]) / den; 99 | double y = (c[3]*u + c[4]*v + c[5]) / den; 100 | 101 | ret->x = rint(x); 102 | ret->y = rint(y); 103 | } 104 | 105 | static void perspective_unmap(const double *c, 106 | const struct quirc_point *in, 107 | double *u, double *v) 108 | { 109 | double x = in->x; 110 | double y = in->y; 111 | double den = -c[0]*c[7]*y + c[1]*c[6]*y + (c[3]*c[7]-c[4]*c[6])*x + 112 | c[0]*c[4] - c[1]*c[3]; 113 | 114 | *u = -(c[1]*(y-c[5]) - c[2]*c[7]*y + (c[5]*c[7]-c[4])*x + c[2]*c[4]) / 115 | den; 116 | *v = (c[0]*(y-c[5]) - c[2]*c[6]*y + (c[5]*c[6]-c[3])*x + c[2]*c[3]) / 117 | den; 118 | } 119 | 120 | /************************************************************************ 121 | * Span-based floodfill routine 122 | */ 123 | 124 | #define FLOOD_FILL_MAX_DEPTH 4096 125 | 126 | typedef void (*span_func_t)(void *user_data, int y, int left, int right); 127 | 128 | static void flood_fill_seed(struct quirc *q, int x, int y, int from, int to, 129 | span_func_t func, void *user_data, 130 | int depth) 131 | { 132 | int left = x; 133 | int right = x; 134 | int i; 135 | uint8_t *row = q->image + y * q->w; 136 | 137 | if (depth >= FLOOD_FILL_MAX_DEPTH) 138 | return; 139 | 140 | while (left > 0 && row[left - 1] == from) 141 | left--; 142 | 143 | while (right < q->w - 1 && row[right + 1] == from) 144 | right++; 145 | 146 | /* Fill the extent */ 147 | for (i = left; i <= right; i++) 148 | row[i] = to; 149 | 150 | if (func) 151 | func(user_data, y, left, right); 152 | 153 | /* Seed new flood-fills */ 154 | if (y > 0) { 155 | row = q->image + (y - 1) * q->w; 156 | 157 | for (i = left; i <= right; i++) 158 | if (row[i] == from) 159 | flood_fill_seed(q, i, y - 1, from, to, 160 | func, user_data, depth + 1); 161 | } 162 | 163 | if (y < q->h - 1) { 164 | row = q->image + (y + 1) * q->w; 165 | 166 | for (i = left; i <= right; i++) 167 | if (row[i] == from) 168 | flood_fill_seed(q, i, y + 1, from, to, 169 | func, user_data, depth + 1); 170 | } 171 | } 172 | 173 | /************************************************************************ 174 | * Adaptive thresholding 175 | */ 176 | 177 | #define THRESHOLD_S_DEN 8 178 | #define THRESHOLD_T 5 179 | 180 | static void threshold(struct quirc *q) 181 | { 182 | int x, y; 183 | int avg_w = 0; 184 | int avg_u = 0; 185 | int threshold_s = q->w / THRESHOLD_S_DEN; 186 | uint8_t *row = q->image; 187 | 188 | for (y = 0; y < q->h; y++) { 189 | int row_average[q->w]; 190 | 191 | memset(row_average, 0, sizeof(row_average)); 192 | 193 | for (x = 0; x < q->w; x++) { 194 | int w, u; 195 | 196 | if (y & 1) { 197 | w = x; 198 | u = q->w - 1 - x; 199 | } else { 200 | w = q->w - 1 - x; 201 | u = x; 202 | } 203 | 204 | avg_w = (avg_w * (threshold_s - 1)) / 205 | threshold_s + row[w]; 206 | avg_u = (avg_u * (threshold_s - 1)) / 207 | threshold_s + row[u]; 208 | 209 | row_average[w] += avg_w; 210 | row_average[u] += avg_u; 211 | } 212 | 213 | for (x = 0; x < q->w; x++) { 214 | if (row[x] < row_average[x] * 215 | (100 - THRESHOLD_T) / (200 * threshold_s)) 216 | row[x] = QUIRC_PIXEL_BLACK; 217 | else 218 | row[x] = QUIRC_PIXEL_WHITE; 219 | } 220 | 221 | row += q->w; 222 | } 223 | } 224 | 225 | static void area_count(void *user_data, int y, int left, int right) 226 | { 227 | ((struct quirc_region *)user_data)->count += right - left + 1; 228 | } 229 | 230 | static int region_code(struct quirc *q, int x, int y) 231 | { 232 | int pixel; 233 | struct quirc_region *box; 234 | int region; 235 | 236 | if (x < 0 || y < 0 || x >= q->w || y >= q->h) 237 | return -1; 238 | 239 | pixel = q->image[y * q->w + x]; 240 | 241 | if (pixel >= QUIRC_PIXEL_REGION) 242 | return pixel; 243 | 244 | if (pixel == QUIRC_PIXEL_WHITE) 245 | return -1; 246 | 247 | if (q->num_regions >= QUIRC_MAX_REGIONS) 248 | return -1; 249 | 250 | region = q->num_regions; 251 | box = &q->regions[q->num_regions++]; 252 | 253 | memset(box, 0, sizeof(*box)); 254 | 255 | box->seed.x = x; 256 | box->seed.y = y; 257 | box->capstone = -1; 258 | 259 | flood_fill_seed(q, x, y, pixel, region, area_count, box, 0); 260 | 261 | return region; 262 | } 263 | 264 | struct polygon_score_data { 265 | struct quirc_point ref; 266 | 267 | int scores[4]; 268 | struct quirc_point *corners; 269 | }; 270 | 271 | static void find_one_corner(void *user_data, int y, int left, int right) 272 | { 273 | struct polygon_score_data *psd = 274 | (struct polygon_score_data *)user_data; 275 | int xs[2] = {left, right}; 276 | int dy = y - psd->ref.y; 277 | int i; 278 | 279 | for (i = 0; i < 2; i++) { 280 | int dx = xs[i] - psd->ref.x; 281 | int d = dx * dx + dy * dy; 282 | 283 | if (d > psd->scores[0]) { 284 | psd->scores[0] = d; 285 | psd->corners[0].x = xs[i]; 286 | psd->corners[0].y = y; 287 | } 288 | } 289 | } 290 | 291 | static void find_other_corners(void *user_data, int y, int left, int right) 292 | { 293 | struct polygon_score_data *psd = 294 | (struct polygon_score_data *)user_data; 295 | int xs[2] = {left, right}; 296 | int i; 297 | 298 | for (i = 0; i < 2; i++) { 299 | int up = xs[i] * psd->ref.x + y * psd->ref.y; 300 | int right = xs[i] * -psd->ref.y + y * psd->ref.x; 301 | int scores[4] = {up, right, -up, -right}; 302 | int j; 303 | 304 | for (j = 0; j < 4; j++) { 305 | if (scores[j] > psd->scores[j]) { 306 | psd->scores[j] = scores[j]; 307 | psd->corners[j].x = xs[i]; 308 | psd->corners[j].y = y; 309 | } 310 | } 311 | } 312 | } 313 | 314 | static void find_region_corners(struct quirc *q, 315 | int rcode, const struct quirc_point *ref, 316 | struct quirc_point *corners) 317 | { 318 | struct quirc_region *region = &q->regions[rcode]; 319 | struct polygon_score_data psd; 320 | int i; 321 | 322 | memset(&psd, 0, sizeof(psd)); 323 | psd.corners = corners; 324 | 325 | memcpy(&psd.ref, ref, sizeof(psd.ref)); 326 | psd.scores[0] = -1; 327 | flood_fill_seed(q, region->seed.x, region->seed.y, 328 | rcode, QUIRC_PIXEL_BLACK, 329 | find_one_corner, &psd, 0); 330 | 331 | psd.ref.x = psd.corners[0].x - psd.ref.x; 332 | psd.ref.y = psd.corners[0].y - psd.ref.y; 333 | 334 | for (i = 0; i < 4; i++) 335 | memcpy(&psd.corners[i], ®ion->seed, 336 | sizeof(psd.corners[i])); 337 | 338 | i = region->seed.x * psd.ref.x + region->seed.y * psd.ref.y; 339 | psd.scores[0] = i; 340 | psd.scores[2] = -i; 341 | i = region->seed.x * -psd.ref.y + region->seed.y * psd.ref.x; 342 | psd.scores[1] = i; 343 | psd.scores[3] = -i; 344 | 345 | flood_fill_seed(q, region->seed.x, region->seed.y, 346 | QUIRC_PIXEL_BLACK, rcode, 347 | find_other_corners, &psd, 0); 348 | } 349 | 350 | static void record_capstone(struct quirc *q, int ring, int stone) 351 | { 352 | struct quirc_region *stone_reg = &q->regions[stone]; 353 | struct quirc_region *ring_reg = &q->regions[ring]; 354 | struct quirc_capstone *capstone; 355 | int cs_index; 356 | 357 | if (q->num_capstones >= QUIRC_MAX_CAPSTONES) 358 | return; 359 | 360 | cs_index = q->num_capstones; 361 | capstone = &q->capstones[q->num_capstones++]; 362 | 363 | memset(capstone, 0, sizeof(*capstone)); 364 | 365 | capstone->qr_grid = -1; 366 | capstone->ring = ring; 367 | capstone->stone = stone; 368 | stone_reg->capstone = cs_index; 369 | ring_reg->capstone = cs_index; 370 | 371 | /* Find the corners of the ring */ 372 | find_region_corners(q, ring, &stone_reg->seed, capstone->corners); 373 | 374 | /* Set up the perspective transform and find the center */ 375 | perspective_setup(capstone->c, capstone->corners, 7.0, 7.0); 376 | perspective_map(capstone->c, 3.5, 3.5, &capstone->center); 377 | } 378 | 379 | static void test_capstone(struct quirc *q, int x, int y, int *pb) 380 | { 381 | int ring_right = region_code(q, x - pb[4], y); 382 | int stone = region_code(q, x - pb[4] - pb[3] - pb[2], y); 383 | int ring_left = region_code(q, x - pb[4] - pb[3] - 384 | pb[2] - pb[1] - pb[0], 385 | y); 386 | struct quirc_region *stone_reg; 387 | struct quirc_region *ring_reg; 388 | int ratio; 389 | 390 | if (ring_left < 0 || ring_right < 0 || stone < 0) 391 | return; 392 | 393 | /* Left and ring of ring should be connected */ 394 | if (ring_left != ring_right) 395 | return; 396 | 397 | /* Ring should be disconnected from stone */ 398 | if (ring_left == stone) 399 | return; 400 | 401 | stone_reg = &q->regions[stone]; 402 | ring_reg = &q->regions[ring_left]; 403 | 404 | /* Already detected */ 405 | if (stone_reg->capstone >= 0 || ring_reg->capstone >= 0) 406 | return; 407 | 408 | /* Ratio should ideally be 37.5 */ 409 | ratio = stone_reg->count * 100 / ring_reg->count; 410 | if (ratio < 10 || ratio > 70) 411 | return; 412 | 413 | record_capstone(q, ring_left, stone); 414 | } 415 | 416 | static void finder_scan(struct quirc *q, int y) 417 | { 418 | uint8_t *row = q->image + y * q->w; 419 | int x; 420 | int last_color; 421 | int run_length = 0; 422 | int run_count = 0; 423 | int pb[5]; 424 | 425 | memset(pb, 0, sizeof(pb)); 426 | for (x = 0; x < q->w; x++) { 427 | int color = row[x] ? 1 : 0; 428 | 429 | if (x && color != last_color) { 430 | memmove(pb, pb + 1, sizeof(pb[0]) * 4); 431 | pb[4] = run_length; 432 | run_length = 0; 433 | run_count++; 434 | 435 | if (!color && run_count >= 5) { 436 | static int check[5] = {1, 1, 3, 1, 1}; 437 | int avg, err; 438 | int i; 439 | int ok = 1; 440 | 441 | avg = (pb[0] + pb[1] + pb[3] + pb[4]) / 4; 442 | err = avg * 3 / 4; 443 | 444 | for (i = 0; i < 5; i++) 445 | if (pb[i] < check[i] * avg - err || 446 | pb[i] > check[i] * avg + err) 447 | ok = 0; 448 | 449 | if (ok) 450 | test_capstone(q, x, y, pb); 451 | } 452 | } 453 | 454 | run_length++; 455 | last_color = color; 456 | } 457 | } 458 | 459 | static void find_alignment_pattern(struct quirc *q, int index) 460 | { 461 | struct quirc_grid *qr = &q->grids[index]; 462 | struct quirc_capstone *c0 = &q->capstones[qr->caps[0]]; 463 | struct quirc_capstone *c2 = &q->capstones[qr->caps[2]]; 464 | struct quirc_point a; 465 | struct quirc_point b; 466 | struct quirc_point c; 467 | int size_estimate; 468 | int step_size = 1; 469 | int dir = 0; 470 | double u, v; 471 | 472 | /* Grab our previous estimate of the alignment pattern corner */ 473 | memcpy(&b, &qr->align, sizeof(b)); 474 | 475 | /* Guess another two corners of the alignment pattern so that we 476 | * can estimate its size. 477 | */ 478 | perspective_unmap(c0->c, &b, &u, &v); 479 | perspective_map(c0->c, u, v + 1.0, &a); 480 | perspective_unmap(c2->c, &b, &u, &v); 481 | perspective_map(c2->c, u + 1.0, v, &c); 482 | 483 | size_estimate = abs((a.x - b.x) * -(c.y - b.y) + 484 | (a.y - b.y) * (c.x - b.x)); 485 | 486 | /* Spiral outwards from the estimate point until we find something 487 | * roughly the right size. Don't look too far from the estimate 488 | * point. 489 | */ 490 | while (step_size * step_size < size_estimate * 100) { 491 | static const int dx_map[] = {1, 0, -1, 0}; 492 | static const int dy_map[] = {0, -1, 0, 1}; 493 | int i; 494 | 495 | for (i = 0; i < step_size; i++) { 496 | int code = region_code(q, b.x, b.y); 497 | 498 | if (code >= 0) { 499 | struct quirc_region *reg = &q->regions[code]; 500 | 501 | if (reg->count >= size_estimate / 2 && 502 | reg->count <= size_estimate * 2) { 503 | qr->align_region = code; 504 | return; 505 | } 506 | } 507 | 508 | b.x += dx_map[dir]; 509 | b.y += dy_map[dir]; 510 | } 511 | 512 | dir = (dir + 1) % 4; 513 | if (!(dir & 1)) 514 | step_size++; 515 | } 516 | } 517 | 518 | static void find_leftmost_to_line(void *user_data, int y, int left, int right) 519 | { 520 | struct polygon_score_data *psd = 521 | (struct polygon_score_data *)user_data; 522 | int xs[2] = {left, right}; 523 | int i; 524 | 525 | for (i = 0; i < 2; i++) { 526 | int d = -psd->ref.y * xs[i] + psd->ref.x * y; 527 | 528 | if (d < psd->scores[0]) { 529 | psd->scores[0] = d; 530 | psd->corners[0].x = xs[i]; 531 | psd->corners[0].y = y; 532 | } 533 | } 534 | } 535 | 536 | /* Do a Bresenham scan from one point to another and count the number 537 | * of black/white transitions. 538 | */ 539 | static int timing_scan(const struct quirc *q, 540 | const struct quirc_point *p0, 541 | const struct quirc_point *p1) 542 | { 543 | int n = p1->x - p0->x; 544 | int d = p1->y - p0->y; 545 | int x = p0->x; 546 | int y = p0->y; 547 | int *dom, *nondom; 548 | int dom_step; 549 | int nondom_step; 550 | int a = 0; 551 | int i; 552 | int run_length = 0; 553 | int count = 0; 554 | 555 | if (p0->x < 0 || p0->y < 0 || p0->x >= q->w || p0->y >= q->h) 556 | return -1; 557 | if (p1->x < 0 || p1->y < 0 || p1->x >= q->w || p1->y >= q->h) 558 | return -1; 559 | 560 | if (abs(n) > abs(d)) { 561 | int swap = n; 562 | 563 | n = d; 564 | d = swap; 565 | 566 | dom = &x; 567 | nondom = &y; 568 | } else { 569 | dom = &y; 570 | nondom = &x; 571 | } 572 | 573 | if (n < 0) { 574 | n = -n; 575 | nondom_step = -1; 576 | } else { 577 | nondom_step = 1; 578 | } 579 | 580 | if (d < 0) { 581 | d = -d; 582 | dom_step = -1; 583 | } else { 584 | dom_step = 1; 585 | } 586 | 587 | x = p0->x; 588 | y = p0->y; 589 | for (i = 0; i <= d; i++) { 590 | int pixel; 591 | 592 | if (y < 0 || y >= q->h || x < 0 || x >= q->w) 593 | break; 594 | 595 | pixel = q->image[y * q->w + x]; 596 | 597 | if (pixel) { 598 | if (run_length >= 2) 599 | count++; 600 | run_length = 0; 601 | } else { 602 | run_length++; 603 | } 604 | 605 | a += n; 606 | *dom += dom_step; 607 | if (a >= d) { 608 | *nondom += nondom_step; 609 | a -= d; 610 | } 611 | } 612 | 613 | return count; 614 | } 615 | 616 | /* Try the measure the timing pattern for a given QR code. This does 617 | * not require the global perspective to have been set up, but it 618 | * does require that the capstone corners have been set to their 619 | * canonical rotation. 620 | * 621 | * For each capstone, we find a point in the middle of the ring band 622 | * which is nearest the centre of the code. Using these points, we do 623 | * a horizontal and a vertical timing scan. 624 | */ 625 | static int measure_timing_pattern(struct quirc *q, int index) 626 | { 627 | struct quirc_grid *qr = &q->grids[index]; 628 | int i; 629 | int scan; 630 | int ver; 631 | int size; 632 | 633 | for (i = 0; i < 3; i++) { 634 | static const double us[] = {6.5, 6.5, 0.5}; 635 | static const double vs[] = {0.5, 6.5, 6.5}; 636 | struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; 637 | 638 | perspective_map(cap->c, us[i], vs[i], &qr->tpep[i]); 639 | } 640 | 641 | qr->hscan = timing_scan(q, &qr->tpep[1], &qr->tpep[2]); 642 | qr->vscan = timing_scan(q, &qr->tpep[1], &qr->tpep[0]); 643 | 644 | scan = qr->hscan; 645 | if (qr->vscan > scan) 646 | scan = qr->vscan; 647 | 648 | /* If neither scan worked, we can't go any further. */ 649 | if (scan < 0) 650 | return -1; 651 | 652 | /* Choose the nearest allowable grid size */ 653 | size = scan * 2 + 13; 654 | ver = (size - 15) / 4; 655 | qr->grid_size = ver * 4 + 17; 656 | 657 | return 0; 658 | } 659 | 660 | /* Read a cell from a grid using the currently set perspective 661 | * transform. Returns +/- 1 for black/white, 0 for cells which are 662 | * out of image bounds. 663 | */ 664 | static int read_cell(const struct quirc *q, int index, int x, int y) 665 | { 666 | const struct quirc_grid *qr = &q->grids[index]; 667 | struct quirc_point p; 668 | 669 | perspective_map(qr->c, x + 0.5, y + 0.5, &p); 670 | if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w) 671 | return 0; 672 | 673 | return q->image[p.y * q->w + p.x] ? 1 : -1; 674 | } 675 | 676 | static int fitness_cell(const struct quirc *q, int index, int x, int y) 677 | { 678 | const struct quirc_grid *qr = &q->grids[index]; 679 | int score = 0; 680 | int u, v; 681 | 682 | for (v = 0; v < 3; v++) 683 | for (u = 0; u < 3; u++) { 684 | static const double offsets[] = {0.3, 0.5, 0.7}; 685 | struct quirc_point p; 686 | 687 | perspective_map(qr->c, x + offsets[u], 688 | y + offsets[v], &p); 689 | if (p.y < 0 || p.y >= q->h || p.x < 0 || p.x >= q->w) 690 | continue; 691 | 692 | if (q->image[p.y * q->w + p.x]) 693 | score++; 694 | else 695 | score--; 696 | } 697 | 698 | return score; 699 | } 700 | 701 | static int fitness_ring(const struct quirc *q, int index, int cx, int cy, 702 | int radius) 703 | { 704 | int i; 705 | int score = 0; 706 | 707 | for (i = 0; i < radius * 2; i++) { 708 | score += fitness_cell(q, index, cx - radius + i, cy - radius); 709 | score += fitness_cell(q, index, cx - radius, cy + radius - i); 710 | score += fitness_cell(q, index, cx + radius, cy - radius + i); 711 | score += fitness_cell(q, index, cx + radius - i, cy + radius); 712 | } 713 | 714 | return score; 715 | } 716 | 717 | static int fitness_apat(const struct quirc *q, int index, int cx, int cy) 718 | { 719 | return fitness_cell(q, index, cx, cy) - 720 | fitness_ring(q, index, cx, cy, 1) + 721 | fitness_ring(q, index, cx, cy, 2); 722 | } 723 | 724 | static int fitness_capstone(const struct quirc *q, int index, int x, int y) 725 | { 726 | x += 3; 727 | y += 3; 728 | 729 | return fitness_cell(q, index, x, y) + 730 | fitness_ring(q, index, x, y, 1) - 731 | fitness_ring(q, index, x, y, 2) + 732 | fitness_ring(q, index, x, y, 3); 733 | } 734 | 735 | /* Compute a fitness score for the currently configured perspective 736 | * transform, using the features we expect to find by scanning the 737 | * grid. 738 | */ 739 | static int fitness_all(const struct quirc *q, int index) 740 | { 741 | const struct quirc_grid *qr = &q->grids[index]; 742 | int version = (qr->grid_size - 17) / 4; 743 | const struct quirc_version_info *info = &quirc_version_db[version]; 744 | int score = 0; 745 | int i, j; 746 | int ap_count; 747 | 748 | /* Check the timing pattern */ 749 | for (i = 0; i < qr->grid_size - 14; i++) { 750 | int expect = (i & 1) ? 1 : -1; 751 | 752 | score += fitness_cell(q, index, i + 7, 6) * expect; 753 | score += fitness_cell(q, index, 6, i + 7) * expect; 754 | } 755 | 756 | /* Check capstones */ 757 | score += fitness_capstone(q, index, 0, 0); 758 | score += fitness_capstone(q, index, qr->grid_size - 7, 0); 759 | score += fitness_capstone(q, index, 0, qr->grid_size - 7); 760 | 761 | if (version < 0 || version > QUIRC_MAX_VERSION) 762 | return score; 763 | 764 | /* Check alignment patterns */ 765 | ap_count = 0; 766 | while (info->apat[ap_count]) 767 | ap_count++; 768 | 769 | for (i = 1; i + 1 < ap_count; i++) { 770 | score += fitness_apat(q, index, 6, info->apat[i]); 771 | score += fitness_apat(q, index, info->apat[i], 6); 772 | } 773 | 774 | for (i = 1; i < ap_count; i++) 775 | for (j = 1; j < ap_count; j++) 776 | score += fitness_apat(q, index, 777 | info->apat[i], info->apat[j]); 778 | 779 | return score; 780 | } 781 | 782 | static void jiggle_perspective(struct quirc *q, int index) 783 | { 784 | struct quirc_grid *qr = &q->grids[index]; 785 | int best = fitness_all(q, index); 786 | int pass; 787 | double adjustments[8]; 788 | int i; 789 | 790 | for (i = 0; i < 8; i++) 791 | adjustments[i] = qr->c[i] * 0.02; 792 | 793 | for (pass = 0; pass < 5; pass++) { 794 | for (i = 0; i < 16; i++) { 795 | int j = i >> 1; 796 | int test; 797 | double old = qr->c[j]; 798 | double step = adjustments[j]; 799 | double new; 800 | 801 | if (i & 1) 802 | new = old + step; 803 | else 804 | new = old - step; 805 | 806 | qr->c[j] = new; 807 | test = fitness_all(q, index); 808 | 809 | if (test > best) 810 | best = test; 811 | else 812 | qr->c[j] = old; 813 | } 814 | 815 | for (i = 0; i < 8; i++) 816 | adjustments[i] *= 0.5; 817 | } 818 | } 819 | 820 | /* Once the capstones are in place and an alignment point has been 821 | * chosen, we call this function to set up a grid-reading perspective 822 | * transform. 823 | */ 824 | static void setup_qr_perspective(struct quirc *q, int index) 825 | { 826 | struct quirc_grid *qr = &q->grids[index]; 827 | struct quirc_point rect[4]; 828 | 829 | /* Set up the perspective map for reading the grid */ 830 | memcpy(&rect[0], &q->capstones[qr->caps[1]].corners[0], 831 | sizeof(rect[0])); 832 | memcpy(&rect[1], &q->capstones[qr->caps[2]].corners[0], 833 | sizeof(rect[0])); 834 | memcpy(&rect[2], &qr->align, sizeof(rect[0])); 835 | memcpy(&rect[3], &q->capstones[qr->caps[0]].corners[0], 836 | sizeof(rect[0])); 837 | perspective_setup(qr->c, rect, qr->grid_size - 7, qr->grid_size - 7); 838 | 839 | jiggle_perspective(q, index); 840 | } 841 | 842 | /* Rotate the capstone with so that corner 0 is the leftmost with respect 843 | * to the given reference line. 844 | */ 845 | static void rotate_capstone(struct quirc_capstone *cap, 846 | const struct quirc_point *h0, 847 | const struct quirc_point *hd) 848 | { 849 | struct quirc_point copy[4]; 850 | int j; 851 | int best; 852 | int best_score; 853 | 854 | for (j = 0; j < 4; j++) { 855 | struct quirc_point *p = &cap->corners[j]; 856 | int score = (p->x - h0->x) * -hd->y + 857 | (p->y - h0->y) * hd->x; 858 | 859 | if (!j || score < best_score) { 860 | best = j; 861 | best_score = score; 862 | } 863 | } 864 | 865 | /* Rotate the capstone */ 866 | for (j = 0; j < 4; j++) 867 | memcpy(©[j], &cap->corners[(j + best) % 4], 868 | sizeof(copy[j])); 869 | memcpy(cap->corners, copy, sizeof(cap->corners)); 870 | perspective_setup(cap->c, cap->corners, 7.0, 7.0); 871 | } 872 | 873 | static void record_qr_grid(struct quirc *q, int a, int b, int c) 874 | { 875 | struct quirc_point h0, hd; 876 | int i; 877 | int qr_index; 878 | struct quirc_grid *qr; 879 | 880 | if (q->num_grids >= QUIRC_MAX_GRIDS) 881 | return; 882 | 883 | /* Construct the hypotenuse line from A to C. B should be to 884 | * the left of this line. 885 | */ 886 | memcpy(&h0, &q->capstones[a].center, sizeof(h0)); 887 | hd.x = q->capstones[c].center.x - q->capstones[a].center.x; 888 | hd.y = q->capstones[c].center.y - q->capstones[a].center.y; 889 | 890 | /* Make sure A-B-C is clockwise */ 891 | if ((q->capstones[b].center.x - h0.x) * -hd.y + 892 | (q->capstones[b].center.y - h0.y) * hd.x > 0) { 893 | int swap = a; 894 | 895 | a = c; 896 | c = swap; 897 | hd.x = -hd.x; 898 | hd.y = -hd.y; 899 | } 900 | 901 | /* Record the grid and its components */ 902 | qr_index = q->num_grids; 903 | qr = &q->grids[q->num_grids++]; 904 | 905 | memset(qr, 0, sizeof(*qr)); 906 | qr->caps[0] = a; 907 | qr->caps[1] = b; 908 | qr->caps[2] = c; 909 | qr->align_region = -1; 910 | 911 | /* Rotate each capstone so that corner 0 is top-left with respect 912 | * to the grid. 913 | */ 914 | for (i = 0; i < 3; i++) { 915 | struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; 916 | 917 | rotate_capstone(cap, &h0, &hd); 918 | cap->qr_grid = qr_index; 919 | } 920 | 921 | /* Check the timing pattern. This doesn't require a perspective 922 | * transform. 923 | */ 924 | if (measure_timing_pattern(q, qr_index) < 0) 925 | goto fail; 926 | 927 | /* Make an estimate based for the alignment pattern based on extending 928 | * lines from capstones A and C. 929 | */ 930 | if (!line_intersect(&q->capstones[a].corners[0], 931 | &q->capstones[a].corners[1], 932 | &q->capstones[c].corners[0], 933 | &q->capstones[c].corners[3], 934 | &qr->align)) 935 | goto fail; 936 | 937 | /* On V2+ grids, we should use the alignment pattern. */ 938 | if (qr->grid_size > 21) { 939 | /* Try to find the actual location of the alignment pattern. */ 940 | find_alignment_pattern(q, qr_index); 941 | 942 | /* Find the point of the alignment pattern closest to the 943 | * top-left of the QR grid. 944 | */ 945 | if (qr->align_region >= 0) { 946 | struct polygon_score_data psd; 947 | struct quirc_region *reg = 948 | &q->regions[qr->align_region]; 949 | 950 | /* Start from some point inside the alignment pattern */ 951 | memcpy(&qr->align, ®->seed, sizeof(qr->align)); 952 | 953 | memcpy(&psd.ref, &hd, sizeof(psd.ref)); 954 | psd.corners = &qr->align; 955 | psd.scores[0] = -hd.y * qr->align.x + 956 | hd.x * qr->align.y; 957 | 958 | flood_fill_seed(q, reg->seed.x, reg->seed.y, 959 | qr->align_region, QUIRC_PIXEL_BLACK, 960 | NULL, NULL, 0); 961 | flood_fill_seed(q, reg->seed.x, reg->seed.y, 962 | QUIRC_PIXEL_BLACK, qr->align_region, 963 | find_leftmost_to_line, &psd, 0); 964 | } 965 | } 966 | 967 | setup_qr_perspective(q, qr_index); 968 | return; 969 | 970 | fail: 971 | /* We've been unable to complete setup for this grid. Undo what we've 972 | * recorded and pretend it never happened. 973 | */ 974 | for (i = 0; i < 3; i++) 975 | q->capstones[qr->caps[i]].qr_grid = -1; 976 | q->num_grids--; 977 | } 978 | 979 | struct neighbour { 980 | int index; 981 | double distance; 982 | }; 983 | 984 | struct neighbour_list { 985 | struct neighbour n[QUIRC_MAX_CAPSTONES]; 986 | int count; 987 | }; 988 | 989 | static void test_neighbours(struct quirc *q, int i, 990 | const struct neighbour_list *hlist, 991 | const struct neighbour_list *vlist) 992 | { 993 | int j, k; 994 | double best_score = 0.0; 995 | int best_h = -1, best_v = -1; 996 | 997 | /* Test each possible grouping */ 998 | for (j = 0; j < hlist->count; j++) 999 | for (k = 0; k < vlist->count; k++) { 1000 | const struct neighbour *hn = &hlist->n[j]; 1001 | const struct neighbour *vn = &vlist->n[k]; 1002 | double score = fabs(1.0 - hn->distance / vn->distance); 1003 | 1004 | if (score > 2.5) 1005 | continue; 1006 | 1007 | if (best_h < 0 || score < best_score) { 1008 | best_h = hn->index; 1009 | best_v = vn->index; 1010 | best_score = score; 1011 | } 1012 | } 1013 | 1014 | if (best_h < 0 || best_v < 0) 1015 | return; 1016 | 1017 | record_qr_grid(q, best_h, i, best_v); 1018 | } 1019 | 1020 | static void test_grouping(struct quirc *q, int i) 1021 | { 1022 | struct quirc_capstone *c1 = &q->capstones[i]; 1023 | int j; 1024 | struct neighbour_list hlist; 1025 | struct neighbour_list vlist; 1026 | 1027 | if (c1->qr_grid >= 0) 1028 | return; 1029 | 1030 | hlist.count = 0; 1031 | vlist.count = 0; 1032 | 1033 | /* Look for potential neighbours by examining the relative gradients 1034 | * from this capstone to others. 1035 | */ 1036 | for (j = 0; j < q->num_capstones; j++) { 1037 | struct quirc_capstone *c2 = &q->capstones[j]; 1038 | double u, v; 1039 | 1040 | if (i == j || c2->qr_grid >= 0) 1041 | continue; 1042 | 1043 | perspective_unmap(c1->c, &c2->center, &u, &v); 1044 | 1045 | u = fabs(u - 3.5); 1046 | v = fabs(v - 3.5); 1047 | 1048 | if (u < 0.2 * v) { 1049 | struct neighbour *n = &hlist.n[hlist.count++]; 1050 | 1051 | n->index = j; 1052 | n->distance = v; 1053 | } 1054 | 1055 | if (v < 0.2 * u) { 1056 | struct neighbour *n = &vlist.n[vlist.count++]; 1057 | 1058 | n->index = j; 1059 | n->distance = u; 1060 | } 1061 | } 1062 | 1063 | if (!(hlist.count && vlist.count)) 1064 | return; 1065 | 1066 | test_neighbours(q, i, &hlist, &vlist); 1067 | } 1068 | 1069 | uint8_t *quirc_begin(struct quirc *q, int *w, int *h) 1070 | { 1071 | q->num_regions = QUIRC_PIXEL_REGION; 1072 | q->num_capstones = 0; 1073 | q->num_grids = 0; 1074 | 1075 | if (w) 1076 | *w = q->w; 1077 | if (h) 1078 | *h = q->h; 1079 | 1080 | return q->image; 1081 | } 1082 | 1083 | void quirc_end(struct quirc *q) 1084 | { 1085 | int i; 1086 | 1087 | threshold(q); 1088 | 1089 | for (i = 0; i < q->h; i++) 1090 | finder_scan(q, i); 1091 | 1092 | for (i = 0; i < q->num_capstones; i++) 1093 | test_grouping(q, i); 1094 | } 1095 | 1096 | void quirc_extract(const struct quirc *q, int index, 1097 | struct quirc_code *code) 1098 | { 1099 | const struct quirc_grid *qr = &q->grids[index]; 1100 | int y; 1101 | int i = 0; 1102 | 1103 | if (index < 0 || index > q->num_grids) 1104 | return; 1105 | 1106 | memset(code, 0, sizeof(*code)); 1107 | 1108 | perspective_map(qr->c, 0.0, 0.0, &code->corners[0]); 1109 | perspective_map(qr->c, qr->grid_size, 0.0, &code->corners[1]); 1110 | perspective_map(qr->c, qr->grid_size, qr->grid_size, 1111 | &code->corners[2]); 1112 | perspective_map(qr->c, 0.0, qr->grid_size, &code->corners[3]); 1113 | 1114 | code->size = qr->grid_size; 1115 | 1116 | for (y = 0; y < qr->grid_size; y++) { 1117 | int x; 1118 | 1119 | for (x = 0; x < qr->grid_size; x++) { 1120 | if (read_cell(q, index, x, y) > 0) 1121 | code->cell_bitmap[i >> 3] |= (1 << (i & 7)); 1122 | 1123 | i++; 1124 | } 1125 | } 1126 | } 1127 | -------------------------------------------------------------------------------- /internal/quirc/lib/quirc.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include "quirc_internal.h" 20 | 21 | const char *quirc_version(void) 22 | { 23 | return "1.0"; 24 | } 25 | 26 | struct quirc *quirc_new(void) 27 | { 28 | struct quirc *q = malloc(sizeof(*q)); 29 | 30 | if (!q) 31 | return NULL; 32 | 33 | memset(q, 0, sizeof(*q)); 34 | return q; 35 | } 36 | 37 | void quirc_destroy(struct quirc *q) 38 | { 39 | if (q->image) 40 | free(q->image); 41 | 42 | free(q); 43 | } 44 | 45 | int quirc_resize(struct quirc *q, int w, int h) 46 | { 47 | uint8_t *new_image = realloc(q->image, w * h); 48 | 49 | if (!new_image) 50 | return -1; 51 | 52 | q->image = new_image; 53 | q->w = w; 54 | q->h = h; 55 | 56 | return 0; 57 | } 58 | 59 | int quirc_count(const struct quirc *q) 60 | { 61 | return q->num_grids; 62 | } 63 | 64 | static const char *const error_table[] = { 65 | [QUIRC_SUCCESS] = "Success", 66 | [QUIRC_ERROR_INVALID_GRID_SIZE] = "Invalid grid size", 67 | [QUIRC_ERROR_INVALID_VERSION] = "Invalid version", 68 | [QUIRC_ERROR_FORMAT_ECC] = "Format data ECC failure", 69 | [QUIRC_ERROR_DATA_ECC] = "ECC failure", 70 | [QUIRC_ERROR_UNKNOWN_DATA_TYPE] = "Unknown data type", 71 | [QUIRC_ERROR_DATA_OVERFLOW] = "Data overflow", 72 | [QUIRC_ERROR_DATA_UNDERFLOW] = "Data underflow" 73 | }; 74 | 75 | const char *quirc_strerror(quirc_decode_error_t err) 76 | { 77 | if (err >= 0 && err < sizeof(error_table) / sizeof(error_table[0])) 78 | return error_table[err]; 79 | 80 | return "Unknown error"; 81 | } 82 | -------------------------------------------------------------------------------- /internal/quirc/lib/quirc.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef QUIRC_H_ 18 | #define QUIRC_H_ 19 | 20 | #include 21 | 22 | struct quirc; 23 | 24 | /* Obtain the library version string. */ 25 | const char *quirc_version(void); 26 | 27 | /* Construct a new QR-code recognizer. This function will return NULL 28 | * if sufficient memory could not be allocated. 29 | */ 30 | struct quirc *quirc_new(void); 31 | 32 | /* Destroy a QR-code recognizer. */ 33 | void quirc_destroy(struct quirc *q); 34 | 35 | /* Resize the QR-code recognizer. The size of an image must be 36 | * specified before codes can be analyzed. 37 | * 38 | * This function returns 0 on success, or -1 if sufficient memory could 39 | * not be allocated. 40 | */ 41 | int quirc_resize(struct quirc *q, int w, int h); 42 | 43 | /* These functions are used to process images for QR-code recognition. 44 | * quirc_begin() must first be called to obtain access to a buffer into 45 | * which the input image should be placed. Optionally, the current 46 | * width and height may be returned. 47 | * 48 | * After filling the buffer, quirc_end() should be called to process 49 | * the image for QR-code recognition. The locations and content of each 50 | * code may be obtained using accessor functions described below. 51 | */ 52 | uint8_t *quirc_begin(struct quirc *q, int *w, int *h); 53 | void quirc_end(struct quirc *q); 54 | 55 | /* This structure describes a location in the input image buffer. */ 56 | struct quirc_point { 57 | int x; 58 | int y; 59 | }; 60 | 61 | /* This enum describes the various decoder errors which may occur. */ 62 | typedef enum { 63 | QUIRC_SUCCESS = 0, 64 | QUIRC_ERROR_INVALID_GRID_SIZE, 65 | QUIRC_ERROR_INVALID_VERSION, 66 | QUIRC_ERROR_FORMAT_ECC, 67 | QUIRC_ERROR_DATA_ECC, 68 | QUIRC_ERROR_UNKNOWN_DATA_TYPE, 69 | QUIRC_ERROR_DATA_OVERFLOW, 70 | QUIRC_ERROR_DATA_UNDERFLOW 71 | } quirc_decode_error_t; 72 | 73 | /* Return a string error message for an error code. */ 74 | const char *quirc_strerror(quirc_decode_error_t err); 75 | 76 | /* Limits on the maximum size of QR-codes and their content. */ 77 | #define QUIRC_MAX_BITMAP 3917 78 | #define QUIRC_MAX_PAYLOAD 8896 79 | 80 | /* QR-code ECC types. */ 81 | #define QUIRC_ECC_LEVEL_M 0 82 | #define QUIRC_ECC_LEVEL_L 1 83 | #define QUIRC_ECC_LEVEL_H 2 84 | #define QUIRC_ECC_LEVEL_Q 3 85 | 86 | /* QR-code data types. */ 87 | #define QUIRC_DATA_TYPE_NUMERIC 1 88 | #define QUIRC_DATA_TYPE_ALPHA 2 89 | #define QUIRC_DATA_TYPE_BYTE 4 90 | #define QUIRC_DATA_TYPE_KANJI 8 91 | 92 | /* This structure is used to return information about detected QR codes 93 | * in the input image. 94 | */ 95 | struct quirc_code { 96 | /* The four corners of the QR-code, from top left, clockwise */ 97 | struct quirc_point corners[4]; 98 | 99 | /* The number of cells across in the QR-code. The cell bitmap 100 | * is a bitmask giving the actual values of cells. If the cell 101 | * at (x, y) is black, then the following bit is set: 102 | * 103 | * cell_bitmap[i << 3] & (1 << (i & 7)) 104 | * 105 | * where i = (y * size) + x. 106 | */ 107 | int size; 108 | uint8_t cell_bitmap[QUIRC_MAX_BITMAP]; 109 | }; 110 | 111 | /* This structure holds the decoded QR-code data */ 112 | struct quirc_data { 113 | /* Various parameters of the QR-code. These can mostly be 114 | * ignored if you only care about the data. 115 | */ 116 | int version; 117 | int ecc_level; 118 | int mask; 119 | 120 | /* This field is the highest-valued data type found in the QR 121 | * code. 122 | */ 123 | int data_type; 124 | 125 | /* Data payload. For the Kanji datatype, payload is encoded as 126 | * Shift-JIS. For all other datatypes, payload is ASCII text. 127 | */ 128 | uint8_t payload[QUIRC_MAX_PAYLOAD]; 129 | int payload_len; 130 | }; 131 | 132 | /* Return the number of QR-codes identified in the last processed 133 | * image. 134 | */ 135 | int quirc_count(const struct quirc *q); 136 | 137 | /* Extract the QR-code specified by the given index. */ 138 | void quirc_extract(const struct quirc *q, int index, 139 | struct quirc_code *code); 140 | 141 | /* Decode a QR-code, returning the payload data. */ 142 | quirc_decode_error_t quirc_decode(const struct quirc_code *code, 143 | struct quirc_data *data); 144 | 145 | #endif 146 | -------------------------------------------------------------------------------- /internal/quirc/lib/quirc_internal.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef QUIRC_INTERNAL_H_ 18 | #define QUIRC_INTERNAL_H_ 19 | 20 | #include "quirc.h" 21 | 22 | #define QUIRC_PIXEL_WHITE 0 23 | #define QUIRC_PIXEL_BLACK 1 24 | #define QUIRC_PIXEL_REGION 2 25 | 26 | #define QUIRC_MAX_REGIONS 254 27 | #define QUIRC_MAX_CAPSTONES 32 28 | #define QUIRC_MAX_GRIDS 8 29 | 30 | #define QUIRC_PERSPECTIVE_PARAMS 8 31 | 32 | struct quirc_region { 33 | struct quirc_point seed; 34 | int count; 35 | int capstone; 36 | }; 37 | 38 | struct quirc_capstone { 39 | int ring; 40 | int stone; 41 | 42 | struct quirc_point corners[4]; 43 | struct quirc_point center; 44 | double c[QUIRC_PERSPECTIVE_PARAMS]; 45 | 46 | int qr_grid; 47 | }; 48 | 49 | struct quirc_grid { 50 | /* Capstone indices */ 51 | int caps[3]; 52 | 53 | /* Alignment pattern region and corner */ 54 | int align_region; 55 | struct quirc_point align; 56 | 57 | /* Timing pattern endpoints */ 58 | struct quirc_point tpep[3]; 59 | int hscan; 60 | int vscan; 61 | 62 | /* Grid size and perspective transform */ 63 | int grid_size; 64 | double c[QUIRC_PERSPECTIVE_PARAMS]; 65 | }; 66 | 67 | struct quirc { 68 | uint8_t *image; 69 | int w; 70 | int h; 71 | 72 | int num_regions; 73 | struct quirc_region regions[QUIRC_MAX_REGIONS]; 74 | 75 | int num_capstones; 76 | struct quirc_capstone capstones[QUIRC_MAX_CAPSTONES]; 77 | 78 | int num_grids; 79 | struct quirc_grid grids[QUIRC_MAX_GRIDS]; 80 | }; 81 | 82 | /************************************************************************ 83 | * QR-code version information database 84 | */ 85 | 86 | #define QUIRC_MAX_VERSION 40 87 | #define QUIRC_MAX_ALIGNMENT 7 88 | 89 | struct quirc_rs_params { 90 | int bs; /* Block size */ 91 | int dw; /* Data words */ 92 | int ce; /* Correctable errors */ 93 | }; 94 | 95 | struct quirc_version_info { 96 | int data_bytes; 97 | int apat[QUIRC_MAX_ALIGNMENT]; 98 | struct quirc_rs_params ecc[4]; 99 | }; 100 | 101 | extern const struct quirc_version_info quirc_version_db[QUIRC_MAX_VERSION + 1]; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /internal/quirc/lib/version_db.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include "quirc_internal.h" 18 | 19 | const struct quirc_version_info quirc_version_db[QUIRC_MAX_VERSION + 1] = { 20 | {0}, 21 | { /* Version 1 */ 22 | .data_bytes = 26, 23 | .apat = {0}, 24 | .ecc = { 25 | {.bs = 26, .dw = 16, .ce = 4}, 26 | {.bs = 26, .dw = 19, .ce = 2}, 27 | {.bs = 26, .dw = 9, .ce = 8}, 28 | {.bs = 26, .dw = 13, .ce = 6} 29 | } 30 | }, 31 | { /* Version 2 */ 32 | .data_bytes = 44, 33 | .apat = {6, 18, 0}, 34 | .ecc = { 35 | {.bs = 44, .dw = 28, .ce = 8}, 36 | {.bs = 44, .dw = 34, .ce = 4}, 37 | {.bs = 44, .dw = 16, .ce = 14}, 38 | {.bs = 44, .dw = 22, .ce = 11} 39 | } 40 | }, 41 | { /* Version 3 */ 42 | .data_bytes = 70, 43 | .apat = {6, 22, 0}, 44 | .ecc = { 45 | {.bs = 70, .dw = 44, .ce = 13}, 46 | {.bs = 70, .dw = 55, .ce = 7}, 47 | {.bs = 35, .dw = 13, .ce = 11}, 48 | {.bs = 35, .dw = 17, .ce = 9} 49 | } 50 | }, 51 | { /* Version 4 */ 52 | .data_bytes = 100, 53 | .apat = {6, 26, 0}, 54 | .ecc = { 55 | {.bs = 50, .dw = 32, .ce = 9}, 56 | {.bs = 100, .dw = 80, .ce = 10}, 57 | {.bs = 25, .dw = 9, .ce = 8}, 58 | {.bs = 50, .dw = 24, .ce = 13} 59 | } 60 | }, 61 | { /* Version 5 */ 62 | .data_bytes = 134, 63 | .apat = {6, 30, 0}, 64 | .ecc = { 65 | {.bs = 67, .dw = 43, .ce = 12}, 66 | {.bs = 134, .dw = 108, .ce = 13}, 67 | {.bs = 33, .dw = 11, .ce = 11}, 68 | {.bs = 33, .dw = 15, .ce = 9} 69 | } 70 | }, 71 | { /* Version 6 */ 72 | .data_bytes = 172, 73 | .apat = {6, 34, 0}, 74 | .ecc = { 75 | {.bs = 43, .dw = 27, .ce = 8}, 76 | {.bs = 86, .dw = 68, .ce = 9}, 77 | {.bs = 43, .dw = 15, .ce = 14}, 78 | {.bs = 43, .dw = 19, .ce = 12} 79 | } 80 | }, 81 | { /* Version 7 */ 82 | .data_bytes = 196, 83 | .apat = {6, 22, 38, 0}, 84 | .ecc = { 85 | {.bs = 49, .dw = 31, .ce = 9}, 86 | {.bs = 98, .dw = 78, .ce = 10}, 87 | {.bs = 39, .dw = 13, .ce = 13}, 88 | {.bs = 32, .dw = 14, .ce = 9} 89 | } 90 | }, 91 | { /* Version 8 */ 92 | .data_bytes = 242, 93 | .apat = {6, 24, 42, 0}, 94 | .ecc = { 95 | {.bs = 60, .dw = 38, .ce = 11}, 96 | {.bs = 121, .dw = 97, .ce = 12}, 97 | {.bs = 40, .dw = 14, .ce = 13}, 98 | {.bs = 40, .dw = 18, .ce = 11} 99 | } 100 | }, 101 | { /* Version 9 */ 102 | .data_bytes = 292, 103 | .apat = {6, 26, 46, 0}, 104 | .ecc = { 105 | {.bs = 58, .dw = 36, .ce = 11}, 106 | {.bs = 146, .dw = 116, .ce = 15}, 107 | {.bs = 36, .dw = 12, .ce = 12}, 108 | {.bs = 36, .dw = 16, .ce = 10} 109 | } 110 | }, 111 | { /* Version 10 */ 112 | .data_bytes = 346, 113 | .apat = {6, 28, 50, 0}, 114 | .ecc = { 115 | {.bs = 69, .dw = 43, .ce = 13}, 116 | {.bs = 86, .dw = 68, .ce = 9}, 117 | {.bs = 43, .dw = 15, .ce = 14}, 118 | {.bs = 43, .dw = 19, .ce = 12} 119 | } 120 | }, 121 | { /* Version 11 */ 122 | .data_bytes = 404, 123 | .apat = {6, 30, 54, 0}, 124 | .ecc = { 125 | {.bs = 80, .dw = 50, .ce = 15}, 126 | {.bs = 101, .dw = 81, .ce = 10}, 127 | {.bs = 36, .dw = 12, .ce = 12}, 128 | {.bs = 50, .dw = 22, .ce = 14} 129 | } 130 | }, 131 | { /* Version 12 */ 132 | .data_bytes = 466, 133 | .apat = {6, 32, 58, 0}, 134 | .ecc = { 135 | {.bs = 58, .dw = 36, .ce = 11}, 136 | {.bs = 116, .dw = 92, .ce = 12}, 137 | {.bs = 42, .dw = 14, .ce = 14}, 138 | {.bs = 46, .dw = 20, .ce = 14} 139 | } 140 | }, 141 | { /* Version 13 */ 142 | .data_bytes = 532, 143 | .apat = {6, 34, 62, 0}, 144 | .ecc = { 145 | {.bs = 59, .dw = 37, .ce = 11}, 146 | {.bs = 133, .dw = 107, .ce = 13}, 147 | {.bs = 33, .dw = 11, .ce = 11}, 148 | {.bs = 44, .dw = 20, .ce = 12} 149 | } 150 | }, 151 | { /* Version 14 */ 152 | .data_bytes = 581, 153 | .apat = {6, 26, 46, 66, 0}, 154 | .ecc = { 155 | {.bs = 65, .dw = 41, .ce = 12}, 156 | {.bs = 109, .dw = 87, .ce = 11}, 157 | {.bs = 36, .dw = 12, .ce = 12}, 158 | {.bs = 54, .dw = 24, .ce = 15} 159 | } 160 | }, 161 | { /* Version 15 */ 162 | .data_bytes = 655, 163 | .apat = {6, 26, 48, 70, 0}, 164 | .ecc = { 165 | {.bs = 65, .dw = 41, .ce = 12}, 166 | {.bs = 109, .dw = 87, .ce = 11}, 167 | {.bs = 36, .dw = 12, .ce = 12}, 168 | {.bs = 54, .dw = 24, .ce = 15} 169 | } 170 | }, 171 | { /* Version 16 */ 172 | .data_bytes = 733, 173 | .apat = {6, 26, 50, 74, 0}, 174 | .ecc = { 175 | {.bs = 73, .dw = 45, .ce = 14}, 176 | {.bs = 122, .dw = 98, .ce = 12}, 177 | {.bs = 45, .dw = 15, .ce = 15}, 178 | {.bs = 43, .dw = 19, .ce = 12} 179 | } 180 | }, 181 | { /* Version 17 */ 182 | .data_bytes = 815, 183 | .apat = {6, 30, 54, 78, 0}, 184 | .ecc = { 185 | {.bs = 74, .dw = 46, .ce = 14}, 186 | {.bs = 135, .dw = 107, .ce = 14}, 187 | {.bs = 42, .dw = 14, .ce = 14}, 188 | {.bs = 50, .dw = 22, .ce = 14} 189 | } 190 | }, 191 | { /* Version 18 */ 192 | .data_bytes = 901, 193 | .apat = {6, 30, 56, 82, 0}, 194 | .ecc = { 195 | {.bs = 69, .dw = 43, .ce = 13}, 196 | {.bs = 150, .dw = 120, .ce = 15}, 197 | {.bs = 42, .dw = 14, .ce = 14}, 198 | {.bs = 50, .dw = 22, .ce = 14} 199 | } 200 | }, 201 | { /* Version 19 */ 202 | .data_bytes = 991, 203 | .apat = {6, 30, 58, 86, 0}, 204 | .ecc = { 205 | {.bs = 70, .dw = 44, .ce = 13}, 206 | {.bs = 141, .dw = 113, .ce = 14}, 207 | {.bs = 39, .dw = 13, .ce = 13}, 208 | {.bs = 47, .dw = 21, .ce = 13} 209 | } 210 | }, 211 | { /* Version 20 */ 212 | .data_bytes = 1085, 213 | .apat = {6, 34, 62, 90, 0}, 214 | .ecc = { 215 | {.bs = 67, .dw = 41, .ce = 13}, 216 | {.bs = 135, .dw = 107, .ce = 14}, 217 | {.bs = 43, .dw = 15, .ce = 14}, 218 | {.bs = 54, .dw = 24, .ce = 15} 219 | } 220 | }, 221 | { /* Version 21 */ 222 | .data_bytes = 1156, 223 | .apat = {6, 28, 50, 72, 92, 0}, 224 | .ecc = { 225 | {.bs = 68, .dw = 42, .ce = 13}, 226 | {.bs = 144, .dw = 116, .ce = 14}, 227 | {.bs = 46, .dw = 16, .ce = 15}, 228 | {.bs = 50, .dw = 22, .ce = 14} 229 | } 230 | }, 231 | { /* Version 22 */ 232 | .data_bytes = 1258, 233 | .apat = {6, 26, 50, 74, 98, 0}, 234 | .ecc = { 235 | {.bs = 74, .dw = 46, .ce = 14}, 236 | {.bs = 139, .dw = 111, .ce = 14}, 237 | {.bs = 37, .dw = 13, .ce = 12}, 238 | {.bs = 54, .dw = 24, .ce = 15} 239 | } 240 | }, 241 | { /* Version 23 */ 242 | .data_bytes = 1364, 243 | .apat = {6, 30, 54, 78, 102, 0}, 244 | .ecc = { 245 | {.bs = 75, .dw = 47, .ce = 14}, 246 | {.bs = 151, .dw = 121, .ce = 15}, 247 | {.bs = 45, .dw = 15, .ce = 15}, 248 | {.bs = 54, .dw = 24, .ce = 15} 249 | } 250 | }, 251 | { /* Version 24 */ 252 | .data_bytes = 1474, 253 | .apat = {6, 28, 54, 80, 106, 0}, 254 | .ecc = { 255 | {.bs = 73, .dw = 45, .ce = 14}, 256 | {.bs = 147, .dw = 117, .ce = 15}, 257 | {.bs = 46, .dw = 16, .ce = 15}, 258 | {.bs = 54, .dw = 24, .ce = 15} 259 | } 260 | }, 261 | { /* Version 25 */ 262 | .data_bytes = 1588, 263 | .apat = {6, 32, 58, 84, 110, 0}, 264 | .ecc = { 265 | {.bs = 75, .dw = 47, .ce = 14}, 266 | {.bs = 132, .dw = 106, .ce = 13}, 267 | {.bs = 45, .dw = 15, .ce = 15}, 268 | {.bs = 54, .dw = 24, .ce = 15} 269 | } 270 | }, 271 | { /* Version 26 */ 272 | .data_bytes = 1706, 273 | .apat = {6, 30, 58, 86, 114, 0}, 274 | .ecc = { 275 | {.bs = 74, .dw = 46, .ce = 14}, 276 | {.bs = 142, .dw = 114, .ce = 14}, 277 | {.bs = 46, .dw = 16, .ce = 15}, 278 | {.bs = 50, .dw = 22, .ce = 14} 279 | } 280 | }, 281 | { /* Version 27 */ 282 | .data_bytes = 1828, 283 | .apat = {6, 34, 62, 90, 118, 0}, 284 | .ecc = { 285 | {.bs = 73, .dw = 45, .ce = 14}, 286 | {.bs = 152, .dw = 122, .ce = 15}, 287 | {.bs = 45, .dw = 15, .ce = 15}, 288 | {.bs = 53, .dw = 23, .ce = 15} 289 | } 290 | }, 291 | { /* Version 28 */ 292 | .data_bytes = 1921, 293 | .apat = {6, 26, 50, 74, 98, 122, 0}, 294 | .ecc = { 295 | {.bs = 73, .dw = 45, .ce = 14}, 296 | {.bs = 147, .dw = 117, .ce = 15}, 297 | {.bs = 45, .dw = 15, .ce = 15}, 298 | {.bs = 54, .dw = 24, .ce = 15} 299 | } 300 | }, 301 | { /* Version 29 */ 302 | .data_bytes = 2051, 303 | .apat = {6, 30, 54, 78, 102, 126, 0}, 304 | .ecc = { 305 | {.bs = 73, .dw = 45, .ce = 14}, 306 | {.bs = 146, .dw = 116, .ce = 15}, 307 | {.bs = 45, .dw = 15, .ce = 15}, 308 | {.bs = 73, .dw = 45, .ce = 14} 309 | } 310 | }, 311 | { /* Version 30 */ 312 | .data_bytes = 2185, 313 | .apat = {6, 26, 52, 78, 104, 130, 0}, 314 | .ecc = { 315 | {.bs = 75, .dw = 47, .ce = 14}, 316 | {.bs = 145, .dw = 115, .ce = 15}, 317 | {.bs = 45, .dw = 15, .ce = 15}, 318 | {.bs = 54, .dw = 24, .ce = 15} 319 | } 320 | }, 321 | { /* Version 31 */ 322 | .data_bytes = 2323, 323 | .apat = {6, 30, 56, 82, 108, 134, 0}, 324 | .ecc = { 325 | {.bs = 74, .dw = 46, .ce = 14}, 326 | {.bs = 145, .dw = 115, .ce = 15}, 327 | {.bs = 45, .dw = 15, .ce = 15}, 328 | {.bs = 54, .dw = 24, .ce = 15} 329 | } 330 | }, 331 | { /* Version 32 */ 332 | .data_bytes = 2465, 333 | .apat = {6, 34, 60, 86, 112, 138, 0}, 334 | .ecc = { 335 | {.bs = 74, .dw = 46, .ce = 14}, 336 | {.bs = 145, .dw = 115, .ce = 15}, 337 | {.bs = 45, .dw = 15, .ce = 15}, 338 | {.bs = 54, .dw = 24, .ce = 15} 339 | } 340 | }, 341 | { /* Version 33 */ 342 | .data_bytes = 2611, 343 | .apat = {6, 30, 58, 96, 114, 142, 0}, 344 | .ecc = { 345 | {.bs = 74, .dw = 46, .ce = 14}, 346 | {.bs = 145, .dw = 115, .ce = 15}, 347 | {.bs = 45, .dw = 15, .ce = 15}, 348 | {.bs = 54, .dw = 24, .ce = 15} 349 | } 350 | }, 351 | { /* Version 34 */ 352 | .data_bytes = 2761, 353 | .apat = {6, 34, 62, 90, 118, 146, 0}, 354 | .ecc = { 355 | {.bs = 74, .dw = 46, .ce = 14}, 356 | {.bs = 145, .dw = 115, .ce = 15}, 357 | {.bs = 46, .dw = 16, .ce = 15}, 358 | {.bs = 54, .dw = 24, .ce = 15} 359 | } 360 | }, 361 | { /* Version 35 */ 362 | .data_bytes = 2876, 363 | .apat = {6, 30, 54, 78, 102, 126, 150}, 364 | .ecc = { 365 | {.bs = 75, .dw = 47, .ce = 14}, 366 | {.bs = 151, .dw = 121, .ce = 15}, 367 | {.bs = 45, .dw = 15, .ce = 15}, 368 | {.bs = 54, .dw = 24, .ce = 15} 369 | } 370 | }, 371 | { /* Version 36 */ 372 | .data_bytes = 3034, 373 | .apat = {6, 24, 50, 76, 102, 128, 154}, 374 | .ecc = { 375 | {.bs = 75, .dw = 47, .ce = 14}, 376 | {.bs = 151, .dw = 121, .ce = 15}, 377 | {.bs = 45, .dw = 15, .ce = 15}, 378 | {.bs = 54, .dw = 24, .ce = 15} 379 | } 380 | }, 381 | { /* Version 37 */ 382 | .data_bytes = 3196, 383 | .apat = {6, 28, 54, 80, 106, 132, 158}, 384 | .ecc = { 385 | {.bs = 74, .dw = 46, .ce = 14}, 386 | {.bs = 152, .dw = 122, .ce = 15}, 387 | {.bs = 45, .dw = 15, .ce = 15}, 388 | {.bs = 54, .dw = 24, .ce = 15} 389 | } 390 | }, 391 | { /* Version 38 */ 392 | .data_bytes = 3362, 393 | .apat = {6, 32, 58, 84, 110, 136, 162}, 394 | .ecc = { 395 | {.bs = 74, .dw = 46, .ce = 14}, 396 | {.bs = 152, .dw = 122, .ce = 15}, 397 | {.bs = 45, .dw = 15, .ce = 15}, 398 | {.bs = 54, .dw = 24, .ce = 15} 399 | } 400 | }, 401 | { /* Version 39 */ 402 | .data_bytes = 3532, 403 | .apat = {6, 26, 54, 82, 110, 138, 166}, 404 | .ecc = { 405 | {.bs = 75, .dw = 47, .ce = 14}, 406 | {.bs = 147, .dw = 117, .ce = 15}, 407 | {.bs = 45, .dw = 15, .ce = 15}, 408 | {.bs = 54, .dw = 24, .ce = 15} 409 | } 410 | }, 411 | { /* Version 40 */ 412 | .data_bytes = 3706, 413 | .apat = {6, 30, 58, 86, 114, 142, 170}, 414 | .ecc = { 415 | {.bs = 75, .dw = 47, .ce = 14}, 416 | {.bs = 148, .dw = 118, .ce = 15}, 417 | {.bs = 45, .dw = 15, .ce = 15}, 418 | {.bs = 54, .dw = 24, .ce = 15} 419 | } 420 | } 421 | }; 422 | -------------------------------------------------------------------------------- /internal/quirc/tests/dbgutil.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "dbgutil.h" 22 | 23 | void dump_data(const struct quirc_data *data) 24 | { 25 | printf(" Version: %d\n", data->version); 26 | printf(" ECC level: %c\n", "MLHQ"[data->ecc_level]); 27 | printf(" Mask: %d\n", data->mask); 28 | printf(" Data type: %d\n", data->data_type); 29 | printf(" Length: %d\n", data->payload_len); 30 | printf(" Payload: %s\n", data->payload); 31 | } 32 | 33 | void dump_cells(const struct quirc_code *code) 34 | { 35 | int u, v; 36 | 37 | printf(" %d cells, corners:", code->size); 38 | for (u = 0; u < 4; u++) 39 | printf(" (%d,%d)", code->corners[u].x, 40 | code->corners[u].y); 41 | printf("\n"); 42 | 43 | for (v = 0; v < code->size; v++) { 44 | printf(" "); 45 | for (u = 0; u < code->size; u++) { 46 | int p = v * code->size + u; 47 | 48 | if (code->cell_bitmap[p >> 3] & (1 << (p & 7))) 49 | printf("[]"); 50 | else 51 | printf(" "); 52 | } 53 | printf("\n"); 54 | } 55 | } 56 | 57 | struct my_jpeg_error { 58 | struct jpeg_error_mgr base; 59 | jmp_buf env; 60 | }; 61 | 62 | static void my_output_message(struct jpeg_common_struct *com) 63 | { 64 | struct my_jpeg_error *err = (struct my_jpeg_error *)com->err; 65 | char buf[JMSG_LENGTH_MAX]; 66 | 67 | err->base.format_message(com, buf); 68 | fprintf(stderr, "JPEG error: %s", buf); 69 | } 70 | 71 | static void my_error_exit(struct jpeg_common_struct *com) 72 | { 73 | struct my_jpeg_error *err = (struct my_jpeg_error *)com->err; 74 | 75 | my_output_message(com); 76 | longjmp(err->env, 0); 77 | } 78 | 79 | static struct jpeg_error_mgr *my_error_mgr(struct my_jpeg_error *err) 80 | { 81 | jpeg_std_error(&err->base); 82 | 83 | err->base.error_exit = my_error_exit; 84 | err->base.output_message = my_output_message; 85 | 86 | return &err->base; 87 | } 88 | 89 | int load_jpeg(struct quirc *q, const char *filename) 90 | { 91 | FILE *infile = fopen(filename, "rb"); 92 | struct jpeg_decompress_struct dinfo; 93 | struct my_jpeg_error err; 94 | uint8_t *image; 95 | int y; 96 | 97 | if (!infile) { 98 | perror("can't open input file"); 99 | return -1; 100 | } 101 | 102 | memset(&dinfo, 0, sizeof(dinfo)); 103 | dinfo.err = my_error_mgr(&err); 104 | 105 | if (setjmp(err.env)) 106 | goto fail; 107 | 108 | jpeg_create_decompress(&dinfo); 109 | jpeg_stdio_src(&dinfo, infile); 110 | 111 | jpeg_read_header(&dinfo, TRUE); 112 | dinfo.output_components = 1; 113 | dinfo.out_color_space = JCS_GRAYSCALE; 114 | jpeg_start_decompress(&dinfo); 115 | 116 | if (dinfo.output_components != 1) { 117 | fprintf(stderr, "Unexpected number of output components: %d", 118 | dinfo.output_components); 119 | goto fail; 120 | } 121 | 122 | if (quirc_resize(q, dinfo.output_width, dinfo.output_height) < 0) 123 | goto fail; 124 | 125 | image = quirc_begin(q, NULL, NULL); 126 | 127 | for (y = 0; y < dinfo.output_height; y++) { 128 | JSAMPROW row_pointer = image + y * dinfo.output_width; 129 | 130 | jpeg_read_scanlines(&dinfo, &row_pointer, 1); 131 | } 132 | 133 | fclose(infile); 134 | jpeg_finish_decompress(&dinfo); 135 | jpeg_destroy_decompress(&dinfo); 136 | return 0; 137 | 138 | fail: 139 | fclose(infile); 140 | jpeg_destroy_decompress(&dinfo); 141 | return -1; 142 | } 143 | -------------------------------------------------------------------------------- /internal/quirc/tests/dbgutil.h: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef DBGUTIL_H_ 18 | #define DBGUTIL_H_ 19 | 20 | #include "quirc.h" 21 | 22 | /* Dump decoded information on stdout. */ 23 | void dump_data(const struct quirc_data *data); 24 | 25 | /* Dump a grid cell map on stdout. */ 26 | void dump_cells(const struct quirc_code *code); 27 | 28 | /* Read a JPEG image into the decoder. 29 | * 30 | * Note that you must call quirc_end() if the function returns 31 | * successfully (0). 32 | */ 33 | int load_jpeg(struct quirc *q, const char *filename); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /internal/quirc/tests/inspect.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "quirc_internal.h" 22 | #include "dbgutil.h" 23 | 24 | static void dump_info(struct quirc *q) 25 | { 26 | int count = quirc_count(q); 27 | int i; 28 | 29 | printf("%d QR-codes found:\n\n", count); 30 | for (i = 0; i < count; i++) { 31 | struct quirc_code code; 32 | struct quirc_data data; 33 | quirc_decode_error_t err; 34 | 35 | quirc_extract(q, i, &code); 36 | err = quirc_decode(&code, &data); 37 | 38 | dump_cells(&code); 39 | printf("\n"); 40 | 41 | if (err) { 42 | printf(" Decoding FAILED: %s\n", quirc_strerror(err)); 43 | } else { 44 | printf(" Decoding successful:\n"); 45 | dump_data(&data); 46 | } 47 | 48 | printf("\n"); 49 | } 50 | } 51 | 52 | static void draw_frame(SDL_Surface *screen, struct quirc *q) 53 | { 54 | uint8_t *pix; 55 | uint8_t *raw = q->image; 56 | int x, y; 57 | 58 | SDL_LockSurface(screen); 59 | pix = screen->pixels; 60 | for (y = 0; y < q->h; y++) { 61 | uint32_t *row = (uint32_t *)pix; 62 | 63 | for (x = 0; x < q->w; x++) { 64 | uint8_t v = *(raw++); 65 | uint32_t color = (v << 16) | (v << 8) | v; 66 | struct quirc_region *reg = &q->regions[v]; 67 | 68 | switch (v) { 69 | case QUIRC_PIXEL_WHITE: 70 | color = 0x00ffffff; 71 | break; 72 | 73 | case QUIRC_PIXEL_BLACK: 74 | color = 0x00000000; 75 | break; 76 | 77 | default: 78 | if (reg->capstone >= 0) 79 | color = 0x00008000; 80 | else 81 | color = 0x00808080; 82 | break; 83 | } 84 | 85 | *(row++) = color; 86 | } 87 | 88 | pix += screen->pitch; 89 | } 90 | SDL_UnlockSurface(screen); 91 | } 92 | 93 | static void draw_blob(SDL_Surface *screen, int x, int y) 94 | { 95 | int i, j; 96 | 97 | for (i = -2; i <= 2; i++) 98 | for (j = -2; j <= 2; j++) 99 | pixelColor(screen, x + i, y + j, 0x0000ffff); 100 | } 101 | 102 | static void draw_mark(SDL_Surface *screen, int x, int y) 103 | { 104 | pixelColor(screen, x, y, 0xff0000ff); 105 | pixelColor(screen, x + 1, y, 0xff0000ff); 106 | pixelColor(screen, x - 1, y, 0xff0000ff); 107 | pixelColor(screen, x, y + 1, 0xff0000ff); 108 | pixelColor(screen, x, y - 1, 0xff0000ff); 109 | } 110 | 111 | static void draw_capstone(SDL_Surface *screen, struct quirc *q, int index) 112 | { 113 | struct quirc_capstone *cap = &q->capstones[index]; 114 | int j; 115 | char buf[8]; 116 | 117 | for (j = 0; j < 4; j++) { 118 | struct quirc_point *p0 = &cap->corners[j]; 119 | struct quirc_point *p1 = &cap->corners[(j + 1) % 4]; 120 | 121 | lineColor(screen, p0->x, p0->y, p1->x, p1->y, 122 | 0x800080ff); 123 | } 124 | 125 | draw_blob(screen, cap->corners[0].x, cap->corners[0].y); 126 | 127 | if (cap->qr_grid < 0) { 128 | snprintf(buf, sizeof(buf), "?%d", index); 129 | stringColor(screen, cap->center.x, cap->center.y, buf, 130 | 0x000000ff); 131 | } 132 | } 133 | 134 | static void perspective_map(const double *c, 135 | double u, double v, struct quirc_point *ret) 136 | { 137 | double den = c[6]*u + c[7]*v + 1.0; 138 | double x = (c[0]*u + c[1]*v + c[2]) / den; 139 | double y = (c[3]*u + c[4]*v + c[5]) / den; 140 | 141 | ret->x = rint(x); 142 | ret->y = rint(y); 143 | } 144 | 145 | static void draw_grid(SDL_Surface *screen, struct quirc *q, int index) 146 | { 147 | struct quirc_grid *qr = &q->grids[index]; 148 | int x, y; 149 | int i; 150 | 151 | for (i = 0; i < 3; i++) { 152 | struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; 153 | char buf[8]; 154 | 155 | snprintf(buf, sizeof(buf), "%d.%c", index, "ABC"[i]); 156 | stringColor(screen, cap->center.x, cap->center.y, buf, 157 | 0x000000ff); 158 | } 159 | 160 | lineColor(screen, qr->tpep[0].x, qr->tpep[0].y, 161 | qr->tpep[1].x, qr->tpep[1].y, 0xff00ffff); 162 | lineColor(screen, qr->tpep[1].x, qr->tpep[1].y, 163 | qr->tpep[2].x, qr->tpep[2].y, 0xff00ffff); 164 | 165 | if (qr->align_region >= 0) 166 | draw_blob(screen, qr->align.x, qr->align.y); 167 | 168 | for (y = 0; y < qr->grid_size; y++) { 169 | for (x = 0; x < qr->grid_size; x++) { 170 | double u = x + 0.5; 171 | double v = y + 0.5; 172 | struct quirc_point p; 173 | 174 | perspective_map(qr->c, u, v, &p); 175 | draw_mark(screen, p.x, p.y); 176 | } 177 | } 178 | } 179 | 180 | static int sdl_examine(struct quirc *q) 181 | { 182 | SDL_Surface *screen; 183 | SDL_Event ev; 184 | 185 | if (SDL_Init(SDL_INIT_VIDEO) < 0) { 186 | fprintf(stderr, "couldn't init SDL: %s\n", SDL_GetError()); 187 | return -1; 188 | } 189 | 190 | screen = SDL_SetVideoMode(q->w, q->h, 32, SDL_SWSURFACE); 191 | if (!screen) { 192 | fprintf(stderr, "couldn't init video mode: %s\n", 193 | SDL_GetError()); 194 | return -1; 195 | } 196 | 197 | while (SDL_WaitEvent(&ev) >= 0) { 198 | int i; 199 | 200 | if (ev.type == SDL_QUIT) 201 | break; 202 | 203 | if (ev.type == SDL_KEYDOWN && 204 | ev.key.keysym.sym == 'q') 205 | break; 206 | 207 | draw_frame(screen, q); 208 | for (i = 0; i < q->num_capstones; i++) 209 | draw_capstone(screen, q, i); 210 | for (i = 0; i < q->num_grids; i++) 211 | draw_grid(screen, q, i); 212 | SDL_Flip(screen); 213 | } 214 | 215 | SDL_Quit(); 216 | return 0; 217 | } 218 | 219 | int main(int argc, char **argv) 220 | { 221 | struct quirc *q; 222 | 223 | printf("quirc inspection program\n"); 224 | printf("Copyright (C) 2010-2012 Daniel Beer \n"); 225 | printf("Library version: %s\n", quirc_version()); 226 | printf("\n"); 227 | 228 | if (argc < 2) { 229 | fprintf(stderr, "Usage: %s \n", argv[0]); 230 | return -1; 231 | } 232 | 233 | q = quirc_new(); 234 | if (!q) { 235 | perror("can't create quirc object"); 236 | return -1; 237 | } 238 | 239 | if (load_jpeg(q, argv[1]) < 0) { 240 | quirc_destroy(q); 241 | return -1; 242 | } 243 | 244 | quirc_end(q); 245 | dump_info(q); 246 | 247 | if (sdl_examine(q) < 0) { 248 | quirc_destroy(q); 249 | return -1; 250 | } 251 | 252 | quirc_destroy(q); 253 | return 0; 254 | } 255 | -------------------------------------------------------------------------------- /internal/quirc/tests/qrtest.c: -------------------------------------------------------------------------------- 1 | /* quirc -- QR-code recognition library 2 | * Copyright (C) 2010-2012 Daniel Beer 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "dbgutil.h" 30 | 31 | static int want_verbose = 0; 32 | static int want_cell_dump = 0; 33 | 34 | #define CLOCK_TO_MS(c) ((c) / (CLOCKS_PER_SEC / 1000)) 35 | 36 | static struct quirc *decoder; 37 | 38 | struct result_info { 39 | int file_count; 40 | int id_count; 41 | int decode_count; 42 | 43 | clock_t load_time; 44 | clock_t identify_time; 45 | clock_t total_time; 46 | }; 47 | 48 | static void print_result(const char *name, struct result_info *info) 49 | { 50 | puts("----------------------------------------" 51 | "---------------------------------------"); 52 | printf("%s: %d files, %d codes, %d decoded (%d failures)", 53 | name, info->file_count, info->id_count, info->decode_count, 54 | (info->id_count - info->decode_count)); 55 | if (info->id_count) 56 | printf(", %d%% success rate", 57 | (info->decode_count * 100 + info->id_count / 2) / 58 | info->id_count); 59 | printf("\n"); 60 | printf("Total time [load: %ld, identify: %ld, total: %ld]\n", 61 | CLOCK_TO_MS(info->load_time), 62 | CLOCK_TO_MS(info->identify_time), 63 | CLOCK_TO_MS(info->total_time)); 64 | if (info->file_count) 65 | printf("Average time [load: %ld, identify: %ld, total: %ld]\n", 66 | CLOCK_TO_MS(info->load_time / info->file_count), 67 | CLOCK_TO_MS(info->identify_time / info->file_count), 68 | CLOCK_TO_MS(info->total_time / info->file_count)); 69 | } 70 | 71 | static void add_result(struct result_info *sum, struct result_info *inf) 72 | { 73 | sum->file_count += inf->file_count; 74 | sum->id_count += inf->id_count; 75 | sum->decode_count += inf->decode_count; 76 | 77 | sum->load_time += inf->load_time; 78 | sum->identify_time += inf->identify_time; 79 | sum->total_time += inf->total_time; 80 | } 81 | 82 | static int scan_file(const char *path, const char *filename, 83 | struct result_info *info) 84 | { 85 | int len = strlen(filename); 86 | const char *ext; 87 | clock_t start; 88 | clock_t total_start; 89 | int ret; 90 | int i; 91 | 92 | while (len >= 0 && filename[len] != '.') 93 | len--; 94 | ext = filename + len + 1; 95 | if (!(strcasecmp(ext, "jpg") || strcasecmp(ext, "jpeg"))) 96 | return 0; 97 | 98 | total_start = start = clock(); 99 | ret = load_jpeg(decoder, path); 100 | info->load_time = clock() - start; 101 | 102 | if (ret < 0) { 103 | fprintf(stderr, "%s: load_jpeg failed\n", filename); 104 | return -1; 105 | } 106 | 107 | start = clock(); 108 | quirc_end(decoder); 109 | info->identify_time = clock() - start; 110 | 111 | info->id_count = quirc_count(decoder); 112 | for (i = 0; i < info->id_count; i++) { 113 | struct quirc_code code; 114 | struct quirc_data data; 115 | 116 | quirc_extract(decoder, i, &code); 117 | 118 | if (!quirc_decode(&code, &data)) 119 | info->decode_count++; 120 | } 121 | 122 | info->total_time += clock() - total_start; 123 | 124 | printf(" %-30s: %5ld %5ld %5ld %5d %5d\n", filename, 125 | CLOCK_TO_MS(info->load_time), 126 | CLOCK_TO_MS(info->identify_time), 127 | CLOCK_TO_MS(info->total_time), 128 | info->id_count, info->decode_count); 129 | 130 | if (want_cell_dump || want_verbose) { 131 | for (i = 0; i < info->id_count; i++) { 132 | struct quirc_code code; 133 | 134 | quirc_extract(decoder, i, &code); 135 | if (want_cell_dump) { 136 | dump_cells(&code); 137 | printf("\n"); 138 | } 139 | 140 | if (want_verbose) { 141 | struct quirc_data data; 142 | quirc_decode_error_t err = 143 | quirc_decode(&code, &data); 144 | 145 | if (err) { 146 | printf(" ERROR: %s\n\n", 147 | quirc_strerror(err)); 148 | } else { 149 | printf(" Decode successful:\n"); 150 | dump_data(&data); 151 | printf("\n"); 152 | } 153 | } 154 | } 155 | } 156 | 157 | info->file_count = 1; 158 | return 1; 159 | } 160 | 161 | static int test_scan(const char *path, struct result_info *info); 162 | 163 | static int scan_dir(const char *path, const char *filename, 164 | struct result_info *info) 165 | { 166 | DIR *d = opendir(path); 167 | struct dirent *ent; 168 | int count = 0; 169 | 170 | if (!d) { 171 | fprintf(stderr, "%s: opendir: %s\n", path, strerror(errno)); 172 | return -1; 173 | } 174 | 175 | printf("%s:\n", path); 176 | 177 | while ((ent = readdir(d))) { 178 | if (ent->d_name[0] != '.') { 179 | char fullpath[1024]; 180 | struct result_info sub; 181 | 182 | snprintf(fullpath, sizeof(fullpath), "%s/%s", 183 | path, ent->d_name); 184 | if (test_scan(fullpath, &sub) > 0) { 185 | add_result(info, &sub); 186 | count++; 187 | } 188 | } 189 | } 190 | 191 | closedir(d); 192 | 193 | if (count > 1) { 194 | print_result(filename, info); 195 | puts(""); 196 | } 197 | 198 | return count > 0; 199 | } 200 | 201 | static int test_scan(const char *path, struct result_info *info) 202 | { 203 | int len = strlen(path); 204 | struct stat st; 205 | const char *filename; 206 | 207 | memset(info, 0, sizeof(*info)); 208 | 209 | while (len >= 0 && path[len] != '/') 210 | len--; 211 | filename = path + len + 1; 212 | 213 | if (lstat(path, &st) < 0) { 214 | fprintf(stderr, "%s: lstat: %s\n", path, strerror(errno)); 215 | return -1; 216 | } 217 | 218 | if (S_ISREG(st.st_mode)) 219 | return scan_file(path, filename, info); 220 | 221 | if (S_ISDIR(st.st_mode)) 222 | return scan_dir(path, filename, info); 223 | 224 | return 0; 225 | } 226 | 227 | static int run_tests(int argc, char **argv) 228 | { 229 | struct result_info sum; 230 | int count = 0; 231 | int i; 232 | 233 | decoder = quirc_new(); 234 | if (!decoder) { 235 | perror("quirc_new"); 236 | return -1; 237 | } 238 | 239 | printf(" %-30s %17s %11s\n", "", "Time (ms)", "Count"); 240 | printf(" %-30s %5s %5s %5s %5s %5s\n", 241 | "Filename", "Load", "ID", "Total", "ID", "Dec"); 242 | puts("----------------------------------------" 243 | "---------------------------------------"); 244 | 245 | memset(&sum, 0, sizeof(sum)); 246 | for (i = 0; i < argc; i++) { 247 | struct result_info info; 248 | 249 | if (test_scan(argv[i], &info) > 0) { 250 | add_result(&sum, &info); 251 | count++; 252 | } 253 | } 254 | 255 | if (count > 1) 256 | print_result("TOTAL", &sum); 257 | 258 | quirc_destroy(decoder); 259 | return 0; 260 | } 261 | 262 | int main(int argc, char **argv) 263 | { 264 | int opt; 265 | 266 | printf("quirc test program\n"); 267 | printf("Copyright (C) 2010-2012 Daniel Beer \n"); 268 | printf("Library version: %s\n", quirc_version()); 269 | printf("\n"); 270 | 271 | while ((opt = getopt(argc, argv, "vd")) >= 0) 272 | switch (opt) { 273 | case 'v': 274 | want_verbose = 1; 275 | break; 276 | 277 | case 'd': 278 | want_cell_dump = 1; 279 | break; 280 | 281 | case '?': 282 | return -1; 283 | } 284 | 285 | argv += optind; 286 | argc -= optind; 287 | 288 | return run_tests(argc, argv);; 289 | } 290 | -------------------------------------------------------------------------------- /testdata/01-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/01-1.jpg -------------------------------------------------------------------------------- /testdata/01-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/01-2.jpg -------------------------------------------------------------------------------- /testdata/01-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/01-3.jpg -------------------------------------------------------------------------------- /testdata/01-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/01-4.jpg -------------------------------------------------------------------------------- /testdata/02-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/02-1.jpg -------------------------------------------------------------------------------- /testdata/02-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/02-2.jpg -------------------------------------------------------------------------------- /testdata/02-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/02-3.jpg -------------------------------------------------------------------------------- /testdata/02-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/02-4.jpg -------------------------------------------------------------------------------- /testdata/03-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/03-1.jpg -------------------------------------------------------------------------------- /testdata/03-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/03-2.jpg -------------------------------------------------------------------------------- /testdata/03-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/03-3.jpg -------------------------------------------------------------------------------- /testdata/03-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/03-4.jpg -------------------------------------------------------------------------------- /testdata/04-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/04-1.jpg -------------------------------------------------------------------------------- /testdata/04-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/04-2.jpg -------------------------------------------------------------------------------- /testdata/04-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/04-3.jpg -------------------------------------------------------------------------------- /testdata/04-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/04-4.jpg -------------------------------------------------------------------------------- /testdata/05-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/05-1.jpg -------------------------------------------------------------------------------- /testdata/05-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/05-2.jpg -------------------------------------------------------------------------------- /testdata/05-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/05-3.jpg -------------------------------------------------------------------------------- /testdata/05-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/05-4.jpg -------------------------------------------------------------------------------- /testdata/06-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/06-1.jpg -------------------------------------------------------------------------------- /testdata/06-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/06-2.jpg -------------------------------------------------------------------------------- /testdata/06-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/06-3.jpg -------------------------------------------------------------------------------- /testdata/06-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/06-4.jpg -------------------------------------------------------------------------------- /testdata/125.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/125.bmp -------------------------------------------------------------------------------- /testdata/out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/out.png -------------------------------------------------------------------------------- /testdata/qart1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart1.png -------------------------------------------------------------------------------- /testdata/qart10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart10.png -------------------------------------------------------------------------------- /testdata/qart11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart11.png -------------------------------------------------------------------------------- /testdata/qart12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart12.png -------------------------------------------------------------------------------- /testdata/qart13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart13.png -------------------------------------------------------------------------------- /testdata/qart14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart14.png -------------------------------------------------------------------------------- /testdata/qart15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart15.png -------------------------------------------------------------------------------- /testdata/qart2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart2.png -------------------------------------------------------------------------------- /testdata/qart3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart3.png -------------------------------------------------------------------------------- /testdata/qart4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart4.png -------------------------------------------------------------------------------- /testdata/qart5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart5.png -------------------------------------------------------------------------------- /testdata/qart6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart6.png -------------------------------------------------------------------------------- /testdata/qart7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart7.png -------------------------------------------------------------------------------- /testdata/qart8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart8.png -------------------------------------------------------------------------------- /testdata/qart9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qart9.png -------------------------------------------------------------------------------- /testdata/qr-bbc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qr-bbc.png -------------------------------------------------------------------------------- /testdata/qr-bbc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qr-bbc1.png -------------------------------------------------------------------------------- /testdata/qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qr.png -------------------------------------------------------------------------------- /testdata/qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kdar/goquirc/467c1664402acc7b6219dfabe62ec16d0dbb9233/testdata/qrcode.jpg --------------------------------------------------------------------------------