diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 00:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 00:06:44 +0000 |
commit | 44cf8ec67278bd1ab6c7f83a9993f7a5686a9541 (patch) | |
tree | 5eec4b0d1a3f163d279c3c27c03324ba49fa235a /test | |
parent | Initial commit. (diff) | |
download | zbar-upstream.tar.xz zbar-upstream.zip |
Adding upstream version 0.23.93.upstream/0.23.93upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test')
-rw-r--r-- | test/Makefile.am.inc | 162 | ||||
-rwxr-xr-x | test/barcodetest.py | 413 | ||||
-rw-r--r-- | test/check_dbus.sh.in | 39 | ||||
-rw-r--r-- | test/dbg_scan.cpp | 218 | ||||
-rw-r--r-- | test/pdf417_encode.h | 4674 | ||||
-rw-r--r-- | test/test_convert.c | 60 | ||||
-rw-r--r-- | test/test_cpp.cpp | 43 | ||||
-rw-r--r-- | test/test_cpp_img.cpp | 214 | ||||
-rw-r--r-- | test/test_dbus.c | 254 | ||||
-rw-r--r-- | test/test_decode.c | 1356 | ||||
-rw-r--r-- | test/test_examples.sh.in | 91 | ||||
-rwxr-xr-x | test/test_gi.py | 216 | ||||
-rw-r--r-- | test/test_images.c | 533 | ||||
-rw-r--r-- | test/test_images.h | 46 | ||||
-rw-r--r-- | test/test_jpeg.c | 158 | ||||
-rwxr-xr-x | test/test_perl.pl | 47 | ||||
-rw-r--r-- | test/test_proc.c | 170 | ||||
-rwxr-xr-x | test/test_pygtk.py | 193 | ||||
-rwxr-xr-x | test/test_python.py | 64 | ||||
-rw-r--r-- | test/test_video.c | 237 | ||||
-rw-r--r-- | test/test_window.c | 98 |
21 files changed, 9286 insertions, 0 deletions
diff --git a/test/Makefile.am.inc b/test/Makefile.am.inc new file mode 100644 index 0000000..55b9814 --- /dev/null +++ b/test/Makefile.am.inc @@ -0,0 +1,162 @@ +check_PROGRAMS += test/test_decode +test_test_decode_SOURCES = test/test_decode.c test/pdf417_encode.h +test_test_decode_CFLAGS = -Wno-unused $(AM_CFLAGS) +test_test_decode_LDADD = zbar/libzbar.la $(AM_LDADD) + +TEST_IMAGE_SOURCES = test/test_images.c test/test_images.h + +check_PROGRAMS += test/test_convert +test_test_convert_SOURCES = test/test_convert.c $(TEST_IMAGE_SOURCES) +test_test_convert_LDADD = zbar/libzbar.la $(AM_LDADD) + +#check_PROGRAMS += test/test_window +#test_test_window_SOURCES = test/test_window.c $(TEST_IMAGE_SOURCES) +#test_test_window_CPPFLAGS = -I$(srcdir)/zbar $(AM_CPPFLAGS) +#test_test_window_LDADD = zbar/libzbar.la $(AM_LDADD) + +if HAVE_VIDEO +check_PROGRAMS += test/test_video +test_test_video_SOURCES = test/test_video.c $(TEST_IMAGE_SOURCES) +test_test_video_LDADD = zbar/libzbar.la $(AM_LDADD) +endif + +check_PROGRAMS += test/test_proc +test_test_proc_SOURCES = test/test_proc.c $(TEST_IMAGE_SOURCES) +test_test_proc_LDADD = zbar/libzbar.la $(AM_LDADD) + +check_PROGRAMS += test/test_cpp +test_test_cpp_SOURCES = test/test_cpp.cpp +test_test_cpp_LDADD = zbar/libzbar.la $(AM_LDADD) + +check_PROGRAMS += test/test_cpp_img +test_test_cpp_img_SOURCES = test/test_cpp_img.cpp $(TEST_IMAGE_SOURCES) +test_test_cpp_img_LDADD = zbar/libzbar.la $(AM_LDADD) + +if HAVE_JPEG +check_PROGRAMS += test/test_jpeg +test_test_jpeg_SOURCES = test/test_jpeg.c +test_test_jpeg_LDADD = zbar/libzbar.la $(AM_LDADD) +endif + +if HAVE_MAGICK +EXTRA_PROGRAMS += test/dbg_scan +test_dbg_scan_SOURCES = test/dbg_scan.cpp +test_dbg_scan_CPPFLAGS = $(MAGICK_CFLAGS) $(AM_CPPFLAGS) +test_dbg_scan_LDADD = $(MAGICK_LIBS) -lMagick++ zbar/libzbar.la $(AM_LDADD) +endif + +if HAVE_DBUS +check_PROGRAMS += test/test_dbus +test_test_dbus_SOURCES = test/test_dbus.c +test_test_dbus_LDFLAGS = $(DBUS_LIBS) +endif + +EXTRA_DIST += test/test_pygtk.py test/test_perl.pl test/test_gi.py test/test_python.py + +# automake bug in "monolithic mode"? +CLEANFILES += test/.libs/test_decode test/.libs/test_proc \ + test/.libs/test_convert test/.libs/test_window \ + test/.libs/test_video test/.libs/dbg_scan test/.libs/test_gtk + + +# Images that work out of the box without needing to enable +# an specific symbology +NORMAL_IMAGES = codabar.png code-128.png code-39.png code-93.png \ + databar.png databar-exp.png ean-13.png ean-8.png i2-5.png \ + qr-code.png sqcode1-generated.png sqcode1-scanned.png + +EXAMPLES = @abs_top_builddir@/examples +ZBARIMG = @abs_top_builddir@/zbarimg/zbarimg --nodbus + +gen_checksum: all + for i in $(NORMAL_IMAGES); do $(ZBARIMG) $(EXAMPLES)/$$i 2>/dev/null|sha1sum|sed "s,-,zbarimg $$i,"; done >$(EXAMPLES)/sha1sum + $(ZBARIMG) -Sean2.enable $(EXAMPLES)/ean-2.png 2>/dev/null|sha1sum|sed "s,-,zbarimg -Sean2.enable ean-2.png," >>$(EXAMPLES)/sha1sum + $(ZBARIMG) -Sean5.enable $(EXAMPLES)/ean-5.png 2>/dev/null|sha1sum|sed "s,-,zbarimg -Sean5.enable ean-5.png," >>$(EXAMPLES)/sha1sum + $(ZBARIMG) -Sisbn10.enable $(EXAMPLES)/ean-13.png 2>/dev/null|sha1sum|sed "s,-,zbarimg -Sisbn10.enable ean-13.png," >>$(EXAMPLES)/sha1sum + $(ZBARIMG) -Sisbn13.enable $(EXAMPLES)/ean-13.png 2>/dev/null|sha1sum|sed "s,-,zbarimg -Sisbn13.enable ean-13.png," >>$(EXAMPLES)/sha1sum + $(ZBARIMG) -Supca.enable $(EXAMPLES)/code-upc-a.png 2>/dev/null|sha1sum|sed "s,-,zbarimg -Supca.enable code-upc-a.png," >>$(EXAMPLES)/sha1sum + $(ZBARIMG) -Stest-inverted $(EXAMPLES)/qr-code-inverted.png 2>/dev/null|sha1sum|sed "s,-,zbarimg -Stest-inverted qr-code-inverted.png," >>$(EXAMPLES)/sha1sum + $(ZBARIMG) --raw -Sbinary $(EXAMPLES)/qr-code-binary.png 2>/dev/null|head -c -1|sha1sum|sed "s,-,zbarimg --raw -Sbinary qr-code-binary.png," >>$(EXAMPLES)/sha1sum + +test_progs: $(check_PROGRAMS) + @$(MAKE) $(check_PROGRAMS) + +# Require X11 to work +check-cpp: test/test_cpp_img + @abs_top_builddir@/test/test_cpp_img + +check-decoder: test/test_decode + @abs_top_builddir@/test/test_decode -q + +regress-decoder: test/test_decode + @abs_top_builddir@/test/test_decode -q -n 100000 + +check-images-py: zbarimg/zbarimg + @PYTHON@ @abs_top_srcdir@/test/barcodetest.py + +check-images: zbarimg/zbarimg + @abs_top_builddir@/test/test_examples.sh + +check-convert: test/test_convert + @abs_top_srcdir@/test/test_convert + @if [ "`sha1sum /tmp/base.I420.zimg |cut -d' ' -f 1`" != \ + "d697b0bb84617bef0f6413b3e5537ee38ba92312" ]; then \ + echo "convert FAILED"; else echo "convert PASSED."; fi + @rm /tmp/base.I420.zimg 2>/dev/null + +if HAVE_PYGTK2 +check-pygtk: pygtk/zbarpygtk.la + PYTHONPATH=@abs_top_srcdir@/pygtk/.libs/ \ + @PYTHON@ @abs_top_srcdir@/test/test_pygtk.py +else +check-pygtk: +endif + +if HAVE_PYTHON +check-python: python/zbar.la + PYTHONPATH=@abs_top_srcdir@/python/.libs/ \ + @PYTHON@ @abs_top_srcdir@/test/test_python.py \ + '@abs_top_srcdir@/examples/ean-13.png' '9789876543217' +else +check-python: +endif + +check-gi: gtk/ZBar-1.0.typelib + LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):@abs_top_srcdir@/gtk/.libs:@abs_top_srcdir@/zbar/.libs \ + GI_TYPELIB_PATH=@abs_top_srcdir@/gtk/ \ + @PYTHON@ @abs_top_srcdir@/test/test_gi.py + +# Require a camera device for it to work +check-video: test/test_video + if [ -d /dev/video0 ]; then @abs_top_srcdir@/test/test_video -q; fi + +check-jpeg: test/test_jpeg + @abs_top_srcdir@/test/test_jpeg -q + +if HAVE_DBUS +# Require a working D-Bus - may fail with containers +check-dbus: test/test_dbus + @abs_top_builddir@/test/check_dbus.sh +else +check-dbus: +endif + +if HAVE_JAVA_UNIT +check-java: zbar/libzbar.la + JAVA_HOME=${JAVA_HOME} $(MAKE) -C java check-java +else +check-java: +endif + +regress: regress-decoder + +check-local: check-images-py check-decoder check-images check-java \ + check-python regress + +other-tests: check-cpp check-convert check-video check-jpeg + +tests: check-local check-dbus other-tests + +.NOTPARALLEL: check-local regress tests + +PHONY += gen_checksum check-cpp check-decoder check-images check-dbus regress-decoder regress-images regress diff --git a/test/barcodetest.py b/test/barcodetest.py new file mode 100755 index 0000000..295832e --- /dev/null +++ b/test/barcodetest.py @@ -0,0 +1,413 @@ +#!/usr/bin/env python +# pylint: disable=C0103,C0114,C0115,C0116,C0209,R0912,R0915,W0511,W0603,W0613,W0707,W0212 + +from __future__ import print_function + +import re +import sys +import unittest as UT +import xml.etree.ElementTree as ET + +from errno import EISDIR, EINVAL, EACCES +from io import StringIO +from os import path, getcwd +from subprocess import Popen, PIPE +from traceback import format_exception + +try: + from urllib.error import HTTPError + from urllib.parse import urljoin, urlunparse + from urllib.request import urlopen +except ImportError: + from urllib2 import urlopen, HTTPError + from urlparse import urljoin, urlunparse + +debug = False + +# program to run - None means we still need to search for it +zbarimg = None +# arguments to said program +zbarimg_args = ['-q', '--xml', '--nodbus'] + + +# namespace support +try: + register_namespace = ET.register_namespace +except AttributeError: + def register_namespace(prefix, uri): + ET._namespace_map[uri] = prefix + +# barcode results +BC = 'http://zbar.sourceforge.net/2008/barcode' +register_namespace('bc', BC) + +# testcase extensions +TS = 'http://zbar.sourceforge.net/2009/test-spec' +register_namespace('test', TS) + + +# printing support +def fixtag(node): + return str(node.tag).split('}', 1)[-1] + + +def toxml(node): + s = StringIO() + ET.ElementTree(node).write(s) + return s.getvalue() + + +def hexdump(data): + print(data) + c = 0 + for i, c in enumerate(data): + if i & 0x7 == 0: + print('[%04x]' % i, end=' ') + print(' %04x' % ord(c), end=' ') + if i & 0x7 == 0x7: + print() + if len(c) & 0x7 != 0x7: + print('\n') + + +# search for a file in the distribution +def distdir_search(search_subdir, base, suffixes=('',)): + # start with current dir, + # then try script invocation path + rundir = path.dirname(sys.argv[0]) + search = ['', rundir] + + # finally, attempt to follow VPATH if present + try: + with open('Makefile', 'r') as makefile: + for line in makefile: + if re.match(r'^VPATH\s*=', line): + vpath = line.split('=', 1)[1].strip() + if vpath and vpath != rundir: + search.append(vpath) + break + except IOError: + pass + + # poke around for subdir + subdirs = tuple((search_subdir, path.join('..', search_subdir), '..', '')) + + for prefix in search: + for subdir in subdirs: + for suffix in suffixes: + file = path.realpath(path.join(prefix, subdir, base + suffix)) + if path.isfile(file): + return file + return None + + +def find_zbarimg(): + """search for zbarimg program to run. + """ + global zbarimg + # look in dist dir first + zbarimg = distdir_search('zbarimg', 'zbarimg', ('', '.exe')) + if not zbarimg: + # fall back to PATH + zbarimg = 'zbarimg' + if debug: + print('using zbarimg from PATH') + elif debug: + print('using:', zbarimg) + + +def run_zbarimg(images): + """invoke zbarimg for the specified files. + + return results as an ET.Element + """ + args = [zbarimg] + args.extend(zbarimg_args) + args.extend(images) + if debug: + print('running:', ' '.join(args)) + + # FIXME should be able to pipe (feed) parser straight from output + child = Popen(args, stdout=PIPE, stderr=PIPE) + (xml, err) = child.communicate() + + rc = child.returncode + if debug: + print('zbarimg returned', rc) + + # FIXME trim usage from error msg + assert rc in (0, 4), \ + 'zbarimg returned error status (%d):\n\t%s\n' % (rc, str(err.decode())) + + assert not err, err + + result = ET.XML(xml) + assert result.tag == ET.QName(BC, 'barcodes') + return result + + +class TestCase(UT.TestCase): + """single barcode source test. + + must have source attribute set to an ET.Element representation of a + bc:source tag before test is run. + """ + + def __init__(self, methodName): + UT.TestCase.__init__(self, methodName) + self.source = None + + def shortDescription(self): + return self.source.get('href') + + def setUp(self): + if not zbarimg: + find_zbarimg() + + def runTest(self): + expect = self.source + assert expect is not None + assert expect.tag == ET.QName(BC, 'source') + actual = run_zbarimg((expect.get('href'),)) + + self.assertEqual(len(actual), 1) + + try: + compare_sources(expect, actual[0]) + except AssertionError: + if expect.get(str(ET.QName(TS, 'exception'))) != 'TODO': + raise + # ignore + + +class BuiltinTestCase(TestCase): + def __init__(self, methodName='runTest'): + TestCase.__init__(self, methodName) + + href = distdir_search('examples', 'ean-13.png') + if not href: + href = 'https://git.linuxtv.org/zbar.git/plain/examples/ean-13.png' + + self.source = src = ET.Element(ET.QName(BC, 'source'), href=href) + sym = ET.SubElement(src, ET.QName(BC, 'symbol'), type='EAN-13', + orientation='UP') + data = ET.SubElement(sym, ET.QName(BC, 'data')) + data.text = '9789876543217' + + +def compare_maps(expect, actual, compare_func): + errors = [] + notes = [] + for key, iact in actual.items(): + iexp = expect.pop(key, None) + if iexp is None: + errors.append('bonus unexpected result:\n' + toxml(iact)) + continue + + try: + compare_func(iexp, iact) + except BaseException: + errors.append(''.join(format_exception(*sys.exc_info()))) + + if iexp.get(str(ET.QName(TS, 'exception'))) == 'TODO': + notes.append('TODO unexpected result:\n' + toxml(iact)) + + for key, iexp in expect.items(): + + exc = iexp.get(str(ET.QName(TS, 'exception'))) + + if exc == 'TODO': + notes.append('TODO missing expected result:\n' + toxml(iexp)) + elif exc is not None: + errors.append('missing expected result:\n' + toxml(iexp)) + + if len(notes) == 1: + print('(TODO)', end=' ', file=sys.stderr) + elif notes: + print('(%d TODO)' % len(notes), end=' ', file=sys.stderr) + assert not errors, '\n'.join(errors) + + +def compare_sources(expect, actual): + assert actual.tag == ET.QName(BC, 'source') + assert actual.get('href').endswith(expect.get('href')), \ + 'source href mismatch: %s != %s' % (actual, expect) + + # FIXME process/trim test:* contents + + def map_source(src): + if src == '' or src[0].tag != ET.QName(BC, 'index'): + # insert artificial hierarchy + syms = src[:] + del src[:] + idx = ET.SubElement(src, ET.QName(BC, 'index'), num='0') + idx[:] = syms + exc = src.get(str(ET.QName(TS, 'exception'))) + if exc is not None: + idx.set(str(ET.QName(TS, 'exception')), exc) + return {'0': idx} + elif len(src): + assert src[0].tag != ET.QName(BC, 'symbol'), \ + 'invalid source element: ' + \ + 'expecting "index" or "symbol", got "%s"' % fixtag(src[0]) + + srcmap = {} + for idx in src: + srcmap[idx.get('num')] = idx + return srcmap + + compare_maps(map_source(expect), map_source(actual), compare_indices) + + +def compare_indices(expect, actual): + assert actual.tag == ET.QName(BC, 'index') + assert actual.get('num') == expect.get('num') + + # FIXME process/trim test:* contents + + def map_index(idx): + idxmap = {} + for sym in idx: + assert sym.tag == ET.QName(BC, 'symbol') + typ = sym.get('type') + assert typ is not None + data = sym.find(str(ET.QName(BC, 'data'))).text + idxmap[typ, data] = sym + + return idxmap + + try: + compare_maps(map_index(expect), map_index(actual), compare_symbols) + except AssertionError: + if expect.get(str(ET.QName(TS, 'exception'))) != 'TODO': + raise + + +def compare_symbols(expect, actual): + orient = expect.get('orientation') + if orient: + assert actual.get('orientation') == orient + +# override unittest.TestLoader to populate tests from xml description + + +class TestLoader: + suiteClass = UT.TestSuite + + def __init__(self): + self.cwd = urlunparse(('file', '', getcwd() + '/', '', '', '')) + if debug: + print('cwd =', self.cwd) + + def loadTestsFromModule(self, module): + return self.suiteClass([BuiltinTestCase()]) + + def loadTestsFromNames(self, names, module=None): + suites = [self.loadTestsFromName(name, module) for name in names] + return self.suiteClass(suites) + + def loadTestsFromURL(self, url=None, file=None): + if debug: + print('loading url:', url) + + target = None + if not file: + if not url: + return self.suiteClass([BuiltinTestCase()]) + + content = None + url = urljoin(self.cwd, url) + # FIXME grok fragment + + try: + if debug: + print('trying:', url) + file = urlopen(url) + content = file.info().get('Content-Type') + except HTTPError: + # possible remote directory + pass + except IOError as e: + if e.errno not in (EISDIR, EINVAL, EACCES): + raise + # could be local directory + + if (not file or + content == 'text/html' or + (isinstance(file, HTTPError) and file.code != 200)): + # could be directory, try opening index + try: + tmp = urljoin(url + '/', 'index.xml') + if debug: + print('trying index:', tmp) + file = urlopen(tmp) + content = file.info().get('Content-Type') + url = tmp + except IOError: + raise IOError('no test index found at: %s' % url) + + if debug: + print('\tContent-Type:', content) + + if content not in ('application/xml', 'text/xml'): + # assume url is image to test, try containing index + # FIXME should be able to keep searching up + try: + target = url.rsplit('/', 1)[1] + index = urljoin(url, 'index.xml') + if debug: + print('trying index:', index) + file = urlopen(index) + content = file.info().get('Content-Type') + if debug: + print('\tContent-Type:', content) + assert content in ('application/xml', 'text/xml') + url = index + except IOError: + raise IOError('no index found for: %s' % url) + + index = ET.ElementTree(file=file).getroot() + assert index.tag == ET.QName(BC, 'barcodes') + + suite = self.suiteClass() + for src in index: + # FIXME trim any meta info + href = src.get('href') + if target and target != href: + continue + if src.tag == ET.QName(BC, 'source'): + test = TestCase() + # convert file URLs to filesystem paths + href = urljoin(url, href) + href = re.sub(r'^file://', '', href) + src.set('href', href) + test.source = src + suite.addTest(test) + elif src.tag == ET.QName(TS, 'index'): + suite.addTest(self.loadTestsFromURL(urljoin(url, href))) + else: + raise AssertionError('malformed test index') # FIXME detail + + assert suite.countTestCases(), 'empty test index: %s' % url + return suite + + def loadTestsFromName(self, name=None, module=None): + return self.loadTestsFromURL(name) + + def unsupported(self, *args, **kwargs): + raise TypeError("unsupported TestLoader API") + + # FAKE discover method needed for python3 to work + def discover(self, start_dir, pattern, top_level_dir=None): + return self.loadTestsFromURL() + + loadTestsFromTestCase = unsupported + getTestCaseNames = unsupported + + +if __name__ == '__main__': + if '-d' in sys.argv: + debug = True + sys.argv.remove('-d') + + UT.main(module=None, testLoader=TestLoader()) diff --git a/test/check_dbus.sh.in b/test/check_dbus.sh.in new file mode 100644 index 0000000..3b97b36 --- /dev/null +++ b/test/check_dbus.sh.in @@ -0,0 +1,39 @@ +#!/bin/bash + +DIR="@abs_top_srcdir@" +BDIR="@abs_top_builddir@" +LOG="/tmp/zbar_dbus_test_$$.log" +LOG_BIN="/tmp/zbar_dbus_test_$$.bin" + +EXPECTED="7294377b69fb00c7e0811429ab7a42cc8cecfda0" +EXPECTED_BIN="df896e459e47a7d392031a7d4962722a143e276b" + + +$BDIR/test/test_dbus -c2 -t5 --log=$LOG --bin-log=$LOG_BIN & +PID=$! + +trap "rm -r $LOG $LOG_BIN" EXIT + +$BDIR/zbarimg/zbarimg $DIR/examples/code-128.png 2>/dev/null >/dev/null +$BDIR/zbarimg/zbarimg -Sbinary $DIR/examples/qr-code-binary.png 2>/dev/null >/dev/null + +wait $PID + +if [ ! -s $LOG ] || [ ! -s $LOG_BIN ]; then + echo "FAILED: nothing received via D-Bus" + exit -2 +fi + +CK="`cat $LOG |sha1sum |cut -d" " -f 1`" +if [ "x$CK" != "x$EXPECTED" ]; then + echo "FAILED: $CK instead of $EXPECTED" + exit -2 +fi + +CK_BIN="`cat $LOG_BIN |sha1sum |cut -d" " -f 1`" +if [ "x$CK_BIN" != "x$EXPECTED_BIN" ]; then + echo "FAILED: $CK_BIN instead of $EXPECTED_BIN" + exit -2 +fi + +echo "D-Bus PASSED." diff --git a/test/dbg_scan.cpp b/test/dbg_scan.cpp new file mode 100644 index 0000000..a496112 --- /dev/null +++ b/test/dbg_scan.cpp @@ -0,0 +1,218 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include <Magick++.h> +#include <fstream> +#include <iostream> +#include <libgen.h> +#include <zbar.h> + +using namespace std; +using namespace zbar; + +#ifndef ZBAR_FIXED +#define ZBAR_FIXED 5 +#endif + +#define ZBAR_FRAC (1 << ZBAR_FIXED) + +Decoder decoder; +Scanner scanner; + +/* undocumented API for drawing cutesy debug graphics */ +extern "C" void zbar_scanner_get_state(const zbar_scanner_t *scn, unsigned *x, + unsigned *cur_edge, unsigned *last_edge, + int *y0, int *y1, int *y2, + int *y1_thresh); + +void scan_image(const char *filename) +{ + scanner.reset(); + // normally scanner would reset associated decoder, + // but this debug program connects them manually + // (to make intermediate state more readily available) + // so decoder must also be reset manually + decoder.reset(); + + Magick::Image image; + image.read(filename); + string file = image.baseFilename(); + size_t baseidx = file.rfind('/'); + if (baseidx != string::npos) + file = file.substr(baseidx + 1, file.length() - baseidx - 1); + ofstream svg((file + ".svg").c_str()); + + unsigned inwidth = image.columns(); + unsigned width = inwidth + 3; + unsigned height = image.rows(); + unsigned midy = height / 2; + cerr << "x+: " << midy << endl; + + image.crop(Magick::Geometry(inwidth, 1, 0, midy)); + + svg << "<?xml version='1.0'?>" << endl + << "<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN'" + << " 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>" << endl + << "<svg version='1.1' id='top'" + << " width='10in' height='6in' preserveAspectRatio='xMinYMid slice'" + << " overflow='visible' viewBox='0,0 " << width * 2 << ",384'" + << " xmlns:xlink='http://www.w3.org/1999/xlink'" + << " xmlns='http://www.w3.org/2000/svg'>" << endl + << "<defs><style type='text/css'><![CDATA[" << endl + << " * { stroke-linejoin: round; stroke-linecap: round;" + << " stroke-width: .1; text-anchor: middle;" + << " image-rendering: optimizeSpeed;" + << " font-size: 6; font-weight: bold }" << endl + << " path { fill: none }" << endl + << " #zero { stroke: #00f }" << endl + << " #edges { stroke: #f00 }" << endl + << " #cur-edge { stroke: #f44 }" << endl + << " #raw { stroke: orange }" << endl + << " #y0 { stroke: yellow }" << endl + << " #y1 { stroke: #0c0 }" << endl + << " #y2 { stroke: #0aa }" << endl + << " .y1thr { stroke: #f0f }" << endl + << " rect.bar { fill: black }" << endl + << " text.bar { fill: white }" << endl + << " rect.space { fill: white }" << endl + << " text.space { fill: black }" << endl + << " text.data { fill: #44f; font-size: 16 }" << endl + << "]]></style></defs>" << endl + << "<image width='" << inwidth * 2 << "' height='384'" + << " preserveAspectRatio='none'" + << " xlink:href='" << file << ".png'/>" << endl + << "<g transform='translate(1,384) scale(2,-.5)'>" << endl; + + // brute force + unsigned raw[inwidth]; + { + // extract scan from image pixels + image.modifyImage(); + Magick::Pixels view(image); + Magick::PixelPacket *pxp = view.get(0, 0, inwidth, 1); + Magick::ColorYUV y; + double max = 0; + svg << "<path id='raw' d='M"; + unsigned i; + for (i = 0; i < inwidth; i++, pxp++) { + y = *pxp; + if (max < y.y()) + max = y.y(); + raw[i] = (unsigned)(y.y() * 0x100); + svg << ((i != 1) ? " " : " L ") << i << "," << raw[i]; + y.u(0); + y.v(0); + *pxp = y; + } + view.sync(); + svg << "'/>" << endl << "</g>" << endl; + } + image.depth(8); + image.write(file + ".png"); + + // process scan and capture calculated values + unsigned cur_edge[width], last_edge[width]; + int y0[width], y1[width], y2[width], y1_thr[width]; + + svg << "<g transform='translate(-3)'>" << endl; + for (unsigned i = 0; i < width; i++) { + int edge; + if (i < inwidth) + edge = scanner.scan_y(raw[i]); + else + edge = scanner.flush(); + + unsigned x; + zbar_scanner_get_state(scanner, &x, &cur_edge[i], &last_edge[i], &y0[i], + &y1[i], &y2[i], &y1_thr[i]); + if (edge) { + unsigned w = scanner.get_width(); + if (w) + svg << "<rect x='" << (2. * (last_edge[i] - w) / ZBAR_FRAC) + << "' width='" << (w * 2. / ZBAR_FRAC) + << "' height='32' class='" + << (scanner.get_color() ? "space" : "bar") << "'/>" << endl + << "<text transform='translate(" + << ((2. * last_edge[i] - w) / ZBAR_FRAC) - 3 + << ",16) rotate(90)' class='" + << (scanner.get_color() ? "space" : "bar") << "'>" << endl + << w << "</text>" << endl; + zbar_symbol_type_t sym = decoder.decode_width(w); + if (sym > ZBAR_PARTIAL) { + svg << "<text transform='translate(" + << (2. * (last_edge[i] + w) / ZBAR_FRAC) + << ",208) rotate(90)' class='data'>" + << decoder.get_data_string() << "</text>" << endl; + } + } else if ((!i) ? last_edge[i] : last_edge[i] == last_edge[i - 1]) + last_edge[i] = 0; + } + + svg << "</g>" << endl + << "<g transform='translate(-3,384) scale(2,-.5)'>" << endl + << "<path id='edges' d='"; + for (unsigned i = 0; i < width; i++) + if (last_edge[i]) + svg << " M" << ((double)last_edge[i] / ZBAR_FRAC) << ",0v768"; + svg << "'/>" << endl + << "</g>" << endl + << "<g transform='translate(-1,384) scale(2,-.5)'>" << endl + << "<path id='y0' d='M"; + for (unsigned i = 0; i < width; i++) + svg << ((i != 1) ? " " : " L ") << i << "," << y0[i]; + svg << "'/>" << endl << "</g>" << endl; + + svg << "<g transform='translate(-1,128) scale(2,-1)'>" << endl + << "<line id='zero' x2='" << width << "'/>" << endl + << "<path id='cur-edge' d='"; + for (unsigned i = 1; i < width - 1; i++) + if (!last_edge[i + 1] && (cur_edge[i] != cur_edge[i + 1])) + svg << " M" << ((double)cur_edge[i] / ZBAR_FRAC) - 1 << ",-32v64"; + svg << "'/>" << endl << "<path class='y1thr' d='M"; + for (unsigned i = 0; i < width; i++) + svg << ((i != 1) ? " " : " L ") << i << "," << y1_thr[i]; + svg << "'/>" << endl << "<path class='y1thr' d='M"; + for (unsigned i = 0; i < width; i++) + svg << ((i != 1) ? " " : " L ") << i << "," << -y1_thr[i]; + svg << "'/>" << endl << "<path id='y1' d='M"; + for (unsigned i = 0; i < width; i++) + svg << ((i != 1) ? " " : " L ") << (i - 0.5) << "," << y1[i]; + svg << "'/>" << endl << "<path id='y2' d='M"; + for (unsigned i = 0; i < width; i++) + svg << ((i != 1) ? " " : " L ") << i << "," << y2[i]; + svg << "'/>" << endl << "</g>" << endl; + + svg << "</svg>" << endl; +} + +int main(int argc, const char *argv[]) +{ + if (argc < 2) { + cerr << "ERROR: specify image file(s) to scan" << endl; + return (1); + } + + for (int i = 1; i < argc; i++) + scan_image(argv[i]); + return (0); +} diff --git a/test/pdf417_encode.h b/test/pdf417_encode.h new file mode 100644 index 0000000..eb70cf5 --- /dev/null +++ b/test/pdf417_encode.h @@ -0,0 +1,4674 @@ +/*------------------------------------------------------------------------ + * Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ +#ifndef _PDF417_ENCODE_H_ +#define _PDF417_ENCODE_H_ + +unsigned long pdf417_encode[929][3] = { + { + 0x31111136, + 0x51111125, + 0x21111155, + }, /* 0 */ + { + 0x41111144, + 0x61111133, + 0x31111163, + }, /* 1 */ + { + 0x51111152, + 0x41111216, + 0x11111246, + }, /* 2 */ + { + 0x31111235, + 0x51111224, + 0x21111254, + }, /* 3 */ + { + 0x41111243, + 0x61111232, + 0x31111262, + }, /* 4 */ + { + 0x51111251, + 0x41111315, + 0x11111345, + }, /* 5 */ + { + 0x21111326, + 0x51111323, + 0x21111353, + }, /* 6 */ + { + 0x31111334, + 0x61111331, + 0x31111361, + }, /* 7 */ + { + 0x21111425, + 0x41111414, + 0x11111444, + }, /* 8 */ + { + 0x11111516, + 0x51111422, + 0x21111452, + }, /* 9 */ + { + 0x21111524, + 0x41111513, + 0x11111543, + }, /* 10 */ + { + 0x11111615, + 0x51111521, + 0x61112114, + }, /* 11 */ + { + 0x21112136, + 0x41111612, + 0x11112155, + }, /* 12 */ + { + 0x31112144, + 0x41112125, + 0x21112163, + }, /* 13 */ + { + 0x41112152, + 0x51112133, + 0x61112213, + }, /* 14 */ + { + 0x21112235, + 0x61112141, + 0x11112254, + }, /* 15 */ + { + 0x31112243, + 0x31112216, + 0x21112262, + }, /* 16 */ + { + 0x41112251, + 0x41112224, + 0x61112312, + }, /* 17 */ + { + 0x11112326, + 0x51112232, + 0x11112353, + }, /* 18 */ + { + 0x21112334, + 0x31112315, + 0x21112361, + }, /* 19 */ + { + 0x11112425, + 0x41112323, + 0x61112411, + }, /* 20 */ + { + 0x11113136, + 0x51112331, + 0x11112452, + }, /* 21 */ + { + 0x21113144, + 0x31112414, + 0x51113114, + }, /* 22 */ + { + 0x31113152, + 0x41112422, + 0x61113122, + }, /* 23 */ + { + 0x11113235, + 0x31112513, + 0x11113163, + }, /* 24 */ + { + 0x21113243, + 0x41112521, + 0x51113213, + }, /* 25 */ + { + 0x31113251, + 0x31112612, + 0x61113221, + }, /* 26 */ + { + 0x11113334, + 0x31113125, + 0x11113262, + }, /* 27 */ + { + 0x21113342, + 0x41113133, + 0x51113312, + }, /* 28 */ + { + 0x11114144, + 0x51113141, + 0x11113361, + }, /* 29 */ + { + 0x21114152, + 0x21113216, + 0x51113411, + }, /* 30 */ + { + 0x11114243, + 0x31113224, + 0x41114114, + }, /* 31 */ + { + 0x21114251, + 0x41113232, + 0x51114122, + }, /* 32 */ + { + 0x11115152, + 0x21113315, + 0x41114213, + }, /* 33 */ + { + 0x51116111, + 0x31113323, + 0x51114221, + }, /* 34 */ + { + 0x31121135, + 0x41113331, + 0x41114312, + }, /* 35 */ + { + 0x41121143, + 0x21113414, + 0x41114411, + }, /* 36 */ + { + 0x51121151, + 0x31113422, + 0x31115114, + }, /* 37 */ + { + 0x21121226, + 0x21113513, + 0x41115122, + }, /* 38 */ + { + 0x31121234, + 0x31113521, + 0x31115213, + }, /* 39 */ + { + 0x41121242, + 0x21113612, + 0x41115221, + }, /* 40 */ + { + 0x21121325, + 0x21114125, + 0x31115312, + }, /* 41 */ + { + 0x31121333, + 0x31114133, + 0x31115411, + }, /* 42 */ + { + 0x11121416, + 0x41114141, + 0x21116114, + }, /* 43 */ + { + 0x21121424, + 0x11114216, + 0x31116122, + }, /* 44 */ + { + 0x31121432, + 0x21114224, + 0x21116213, + }, /* 45 */ + { + 0x11121515, + 0x31114232, + 0x31116221, + }, /* 46 */ + { + 0x21121523, + 0x11114315, + 0x21116312, + }, /* 47 */ + { + 0x11121614, + 0x21114323, + 0x11121146, + }, /* 48 */ + { + 0x21122135, + 0x31114331, + 0x21121154, + }, /* 49 */ + { + 0x31122143, + 0x11114414, + 0x31121162, + }, /* 50 */ + { + 0x41122151, + 0x21114422, + 0x11121245, + }, /* 51 */ + { + 0x11122226, + 0x11114513, + 0x21121253, + }, /* 52 */ + { + 0x21122234, + 0x21114521, + 0x31121261, + }, /* 53 */ + { + 0x31122242, + 0x11115125, + 0x11121344, + }, /* 54 */ + { + 0x11122325, + 0x21115133, + 0x21121352, + }, /* 55 */ + { + 0x21122333, + 0x31115141, + 0x11121443, + }, /* 56 */ + { + 0x31122341, + 0x11115224, + 0x21121451, + }, /* 57 */ + { + 0x11122424, + 0x21115232, + 0x11121542, + }, /* 58 */ + { + 0x21122432, + 0x11115323, + 0x61122113, + }, /* 59 */ + { + 0x11123135, + 0x21115331, + 0x11122154, + }, /* 60 */ + { + 0x21123143, + 0x11115422, + 0x21122162, + }, /* 61 */ + { + 0x31123151, + 0x11116133, + 0x61122212, + }, /* 62 */ + { + 0x11123234, + 0x21116141, + 0x11122253, + }, /* 63 */ + { + 0x21123242, + 0x11116232, + 0x21122261, + }, /* 64 */ + { + 0x11123333, + 0x11116331, + 0x61122311, + }, /* 65 */ + { + 0x21123341, + 0x41121116, + 0x11122352, + }, /* 66 */ + { + 0x11124143, + 0x51121124, + 0x11122451, + }, /* 67 */ + { + 0x21124151, + 0x61121132, + 0x51123113, + }, /* 68 */ + { + 0x11124242, + 0x41121215, + 0x61123121, + }, /* 69 */ + { + 0x11124341, + 0x51121223, + 0x11123162, + }, /* 70 */ + { + 0x21131126, + 0x61121231, + 0x51123212, + }, /* 71 */ + { + 0x31131134, + 0x41121314, + 0x11123261, + }, /* 72 */ + { + 0x41131142, + 0x51121322, + 0x51123311, + }, /* 73 */ + { + 0x21131225, + 0x41121413, + 0x41124113, + }, /* 74 */ + { + 0x31131233, + 0x51121421, + 0x51124121, + }, /* 75 */ + { + 0x41131241, + 0x41121512, + 0x41124212, + }, /* 76 */ + { + 0x11131316, + 0x41121611, + 0x41124311, + }, /* 77 */ + { + 0x21131324, + 0x31122116, + 0x31125113, + }, /* 78 */ + { + 0x31131332, + 0x41122124, + 0x41125121, + }, /* 79 */ + { + 0x11131415, + 0x51122132, + 0x31125212, + }, /* 80 */ + { + 0x21131423, + 0x31122215, + 0x31125311, + }, /* 81 */ + { + 0x11131514, + 0x41122223, + 0x21126113, + }, /* 82 */ + { + 0x11131613, + 0x51122231, + 0x31126121, + }, /* 83 */ + { + 0x11132126, + 0x31122314, + 0x21126212, + }, /* 84 */ + { + 0x21132134, + 0x41122322, + 0x21126311, + }, /* 85 */ + { + 0x31132142, + 0x31122413, + 0x11131145, + }, /* 86 */ + { + 0x11132225, + 0x41122421, + 0x21131153, + }, /* 87 */ + { + 0x21132233, + 0x31122512, + 0x31131161, + }, /* 88 */ + { + 0x31132241, + 0x31122611, + 0x11131244, + }, /* 89 */ + { + 0x11132324, + 0x21123116, + 0x21131252, + }, /* 90 */ + { + 0x21132332, + 0x31123124, + 0x11131343, + }, /* 91 */ + { + 0x11132423, + 0x41123132, + 0x21131351, + }, /* 92 */ + { + 0x11132522, + 0x21123215, + 0x11131442, + }, /* 93 */ + { + 0x11133134, + 0x31123223, + 0x11131541, + }, /* 94 */ + { + 0x21133142, + 0x41123231, + 0x61132112, + }, /* 95 */ + { + 0x11133233, + 0x21123314, + 0x11132153, + }, /* 96 */ + { + 0x21133241, + 0x31123322, + 0x21132161, + }, /* 97 */ + { + 0x11133332, + 0x21123413, + 0x61132211, + }, /* 98 */ + { + 0x11134142, + 0x31123421, + 0x11132252, + }, /* 99 */ + { + 0x21141125, + 0x21123512, + 0x11132351, + }, /* 100 */ + { + 0x31141133, + 0x21123611, + 0x51133112, + }, /* 101 */ + { + 0x41141141, + 0x11124116, + 0x11133161, + }, /* 102 */ + { + 0x11141216, + 0x21124124, + 0x51133211, + }, /* 103 */ + { + 0x21141224, + 0x31124132, + 0x41134112, + }, /* 104 */ + { + 0x31141232, + 0x11124215, + 0x41134211, + }, /* 105 */ + { + 0x11141315, + 0x21124223, + 0x31135112, + }, /* 106 */ + { + 0x21141323, + 0x31124231, + 0x31135211, + }, /* 107 */ + { + 0x31141331, + 0x11124314, + 0x21136112, + }, /* 108 */ + { + 0x11141414, + 0x21124322, + 0x21136211, + }, /* 109 */ + { + 0x21141422, + 0x11124413, + 0x11141144, + }, /* 110 */ + { + 0x11141513, + 0x21124421, + 0x21141152, + }, /* 111 */ + { + 0x21141521, + 0x11124512, + 0x11141243, + }, /* 112 */ + { + 0x11142125, + 0x11125124, + 0x21141251, + }, /* 113 */ + { + 0x21142133, + 0x21125132, + 0x11141342, + }, /* 114 */ + { + 0x31142141, + 0x11125223, + 0x11141441, + }, /* 115 */ + { + 0x11142224, + 0x21125231, + 0x61142111, + }, /* 116 */ + { + 0x21142232, + 0x11125322, + 0x11142152, + }, /* 117 */ + { + 0x11142323, + 0x11125421, + 0x11142251, + }, /* 118 */ + { + 0x21142331, + 0x11126132, + 0x51143111, + }, /* 119 */ + { + 0x11142422, + 0x11126231, + 0x41144111, + }, /* 120 */ + { + 0x11142521, + 0x41131115, + 0x31145111, + }, /* 121 */ + { + 0x21143141, + 0x51131123, + 0x11151143, + }, /* 122 */ + { + 0x11143331, + 0x61131131, + 0x21151151, + }, /* 123 */ + { + 0x11151116, + 0x41131214, + 0x11151242, + }, /* 124 */ + { + 0x21151124, + 0x51131222, + 0x11151341, + }, /* 125 */ + { + 0x31151132, + 0x41131313, + 0x11152151, + }, /* 126 */ + { + 0x11151215, + 0x51131321, + 0x11161142, + }, /* 127 */ + { + 0x21151223, + 0x41131412, + 0x11161241, + }, /* 128 */ + { + 0x31151231, + 0x41131511, + 0x12111146, + }, /* 129 */ + { + 0x11151314, + 0x31132115, + 0x22111154, + }, /* 130 */ + { + 0x21151322, + 0x41132123, + 0x32111162, + }, /* 131 */ + { + 0x11151413, + 0x51132131, + 0x12111245, + }, /* 132 */ + { + 0x21151421, + 0x31132214, + 0x22111253, + }, /* 133 */ + { + 0x11151512, + 0x41132222, + 0x32111261, + }, /* 134 */ + { + 0x11152124, + 0x31132313, + 0x12111344, + }, /* 135 */ + { + 0x11152223, + 0x41132321, + 0x22111352, + }, /* 136 */ + { + 0x11152322, + 0x31132412, + 0x12111443, + }, /* 137 */ + { + 0x11161115, + 0x31132511, + 0x22111451, + }, /* 138 */ + { + 0x31161131, + 0x21133115, + 0x12111542, + }, /* 139 */ + { + 0x21161222, + 0x31133123, + 0x62112113, + }, /* 140 */ + { + 0x21161321, + 0x41133131, + 0x12112154, + }, /* 141 */ + { + 0x11161511, + 0x21133214, + 0x22112162, + }, /* 142 */ + { + 0x32111135, + 0x31133222, + 0x62112212, + }, /* 143 */ + { + 0x42111143, + 0x21133313, + 0x12112253, + }, /* 144 */ + { + 0x52111151, + 0x31133321, + 0x22112261, + }, /* 145 */ + { + 0x22111226, + 0x21133412, + 0x62112311, + }, /* 146 */ + { + 0x32111234, + 0x21133511, + 0x12112352, + }, /* 147 */ + { + 0x42111242, + 0x11134115, + 0x12112451, + }, /* 148 */ + { + 0x22111325, + 0x21134123, + 0x52113113, + }, /* 149 */ + { + 0x32111333, + 0x31134131, + 0x62113121, + }, /* 150 */ + { + 0x42111341, + 0x11134214, + 0x12113162, + }, /* 151 */ + { + 0x12111416, + 0x21134222, + 0x52113212, + }, /* 152 */ + { + 0x22111424, + 0x11134313, + 0x12113261, + }, /* 153 */ + { + 0x12111515, + 0x21134321, + 0x52113311, + }, /* 154 */ + { + 0x22112135, + 0x11134412, + 0x42114113, + }, /* 155 */ + { + 0x32112143, + 0x11134511, + 0x52114121, + }, /* 156 */ + { + 0x42112151, + 0x11135123, + 0x42114212, + }, /* 157 */ + { + 0x12112226, + 0x21135131, + 0x42114311, + }, /* 158 */ + { + 0x22112234, + 0x11135222, + 0x32115113, + }, /* 159 */ + { + 0x32112242, + 0x11135321, + 0x42115121, + }, /* 160 */ + { + 0x12112325, + 0x11136131, + 0x32115212, + }, /* 161 */ + { + 0x22112333, + 0x41141114, + 0x32115311, + }, /* 162 */ + { + 0x12112424, + 0x51141122, + 0x22116113, + }, /* 163 */ + { + 0x12112523, + 0x41141213, + 0x32116121, + }, /* 164 */ + { + 0x12113135, + 0x51141221, + 0x22116212, + }, /* 165 */ + { + 0x22113143, + 0x41141312, + 0x22116311, + }, /* 166 */ + { + 0x32113151, + 0x41141411, + 0x21211145, + }, /* 167 */ + { + 0x12113234, + 0x31142114, + 0x31211153, + }, /* 168 */ + { + 0x22113242, + 0x41142122, + 0x41211161, + }, /* 169 */ + { + 0x12113333, + 0x31142213, + 0x11211236, + }, /* 170 */ + { + 0x12113432, + 0x41142221, + 0x21211244, + }, /* 171 */ + { + 0x12114143, + 0x31142312, + 0x31211252, + }, /* 172 */ + { + 0x22114151, + 0x31142411, + 0x11211335, + }, /* 173 */ + { + 0x12114242, + 0x21143114, + 0x21211343, + }, /* 174 */ + { + 0x12115151, + 0x31143122, + 0x31211351, + }, /* 175 */ + { + 0x31211126, + 0x21143213, + 0x11211434, + }, /* 176 */ + { + 0x41211134, + 0x31143221, + 0x21211442, + }, /* 177 */ + { + 0x51211142, + 0x21143312, + 0x11211533, + }, /* 178 */ + { + 0x31211225, + 0x21143411, + 0x21211541, + }, /* 179 */ + { + 0x41211233, + 0x11144114, + 0x11211632, + }, /* 180 */ + { + 0x51211241, + 0x21144122, + 0x12121145, + }, /* 181 */ + { + 0x21211316, + 0x11144213, + 0x22121153, + }, /* 182 */ + { + 0x31211324, + 0x21144221, + 0x32121161, + }, /* 183 */ + { + 0x41211332, + 0x11144312, + 0x11212145, + }, /* 184 */ + { + 0x21211415, + 0x11144411, + 0x12121244, + }, /* 185 */ + { + 0x31211423, + 0x11145122, + 0x22121252, + }, /* 186 */ + { + 0x41211431, + 0x11145221, + 0x11212244, + }, /* 187 */ + { + 0x21211514, + 0x41151113, + 0x21212252, + }, /* 188 */ + { + 0x31211522, + 0x51151121, + 0x22121351, + }, /* 189 */ + { + 0x22121126, + 0x41151212, + 0x11212343, + }, /* 190 */ + { + 0x32121134, + 0x41151311, + 0x12121442, + }, /* 191 */ + { + 0x42121142, + 0x31152113, + 0x11212442, + }, /* 192 */ + { + 0x21212126, + 0x41152121, + 0x12121541, + }, /* 193 */ + { + 0x22121225, + 0x31152212, + 0x11212541, + }, /* 194 */ + { + 0x32121233, + 0x31152311, + 0x62122112, + }, /* 195 */ + { + 0x42121241, + 0x21153113, + 0x12122153, + }, /* 196 */ + { + 0x21212225, + 0x31153121, + 0x22122161, + }, /* 197 */ + { + 0x31212233, + 0x21153212, + 0x61213112, + }, /* 198 */ + { + 0x41212241, + 0x21153311, + 0x62122211, + }, /* 199 */ + { + 0x11212316, + 0x11154113, + 0x11213153, + }, /* 200 */ + { + 0x12121415, + 0x21154121, + 0x12122252, + }, /* 201 */ + { + 0x22121423, + 0x11154212, + 0x61213211, + }, /* 202 */ + { + 0x32121431, + 0x11154311, + 0x11213252, + }, /* 203 */ + { + 0x11212415, + 0x41161112, + 0x12122351, + }, /* 204 */ + { + 0x21212423, + 0x41161211, + 0x11213351, + }, /* 205 */ + { + 0x11212514, + 0x31162112, + 0x52123112, + }, /* 206 */ + { + 0x12122126, + 0x31162211, + 0x12123161, + }, /* 207 */ + { + 0x22122134, + 0x21163112, + 0x51214112, + }, /* 208 */ + { + 0x32122142, + 0x21163211, + 0x52123211, + }, /* 209 */ + { + 0x11213126, + 0x42111116, + 0x11214161, + }, /* 210 */ + { + 0x12122225, + 0x52111124, + 0x51214211, + }, /* 211 */ + { + 0x22122233, + 0x62111132, + 0x42124112, + }, /* 212 */ + { + 0x32122241, + 0x42111215, + 0x41215112, + }, /* 213 */ + { + 0x11213225, + 0x52111223, + 0x42124211, + }, /* 214 */ + { + 0x21213233, + 0x62111231, + 0x41215211, + }, /* 215 */ + { + 0x31213241, + 0x42111314, + 0x32125112, + }, /* 216 */ + { + 0x11213324, + 0x52111322, + 0x31216112, + }, /* 217 */ + { + 0x12122423, + 0x42111413, + 0x32125211, + }, /* 218 */ + { + 0x11213423, + 0x52111421, + 0x31216211, + }, /* 219 */ + { + 0x12123134, + 0x42111512, + 0x22126112, + }, /* 220 */ + { + 0x22123142, + 0x42111611, + 0x22126211, + }, /* 221 */ + { + 0x11214134, + 0x32112116, + 0x11221136, + }, /* 222 */ + { + 0x12123233, + 0x42112124, + 0x21221144, + }, /* 223 */ + { + 0x22123241, + 0x52112132, + 0x31221152, + }, /* 224 */ + { + 0x11214233, + 0x32112215, + 0x11221235, + }, /* 225 */ + { + 0x21214241, + 0x42112223, + 0x21221243, + }, /* 226 */ + { + 0x11214332, + 0x52112231, + 0x31221251, + }, /* 227 */ + { + 0x12124142, + 0x32112314, + 0x11221334, + }, /* 228 */ + { + 0x11215142, + 0x42112322, + 0x21221342, + }, /* 229 */ + { + 0x12124241, + 0x32112413, + 0x11221433, + }, /* 230 */ + { + 0x11215241, + 0x42112421, + 0x21221441, + }, /* 231 */ + { + 0x31221125, + 0x32112512, + 0x11221532, + }, /* 232 */ + { + 0x41221133, + 0x32112611, + 0x11221631, + }, /* 233 */ + { + 0x51221141, + 0x22113116, + 0x12131144, + }, /* 234 */ + { + 0x21221216, + 0x32113124, + 0x22131152, + }, /* 235 */ + { + 0x31221224, + 0x42113132, + 0x11222144, + }, /* 236 */ + { + 0x41221232, + 0x22113215, + 0x12131243, + }, /* 237 */ + { + 0x21221315, + 0x32113223, + 0x22131251, + }, /* 238 */ + { + 0x31221323, + 0x42113231, + 0x11222243, + }, /* 239 */ + { + 0x41221331, + 0x22113314, + 0x21222251, + }, /* 240 */ + { + 0x21221414, + 0x32113322, + 0x11222342, + }, /* 241 */ + { + 0x31221422, + 0x22113413, + 0x12131441, + }, /* 242 */ + { + 0x21221513, + 0x32113421, + 0x11222441, + }, /* 243 */ + { + 0x21221612, + 0x22113512, + 0x62132111, + }, /* 244 */ + { + 0x22131125, + 0x22113611, + 0x12132152, + }, /* 245 */ + { + 0x32131133, + 0x12114116, + 0x61223111, + }, /* 246 */ + { + 0x42131141, + 0x22114124, + 0x11223152, + }, /* 247 */ + { + 0x21222125, + 0x32114132, + 0x12132251, + }, /* 248 */ + { + 0x22131224, + 0x12114215, + 0x11223251, + }, /* 249 */ + { + 0x32131232, + 0x22114223, + 0x52133111, + }, /* 250 */ + { + 0x11222216, + 0x32114231, + 0x51224111, + }, /* 251 */ + { + 0x12131315, + 0x12114314, + 0x42134111, + }, /* 252 */ + { + 0x31222232, + 0x22114322, + 0x41225111, + }, /* 253 */ + { + 0x32131331, + 0x12114413, + 0x32135111, + }, /* 254 */ + { + 0x11222315, + 0x22114421, + 0x31226111, + }, /* 255 */ + { + 0x12131414, + 0x12114512, + 0x22136111, + }, /* 256 */ + { + 0x22131422, + 0x12115124, + 0x11231135, + }, /* 257 */ + { + 0x11222414, + 0x22115132, + 0x21231143, + }, /* 258 */ + { + 0x21222422, + 0x12115223, + 0x31231151, + }, /* 259 */ + { + 0x22131521, + 0x22115231, + 0x11231234, + }, /* 260 */ + { + 0x12131612, + 0x12115322, + 0x21231242, + }, /* 261 */ + { + 0x12132125, + 0x12115421, + 0x11231333, + }, /* 262 */ + { + 0x22132133, + 0x12116132, + 0x21231341, + }, /* 263 */ + { + 0x32132141, + 0x12116231, + 0x11231432, + }, /* 264 */ + { + 0x11223125, + 0x51211115, + 0x11231531, + }, /* 265 */ + { + 0x12132224, + 0x61211123, + 0x12141143, + }, /* 266 */ + { + 0x22132232, + 0x11211164, + 0x22141151, + }, /* 267 */ + { + 0x11223224, + 0x51211214, + 0x11232143, + }, /* 268 */ + { + 0x21223232, + 0x61211222, + 0x12141242, + }, /* 269 */ + { + 0x22132331, + 0x11211263, + 0x11232242, + }, /* 270 */ + { + 0x11223323, + 0x51211313, + 0x12141341, + }, /* 271 */ + { + 0x12132422, + 0x61211321, + 0x11232341, + }, /* 272 */ + { + 0x12132521, + 0x11211362, + 0x12142151, + }, /* 273 */ + { + 0x12133133, + 0x51211412, + 0x11233151, + }, /* 274 */ + { + 0x22133141, + 0x51211511, + 0x11241134, + }, /* 275 */ + { + 0x11224133, + 0x42121115, + 0x21241142, + }, /* 276 */ + { + 0x12133232, + 0x52121123, + 0x11241233, + }, /* 277 */ + { + 0x11224232, + 0x62121131, + 0x21241241, + }, /* 278 */ + { + 0x12133331, + 0x41212115, + 0x11241332, + }, /* 279 */ + { + 0x11224331, + 0x42121214, + 0x11241431, + }, /* 280 */ + { + 0x11225141, + 0x61212131, + 0x12151142, + }, /* 281 */ + { + 0x21231116, + 0x41212214, + 0x11242142, + }, /* 282 */ + { + 0x31231124, + 0x51212222, + 0x12151241, + }, /* 283 */ + { + 0x41231132, + 0x52121321, + 0x11242241, + }, /* 284 */ + { + 0x21231215, + 0x41212313, + 0x11251133, + }, /* 285 */ + { + 0x31231223, + 0x42121412, + 0x21251141, + }, /* 286 */ + { + 0x41231231, + 0x41212412, + 0x11251232, + }, /* 287 */ + { + 0x21231314, + 0x42121511, + 0x11251331, + }, /* 288 */ + { + 0x31231322, + 0x41212511, + 0x12161141, + }, /* 289 */ + { + 0x21231413, + 0x32122115, + 0x11252141, + }, /* 290 */ + { + 0x31231421, + 0x42122123, + 0x11261132, + }, /* 291 */ + { + 0x21231512, + 0x52122131, + 0x11261231, + }, /* 292 */ + { + 0x21231611, + 0x31213115, + 0x13111145, + }, /* 293 */ + { + 0x12141116, + 0x32122214, + 0x23111153, + }, /* 294 */ + { + 0x22141124, + 0x42122222, + 0x33111161, + }, /* 295 */ + { + 0x32141132, + 0x31213214, + 0x13111244, + }, /* 296 */ + { + 0x11232116, + 0x41213222, + 0x23111252, + }, /* 297 */ + { + 0x12141215, + 0x42122321, + 0x13111343, + }, /* 298 */ + { + 0x22141223, + 0x31213313, + 0x23111351, + }, /* 299 */ + { + 0x32141231, + 0x32122412, + 0x13111442, + }, /* 300 */ + { + 0x11232215, + 0x31213412, + 0x13111541, + }, /* 301 */ + { + 0x21232223, + 0x32122511, + 0x63112112, + }, /* 302 */ + { + 0x31232231, + 0x31213511, + 0x13112153, + }, /* 303 */ + { + 0x11232314, + 0x22123115, + 0x23112161, + }, /* 304 */ + { + 0x12141413, + 0x32123123, + 0x63112211, + }, /* 305 */ + { + 0x22141421, + 0x42123131, + 0x13112252, + }, /* 306 */ + { + 0x11232413, + 0x21214115, + 0x13112351, + }, /* 307 */ + { + 0x21232421, + 0x22123214, + 0x53113112, + }, /* 308 */ + { + 0x11232512, + 0x32123222, + 0x13113161, + }, /* 309 */ + { + 0x12142124, + 0x21214214, + 0x53113211, + }, /* 310 */ + { + 0x22142132, + 0x31214222, + 0x43114112, + }, /* 311 */ + { + 0x11233124, + 0x32123321, + 0x43114211, + }, /* 312 */ + { + 0x12142223, + 0x21214313, + 0x33115112, + }, /* 313 */ + { + 0x22142231, + 0x22123412, + 0x33115211, + }, /* 314 */ + { + 0x11233223, + 0x21214412, + 0x23116112, + }, /* 315 */ + { + 0x21233231, + 0x22123511, + 0x23116211, + }, /* 316 */ + { + 0x11233322, + 0x21214511, + 0x12211136, + }, /* 317 */ + { + 0x12142421, + 0x12124115, + 0x22211144, + }, /* 318 */ + { + 0x11233421, + 0x22124123, + 0x32211152, + }, /* 319 */ + { + 0x11234132, + 0x32124131, + 0x12211235, + }, /* 320 */ + { + 0x11234231, + 0x11215115, + 0x22211243, + }, /* 321 */ + { + 0x21241115, + 0x12124214, + 0x32211251, + }, /* 322 */ + { + 0x31241123, + 0x22124222, + 0x12211334, + }, /* 323 */ + { + 0x41241131, + 0x11215214, + 0x22211342, + }, /* 324 */ + { + 0x21241214, + 0x21215222, + 0x12211433, + }, /* 325 */ + { + 0x31241222, + 0x22124321, + 0x22211441, + }, /* 326 */ + { + 0x21241313, + 0x11215313, + 0x12211532, + }, /* 327 */ + { + 0x31241321, + 0x12124412, + 0x12211631, + }, /* 328 */ + { + 0x21241412, + 0x11215412, + 0x13121144, + }, /* 329 */ + { + 0x21241511, + 0x12124511, + 0x23121152, + }, /* 330 */ + { + 0x12151115, + 0x12125123, + 0x12212144, + }, /* 331 */ + { + 0x22151123, + 0x22125131, + 0x13121243, + }, /* 332 */ + { + 0x32151131, + 0x11216123, + 0x23121251, + }, /* 333 */ + { + 0x11242115, + 0x12125222, + 0x12212243, + }, /* 334 */ + { + 0x12151214, + 0x11216222, + 0x22212251, + }, /* 335 */ + { + 0x22151222, + 0x12125321, + 0x12212342, + }, /* 336 */ + { + 0x11242214, + 0x11216321, + 0x13121441, + }, /* 337 */ + { + 0x21242222, + 0x12126131, + 0x12212441, + }, /* 338 */ + { + 0x22151321, + 0x51221114, + 0x63122111, + }, /* 339 */ + { + 0x11242313, + 0x61221122, + 0x13122152, + }, /* 340 */ + { + 0x12151412, + 0x11221163, + 0x62213111, + }, /* 341 */ + { + 0x11242412, + 0x51221213, + 0x12213152, + }, /* 342 */ + { + 0x12151511, + 0x61221221, + 0x13122251, + }, /* 343 */ + { + 0x12152123, + 0x11221262, + 0x12213251, + }, /* 344 */ + { + 0x11243123, + 0x51221312, + 0x53123111, + }, /* 345 */ + { + 0x11243222, + 0x11221361, + 0x52214111, + }, /* 346 */ + { + 0x11243321, + 0x51221411, + 0x43124111, + }, /* 347 */ + { + 0x31251122, + 0x42131114, + 0x42215111, + }, /* 348 */ + { + 0x31251221, + 0x52131122, + 0x33125111, + }, /* 349 */ + { + 0x21251411, + 0x41222114, + 0x32216111, + }, /* 350 */ + { + 0x22161122, + 0x42131213, + 0x23126111, + }, /* 351 */ + { + 0x12161213, + 0x52131221, + 0x21311135, + }, /* 352 */ + { + 0x11252213, + 0x41222213, + 0x31311143, + }, /* 353 */ + { + 0x11252312, + 0x51222221, + 0x41311151, + }, /* 354 */ + { + 0x11252411, + 0x41222312, + 0x11311226, + }, /* 355 */ + { + 0x23111126, + 0x42131411, + 0x21311234, + }, /* 356 */ + { + 0x33111134, + 0x41222411, + 0x31311242, + }, /* 357 */ + { + 0x43111142, + 0x32132114, + 0x11311325, + }, /* 358 */ + { + 0x23111225, + 0x42132122, + 0x21311333, + }, /* 359 */ + { + 0x33111233, + 0x31223114, + 0x31311341, + }, /* 360 */ + { + 0x13111316, + 0x32132213, + 0x11311424, + }, /* 361 */ + { + 0x23111324, + 0x42132221, + 0x21311432, + }, /* 362 */ + { + 0x33111332, + 0x31223213, + 0x11311523, + }, /* 363 */ + { + 0x13111415, + 0x41223221, + 0x21311531, + }, /* 364 */ + { + 0x23111423, + 0x31223312, + 0x11311622, + }, /* 365 */ + { + 0x13111514, + 0x32132411, + 0x12221135, + }, /* 366 */ + { + 0x13111613, + 0x31223411, + 0x22221143, + }, /* 367 */ + { + 0x13112126, + 0x22133114, + 0x32221151, + }, /* 368 */ + { + 0x23112134, + 0x32133122, + 0x11312135, + }, /* 369 */ + { + 0x33112142, + 0x21224114, + 0x12221234, + }, /* 370 */ + { + 0x13112225, + 0x22133213, + 0x22221242, + }, /* 371 */ + { + 0x23112233, + 0x32133221, + 0x11312234, + }, /* 372 */ + { + 0x33112241, + 0x21224213, + 0x21312242, + }, /* 373 */ + { + 0x13112324, + 0x31224221, + 0x22221341, + }, /* 374 */ + { + 0x23112332, + 0x21224312, + 0x11312333, + }, /* 375 */ + { + 0x13112423, + 0x22133411, + 0x12221432, + }, /* 376 */ + { + 0x13112522, + 0x21224411, + 0x11312432, + }, /* 377 */ + { + 0x13113134, + 0x12134114, + 0x12221531, + }, /* 378 */ + { + 0x23113142, + 0x22134122, + 0x11312531, + }, /* 379 */ + { + 0x13113233, + 0x11225114, + 0x13131143, + }, /* 380 */ + { + 0x23113241, + 0x12134213, + 0x23131151, + }, /* 381 */ + { + 0x13113332, + 0x22134221, + 0x12222143, + }, /* 382 */ + { + 0x13114142, + 0x11225213, + 0x13131242, + }, /* 383 */ + { + 0x13114241, + 0x21225221, + 0x11313143, + }, /* 384 */ + { + 0x32211125, + 0x11225312, + 0x12222242, + }, /* 385 */ + { + 0x42211133, + 0x12134411, + 0x13131341, + }, /* 386 */ + { + 0x52211141, + 0x11225411, + 0x11313242, + }, /* 387 */ + { + 0x22211216, + 0x12135122, + 0x12222341, + }, /* 388 */ + { + 0x32211224, + 0x11226122, + 0x11313341, + }, /* 389 */ + { + 0x42211232, + 0x12135221, + 0x13132151, + }, /* 390 */ + { + 0x22211315, + 0x11226221, + 0x12223151, + }, /* 391 */ + { + 0x32211323, + 0x51231113, + 0x11314151, + }, /* 392 */ + { + 0x42211331, + 0x61231121, + 0x11321126, + }, /* 393 */ + { + 0x22211414, + 0x11231162, + 0x21321134, + }, /* 394 */ + { + 0x32211422, + 0x51231212, + 0x31321142, + }, /* 395 */ + { + 0x22211513, + 0x11231261, + 0x11321225, + }, /* 396 */ + { + 0x32211521, + 0x51231311, + 0x21321233, + }, /* 397 */ + { + 0x23121125, + 0x42141113, + 0x31321241, + }, /* 398 */ + { + 0x33121133, + 0x52141121, + 0x11321324, + }, /* 399 */ + { + 0x43121141, + 0x41232113, + 0x21321332, + }, /* 400 */ + { + 0x22212125, + 0x51232121, + 0x11321423, + }, /* 401 */ + { + 0x23121224, + 0x41232212, + 0x21321431, + }, /* 402 */ + { + 0x33121232, + 0x42141311, + 0x11321522, + }, /* 403 */ + { + 0x12212216, + 0x41232311, + 0x11321621, + }, /* 404 */ + { + 0x13121315, + 0x32142113, + 0x12231134, + }, /* 405 */ + { + 0x32212232, + 0x42142121, + 0x22231142, + }, /* 406 */ + { + 0x33121331, + 0x31233113, + 0x11322134, + }, /* 407 */ + { + 0x12212315, + 0x32142212, + 0x12231233, + }, /* 408 */ + { + 0x22212323, + 0x31233212, + 0x22231241, + }, /* 409 */ + { + 0x23121422, + 0x32142311, + 0x11322233, + }, /* 410 */ + { + 0x12212414, + 0x31233311, + 0x21322241, + }, /* 411 */ + { + 0x13121513, + 0x22143113, + 0x11322332, + }, /* 412 */ + { + 0x12212513, + 0x32143121, + 0x12231431, + }, /* 413 */ + { + 0x13122125, + 0x21234113, + 0x11322431, + }, /* 414 */ + { + 0x23122133, + 0x31234121, + 0x13141142, + }, /* 415 */ + { + 0x33122141, + 0x21234212, + 0x12232142, + }, /* 416 */ + { + 0x12213125, + 0x22143311, + 0x13141241, + }, /* 417 */ + { + 0x13122224, + 0x21234311, + 0x11323142, + }, /* 418 */ + { + 0x32213141, + 0x12144113, + 0x12232241, + }, /* 419 */ + { + 0x12213224, + 0x22144121, + 0x11323241, + }, /* 420 */ + { + 0x22213232, + 0x11235113, + 0x11331125, + }, /* 421 */ + { + 0x23122331, + 0x12144212, + 0x21331133, + }, /* 422 */ + { + 0x12213323, + 0x11235212, + 0x31331141, + }, /* 423 */ + { + 0x13122422, + 0x12144311, + 0x11331224, + }, /* 424 */ + { + 0x12213422, + 0x11235311, + 0x21331232, + }, /* 425 */ + { + 0x13123133, + 0x12145121, + 0x11331323, + }, /* 426 */ + { + 0x23123141, + 0x11236121, + 0x21331331, + }, /* 427 */ + { + 0x12214133, + 0x51241112, + 0x11331422, + }, /* 428 */ + { + 0x13123232, + 0x11241161, + 0x11331521, + }, /* 429 */ + { + 0x12214232, + 0x51241211, + 0x12241133, + }, /* 430 */ + { + 0x13123331, + 0x42151112, + 0x22241141, + }, /* 431 */ + { + 0x13124141, + 0x41242112, + 0x11332133, + }, /* 432 */ + { + 0x12215141, + 0x42151211, + 0x12241232, + }, /* 433 */ + { + 0x31311116, + 0x41242211, + 0x11332232, + }, /* 434 */ + { + 0x41311124, + 0x32152112, + 0x12241331, + }, /* 435 */ + { + 0x51311132, + 0x31243112, + 0x11332331, + }, /* 436 */ + { + 0x31311215, + 0x32152211, + 0x13151141, + }, /* 437 */ + { + 0x41311223, + 0x31243211, + 0x12242141, + }, /* 438 */ + { + 0x51311231, + 0x22153112, + 0x11333141, + }, /* 439 */ + { + 0x31311314, + 0x21244112, + 0x11341124, + }, /* 440 */ + { + 0x41311322, + 0x22153211, + 0x21341132, + }, /* 441 */ + { + 0x31311413, + 0x21244211, + 0x11341223, + }, /* 442 */ + { + 0x41311421, + 0x12154112, + 0x21341231, + }, /* 443 */ + { + 0x31311512, + 0x11245112, + 0x11341322, + }, /* 444 */ + { + 0x22221116, + 0x12154211, + 0x11341421, + }, /* 445 */ + { + 0x32221124, + 0x11245211, + 0x12251132, + }, /* 446 */ + { + 0x42221132, + 0x51251111, + 0x11342132, + }, /* 447 */ + { + 0x21312116, + 0x42161111, + 0x12251231, + }, /* 448 */ + { + 0x22221215, + 0x41252111, + 0x11342231, + }, /* 449 */ + { + 0x41312132, + 0x32162111, + 0x11351123, + }, /* 450 */ + { + 0x42221231, + 0x31253111, + 0x21351131, + }, /* 451 */ + { + 0x21312215, + 0x22163111, + 0x11351222, + }, /* 452 */ + { + 0x31312223, + 0x21254111, + 0x11351321, + }, /* 453 */ + { + 0x41312231, + 0x43111115, + 0x12261131, + }, /* 454 */ + { + 0x21312314, + 0x53111123, + 0x11352131, + }, /* 455 */ + { + 0x22221413, + 0x63111131, + 0x11361122, + }, /* 456 */ + { + 0x32221421, + 0x43111214, + 0x11361221, + }, /* 457 */ + { + 0x21312413, + 0x53111222, + 0x14111144, + }, /* 458 */ + { + 0x31312421, + 0x43111313, + 0x24111152, + }, /* 459 */ + { + 0x22221611, + 0x53111321, + 0x14111243, + }, /* 460 */ + { + 0x13131116, + 0x43111412, + 0x24111251, + }, /* 461 */ + { + 0x23131124, + 0x43111511, + 0x14111342, + }, /* 462 */ + { + 0x33131132, + 0x33112115, + 0x14111441, + }, /* 463 */ + { + 0x12222116, + 0x43112123, + 0x14112152, + }, /* 464 */ + { + 0x13131215, + 0x53112131, + 0x14112251, + }, /* 465 */ + { + 0x23131223, + 0x33112214, + 0x54113111, + }, /* 466 */ + { + 0x33131231, + 0x43112222, + 0x44114111, + }, /* 467 */ + { + 0x11313116, + 0x33112313, + 0x34115111, + }, /* 468 */ + { + 0x12222215, + 0x43112321, + 0x24116111, + }, /* 469 */ + { + 0x22222223, + 0x33112412, + 0x13211135, + }, /* 470 */ + { + 0x32222231, + 0x33112511, + 0x23211143, + }, /* 471 */ + { + 0x11313215, + 0x23113115, + 0x33211151, + }, /* 472 */ + { + 0x21313223, + 0x33113123, + 0x13211234, + }, /* 473 */ + { + 0x31313231, + 0x43113131, + 0x23211242, + }, /* 474 */ + { + 0x23131421, + 0x23113214, + 0x13211333, + }, /* 475 */ + { + 0x11313314, + 0x33113222, + 0x23211341, + }, /* 476 */ + { + 0x12222413, + 0x23113313, + 0x13211432, + }, /* 477 */ + { + 0x22222421, + 0x33113321, + 0x13211531, + }, /* 478 */ + { + 0x11313413, + 0x23113412, + 0x14121143, + }, /* 479 */ + { + 0x13131611, + 0x23113511, + 0x24121151, + }, /* 480 */ + { + 0x13132124, + 0x13114115, + 0x13212143, + }, /* 481 */ + { + 0x23132132, + 0x23114123, + 0x14121242, + }, /* 482 */ + { + 0x12223124, + 0x33114131, + 0x13212242, + }, /* 483 */ + { + 0x13132223, + 0x13114214, + 0x14121341, + }, /* 484 */ + { + 0x23132231, + 0x23114222, + 0x13212341, + }, /* 485 */ + { + 0x11314124, + 0x13114313, + 0x14122151, + }, /* 486 */ + { + 0x12223223, + 0x23114321, + 0x13213151, + }, /* 487 */ + { + 0x22223231, + 0x13114412, + 0x12311126, + }, /* 488 */ + { + 0x11314223, + 0x13114511, + 0x22311134, + }, /* 489 */ + { + 0x21314231, + 0x13115123, + 0x32311142, + }, /* 490 */ + { + 0x13132421, + 0x23115131, + 0x12311225, + }, /* 491 */ + { + 0x12223421, + 0x13115222, + 0x22311233, + }, /* 492 */ + { + 0x13133132, + 0x13115321, + 0x32311241, + }, /* 493 */ + { + 0x12224132, + 0x13116131, + 0x12311324, + }, /* 494 */ + { + 0x13133231, + 0x52211114, + 0x22311332, + }, /* 495 */ + { + 0x11315132, + 0x62211122, + 0x12311423, + }, /* 496 */ + { + 0x12224231, + 0x12211163, + 0x22311431, + }, /* 497 */ + { + 0x31321115, + 0x52211213, + 0x12311522, + }, /* 498 */ + { + 0x41321123, + 0x62211221, + 0x12311621, + }, /* 499 */ + { + 0x51321131, + 0x12211262, + 0x13221134, + }, /* 500 */ + { + 0x31321214, + 0x52211312, + 0x23221142, + }, /* 501 */ + { + 0x41321222, + 0x12211361, + 0x12312134, + }, /* 502 */ + { + 0x31321313, + 0x52211411, + 0x13221233, + }, /* 503 */ + { + 0x41321321, + 0x43121114, + 0x23221241, + }, /* 504 */ + { + 0x31321412, + 0x53121122, + 0x12312233, + }, /* 505 */ + { + 0x31321511, + 0x42212114, + 0x13221332, + }, /* 506 */ + { + 0x22231115, + 0x43121213, + 0x12312332, + }, /* 507 */ + { + 0x32231123, + 0x53121221, + 0x13221431, + }, /* 508 */ + { + 0x42231131, + 0x42212213, + 0x12312431, + }, /* 509 */ + { + 0x21322115, + 0x52212221, + 0x14131142, + }, /* 510 */ + { + 0x22231214, + 0x42212312, + 0x13222142, + }, /* 511 */ + { + 0x41322131, + 0x43121411, + 0x14131241, + }, /* 512 */ + { + 0x21322214, + 0x42212411, + 0x12313142, + }, /* 513 */ + { + 0x31322222, + 0x33122114, + 0x13222241, + }, /* 514 */ + { + 0x32231321, + 0x43122122, + 0x12313241, + }, /* 515 */ + { + 0x21322313, + 0x32213114, + 0x21411125, + }, /* 516 */ + { + 0x22231412, + 0x33122213, + 0x31411133, + }, /* 517 */ + { + 0x21322412, + 0x43122221, + 0x41411141, + }, /* 518 */ + { + 0x22231511, + 0x32213213, + 0x11411216, + }, /* 519 */ + { + 0x21322511, + 0x42213221, + 0x21411224, + }, /* 520 */ + { + 0x13141115, + 0x32213312, + 0x31411232, + }, /* 521 */ + { + 0x23141123, + 0x33122411, + 0x11411315, + }, /* 522 */ + { + 0x33141131, + 0x32213411, + 0x21411323, + }, /* 523 */ + { + 0x12232115, + 0x23123114, + 0x31411331, + }, /* 524 */ + { + 0x13141214, + 0x33123122, + 0x11411414, + }, /* 525 */ + { + 0x23141222, + 0x22214114, + 0x21411422, + }, /* 526 */ + { + 0x11323115, + 0x23123213, + 0x11411513, + }, /* 527 */ + { + 0x12232214, + 0x33123221, + 0x21411521, + }, /* 528 */ + { + 0x22232222, + 0x22214213, + 0x11411612, + }, /* 529 */ + { + 0x23141321, + 0x32214221, + 0x12321125, + }, /* 530 */ + { + 0x11323214, + 0x22214312, + 0x22321133, + }, /* 531 */ + { + 0x21323222, + 0x23123411, + 0x32321141, + }, /* 532 */ + { + 0x13141412, + 0x22214411, + 0x11412125, + }, /* 533 */ + { + 0x11323313, + 0x13124114, + 0x12321224, + }, /* 534 */ + { + 0x12232412, + 0x23124122, + 0x22321232, + }, /* 535 */ + { + 0x13141511, + 0x12215114, + 0x11412224, + }, /* 536 */ + { + 0x12232511, + 0x13124213, + 0x21412232, + }, /* 537 */ + { + 0x13142123, + 0x23124221, + 0x22321331, + }, /* 538 */ + { + 0x23142131, + 0x12215213, + 0x11412323, + }, /* 539 */ + { + 0x12233123, + 0x22215221, + 0x12321422, + }, /* 540 */ + { + 0x13142222, + 0x12215312, + 0x11412422, + }, /* 541 */ + { + 0x11324123, + 0x13124411, + 0x12321521, + }, /* 542 */ + { + 0x12233222, + 0x12215411, + 0x11412521, + }, /* 543 */ + { + 0x13142321, + 0x13125122, + 0x13231133, + }, /* 544 */ + { + 0x11324222, + 0x12216122, + 0x23231141, + }, /* 545 */ + { + 0x12233321, + 0x13125221, + 0x12322133, + }, /* 546 */ + { + 0x13143131, + 0x12216221, + 0x13231232, + }, /* 547 */ + { + 0x11325131, + 0x61311113, + 0x11413133, + }, /* 548 */ + { + 0x31331114, + 0x11311154, + 0x12322232, + }, /* 549 */ + { + 0x41331122, + 0x21311162, + 0x13231331, + }, /* 550 */ + { + 0x31331213, + 0x61311212, + 0x11413232, + }, /* 551 */ + { + 0x41331221, + 0x11311253, + 0x12322331, + }, /* 552 */ + { + 0x31331312, + 0x21311261, + 0x11413331, + }, /* 553 */ + { + 0x31331411, + 0x61311311, + 0x14141141, + }, /* 554 */ + { + 0x22241114, + 0x11311352, + 0x13232141, + }, /* 555 */ + { + 0x32241122, + 0x11311451, + 0x12323141, + }, /* 556 */ + { + 0x21332114, + 0x52221113, + 0x11414141, + }, /* 557 */ + { + 0x22241213, + 0x62221121, + 0x11421116, + }, /* 558 */ + { + 0x32241221, + 0x12221162, + 0x21421124, + }, /* 559 */ + { + 0x21332213, + 0x51312113, + 0x31421132, + }, /* 560 */ + { + 0x31332221, + 0x61312121, + 0x11421215, + }, /* 561 */ + { + 0x21332312, + 0x11312162, + 0x21421223, + }, /* 562 */ + { + 0x22241411, + 0x12221261, + 0x31421231, + }, /* 563 */ + { + 0x21332411, + 0x51312212, + 0x11421314, + }, /* 564 */ + { + 0x13151114, + 0x52221311, + 0x21421322, + }, /* 565 */ + { + 0x23151122, + 0x11312261, + 0x11421413, + }, /* 566 */ + { + 0x12242114, + 0x51312311, + 0x21421421, + }, /* 567 */ + { + 0x13151213, + 0x43131113, + 0x11421512, + }, /* 568 */ + { + 0x23151221, + 0x53131121, + 0x11421611, + }, /* 569 */ + { + 0x11333114, + 0x42222113, + 0x12331124, + }, /* 570 */ + { + 0x12242213, + 0x43131212, + 0x22331132, + }, /* 571 */ + { + 0x22242221, + 0x41313113, + 0x11422124, + }, /* 572 */ + { + 0x11333213, + 0x51313121, + 0x12331223, + }, /* 573 */ + { + 0x21333221, + 0x43131311, + 0x22331231, + }, /* 574 */ + { + 0x13151411, + 0x41313212, + 0x11422223, + }, /* 575 */ + { + 0x11333312, + 0x42222311, + 0x21422231, + }, /* 576 */ + { + 0x12242411, + 0x41313311, + 0x11422322, + }, /* 577 */ + { + 0x11333411, + 0x33132113, + 0x12331421, + }, /* 578 */ + { + 0x12243122, + 0x43132121, + 0x11422421, + }, /* 579 */ + { + 0x11334122, + 0x32223113, + 0x13241132, + }, /* 580 */ + { + 0x11334221, + 0x33132212, + 0x12332132, + }, /* 581 */ + { + 0x41341121, + 0x31314113, + 0x13241231, + }, /* 582 */ + { + 0x31341311, + 0x32223212, + 0x11423132, + }, /* 583 */ + { + 0x32251121, + 0x33132311, + 0x12332231, + }, /* 584 */ + { + 0x22251212, + 0x31314212, + 0x11423231, + }, /* 585 */ + { + 0x22251311, + 0x32223311, + 0x11431115, + }, /* 586 */ + { + 0x13161113, + 0x31314311, + 0x21431123, + }, /* 587 */ + { + 0x12252113, + 0x23133113, + 0x31431131, + }, /* 588 */ + { + 0x11343113, + 0x33133121, + 0x11431214, + }, /* 589 */ + { + 0x13161311, + 0x22224113, + 0x21431222, + }, /* 590 */ + { + 0x12252311, + 0x23133212, + 0x11431313, + }, /* 591 */ + { + 0x24111125, + 0x21315113, + 0x21431321, + }, /* 592 */ + { + 0x14111216, + 0x22224212, + 0x11431412, + }, /* 593 */ + { + 0x24111224, + 0x23133311, + 0x11431511, + }, /* 594 */ + { + 0x14111315, + 0x21315212, + 0x12341123, + }, /* 595 */ + { + 0x24111323, + 0x22224311, + 0x22341131, + }, /* 596 */ + { + 0x34111331, + 0x21315311, + 0x11432123, + }, /* 597 */ + { + 0x14111414, + 0x13134113, + 0x12341222, + }, /* 598 */ + { + 0x24111422, + 0x23134121, + 0x11432222, + }, /* 599 */ + { + 0x14111513, + 0x12225113, + 0x12341321, + }, /* 600 */ + { + 0x24111521, + 0x13134212, + 0x11432321, + }, /* 601 */ + { + 0x14112125, + 0x11316113, + 0x13251131, + }, /* 602 */ + { + 0x24112133, + 0x12225212, + 0x12342131, + }, /* 603 */ + { + 0x34112141, + 0x13134311, + 0x11433131, + }, /* 604 */ + { + 0x14112224, + 0x11316212, + 0x11441114, + }, /* 605 */ + { + 0x24112232, + 0x12225311, + 0x21441122, + }, /* 606 */ + { + 0x14112323, + 0x11316311, + 0x11441213, + }, /* 607 */ + { + 0x24112331, + 0x13135121, + 0x21441221, + }, /* 608 */ + { + 0x14112422, + 0x12226121, + 0x11441312, + }, /* 609 */ + { + 0x14112521, + 0x61321112, + 0x11441411, + }, /* 610 */ + { + 0x14113133, + 0x11321153, + 0x12351122, + }, /* 611 */ + { + 0x24113141, + 0x21321161, + 0x11442122, + }, /* 612 */ + { + 0x14113232, + 0x61321211, + 0x12351221, + }, /* 613 */ + { + 0x14113331, + 0x11321252, + 0x11442221, + }, /* 614 */ + { + 0x14114141, + 0x11321351, + 0x11451113, + }, /* 615 */ + { + 0x23211116, + 0x52231112, + 0x21451121, + }, /* 616 */ + { + 0x33211124, + 0x12231161, + 0x11451212, + }, /* 617 */ + { + 0x43211132, + 0x51322112, + 0x11451311, + }, /* 618 */ + { + 0x23211215, + 0x52231211, + 0x12361121, + }, /* 619 */ + { + 0x33211223, + 0x11322161, + 0x11452121, + }, /* 620 */ + { + 0x23211314, + 0x51322211, + 0x15111143, + }, /* 621 */ + { + 0x33211322, + 0x43141112, + 0x25111151, + }, /* 622 */ + { + 0x23211413, + 0x42232112, + 0x15111242, + }, /* 623 */ + { + 0x33211421, + 0x43141211, + 0x15111341, + }, /* 624 */ + { + 0x23211512, + 0x41323112, + 0x15112151, + }, /* 625 */ + { + 0x14121116, + 0x42232211, + 0x14211134, + }, /* 626 */ + { + 0x24121124, + 0x41323211, + 0x24211142, + }, /* 627 */ + { + 0x34121132, + 0x33142112, + 0x14211233, + }, /* 628 */ + { + 0x13212116, + 0x32233112, + 0x24211241, + }, /* 629 */ + { + 0x14121215, + 0x33142211, + 0x14211332, + }, /* 630 */ + { + 0x33212132, + 0x31324112, + 0x14211431, + }, /* 631 */ + { + 0x34121231, + 0x32233211, + 0x15121142, + }, /* 632 */ + { + 0x13212215, + 0x31324211, + 0x14212142, + }, /* 633 */ + { + 0x23212223, + 0x23143112, + 0x15121241, + }, /* 634 */ + { + 0x33212231, + 0x22234112, + 0x14212241, + }, /* 635 */ + { + 0x13212314, + 0x23143211, + 0x13311125, + }, /* 636 */ + { + 0x14121413, + 0x21325112, + 0x23311133, + }, /* 637 */ + { + 0x24121421, + 0x22234211, + 0x33311141, + }, /* 638 */ + { + 0x13212413, + 0x21325211, + 0x13311224, + }, /* 639 */ + { + 0x23212421, + 0x13144112, + 0x23311232, + }, /* 640 */ + { + 0x14121611, + 0x12235112, + 0x13311323, + }, /* 641 */ + { + 0x14122124, + 0x13144211, + 0x23311331, + }, /* 642 */ + { + 0x24122132, + 0x11326112, + 0x13311422, + }, /* 643 */ + { + 0x13213124, + 0x12235211, + 0x13311521, + }, /* 644 */ + { + 0x14122223, + 0x11326211, + 0x14221133, + }, /* 645 */ + { + 0x24122231, + 0x61331111, + 0x24221141, + }, /* 646 */ + { + 0x13213223, + 0x11331152, + 0x13312133, + }, /* 647 */ + { + 0x23213231, + 0x11331251, + 0x14221232, + }, /* 648 */ + { + 0x13213322, + 0x52241111, + 0x13312232, + }, /* 649 */ + { + 0x14122421, + 0x51332111, + 0x14221331, + }, /* 650 */ + { + 0x14123132, + 0x43151111, + 0x13312331, + }, /* 651 */ + { + 0x13214132, + 0x42242111, + 0x15131141, + }, /* 652 */ + { + 0x14123231, + 0x41333111, + 0x14222141, + }, /* 653 */ + { + 0x13214231, + 0x33152111, + 0x13313141, + }, /* 654 */ + { + 0x32311115, + 0x32243111, + 0x12411116, + }, /* 655 */ + { + 0x42311123, + 0x31334111, + 0x22411124, + }, /* 656 */ + { + 0x52311131, + 0x23153111, + 0x32411132, + }, /* 657 */ + { + 0x32311214, + 0x22244111, + 0x12411215, + }, /* 658 */ + { + 0x42311222, + 0x21335111, + 0x22411223, + }, /* 659 */ + { + 0x32311313, + 0x13154111, + 0x32411231, + }, /* 660 */ + { + 0x42311321, + 0x12245111, + 0x12411314, + }, /* 661 */ + { + 0x32311412, + 0x11336111, + 0x22411322, + }, /* 662 */ + { + 0x32311511, + 0x11341151, + 0x12411413, + }, /* 663 */ + { + 0x23221115, + 0x44111114, + 0x22411421, + }, /* 664 */ + { + 0x33221123, + 0x54111122, + 0x12411512, + }, /* 665 */ + { + 0x22312115, + 0x44111213, + 0x12411611, + }, /* 666 */ + { + 0x23221214, + 0x54111221, + 0x13321124, + }, /* 667 */ + { + 0x33221222, + 0x44111312, + 0x23321132, + }, /* 668 */ + { + 0x22312214, + 0x44111411, + 0x12412124, + }, /* 669 */ + { + 0x32312222, + 0x34112114, + 0x13321223, + }, /* 670 */ + { + 0x33221321, + 0x44112122, + 0x23321231, + }, /* 671 */ + { + 0x22312313, + 0x34112213, + 0x12412223, + }, /* 672 */ + { + 0x23221412, + 0x44112221, + 0x22412231, + }, /* 673 */ + { + 0x22312412, + 0x34112312, + 0x12412322, + }, /* 674 */ + { + 0x23221511, + 0x34112411, + 0x13321421, + }, /* 675 */ + { + 0x22312511, + 0x24113114, + 0x12412421, + }, /* 676 */ + { + 0x14131115, + 0x34113122, + 0x14231132, + }, /* 677 */ + { + 0x24131123, + 0x24113213, + 0x13322132, + }, /* 678 */ + { + 0x13222115, + 0x34113221, + 0x14231231, + }, /* 679 */ + { + 0x14131214, + 0x24113312, + 0x12413132, + }, /* 680 */ + { + 0x33222131, + 0x24113411, + 0x13322231, + }, /* 681 */ + { + 0x12313115, + 0x14114114, + 0x12413231, + }, /* 682 */ + { + 0x13222214, + 0x24114122, + 0x21511115, + }, /* 683 */ + { + 0x23222222, + 0x14114213, + 0x31511123, + }, /* 684 */ + { + 0x24131321, + 0x24114221, + 0x41511131, + }, /* 685 */ + { + 0x12313214, + 0x14114312, + 0x21511214, + }, /* 686 */ + { + 0x22313222, + 0x14114411, + 0x31511222, + }, /* 687 */ + { + 0x14131412, + 0x14115122, + 0x21511313, + }, /* 688 */ + { + 0x12313313, + 0x14115221, + 0x31511321, + }, /* 689 */ + { + 0x13222412, + 0x53211113, + 0x21511412, + }, /* 690 */ + { + 0x14131511, + 0x63211121, + 0x21511511, + }, /* 691 */ + { + 0x13222511, + 0x13211162, + 0x12421115, + }, /* 692 */ + { + 0x14132123, + 0x53211212, + 0x22421123, + }, /* 693 */ + { + 0x24132131, + 0x13211261, + 0x32421131, + }, /* 694 */ + { + 0x13223123, + 0x53211311, + 0x11512115, + }, /* 695 */ + { + 0x14132222, + 0x44121113, + 0x12421214, + }, /* 696 */ + { + 0x12314123, + 0x54121121, + 0x22421222, + }, /* 697 */ + { + 0x13223222, + 0x43212113, + 0x11512214, + }, /* 698 */ + { + 0x14132321, + 0x44121212, + 0x21512222, + }, /* 699 */ + { + 0x12314222, + 0x43212212, + 0x22421321, + }, /* 700 */ + { + 0x13223321, + 0x44121311, + 0x11512313, + }, /* 701 */ + { + 0x14133131, + 0x43212311, + 0x12421412, + }, /* 702 */ + { + 0x13224131, + 0x34122113, + 0x11512412, + }, /* 703 */ + { + 0x12315131, + 0x44122121, + 0x12421511, + }, /* 704 */ + { + 0x41411114, + 0x33213113, + 0x11512511, + }, /* 705 */ + { + 0x51411122, + 0x34122212, + 0x13331123, + }, /* 706 */ + { + 0x41411213, + 0x33213212, + 0x23331131, + }, /* 707 */ + { + 0x51411221, + 0x34122311, + 0x12422123, + }, /* 708 */ + { + 0x41411312, + 0x33213311, + 0x13331222, + }, /* 709 */ + { + 0x41411411, + 0x24123113, + 0x11513123, + }, /* 710 */ + { + 0x32321114, + 0x34123121, + 0x12422222, + }, /* 711 */ + { + 0x42321122, + 0x23214113, + 0x13331321, + }, /* 712 */ + { + 0x31412114, + 0x24123212, + 0x11513222, + }, /* 713 */ + { + 0x41412122, + 0x23214212, + 0x12422321, + }, /* 714 */ + { + 0x42321221, + 0x24123311, + 0x11513321, + }, /* 715 */ + { + 0x31412213, + 0x23214311, + 0x14241131, + }, /* 716 */ + { + 0x41412221, + 0x14124113, + 0x13332131, + }, /* 717 */ + { + 0x31412312, + 0x24124121, + 0x12423131, + }, /* 718 */ + { + 0x32321411, + 0x13215113, + 0x11514131, + }, /* 719 */ + { + 0x31412411, + 0x14124212, + 0x21521114, + }, /* 720 */ + { + 0x23231114, + 0x13215212, + 0x31521122, + }, /* 721 */ + { + 0x33231122, + 0x14124311, + 0x21521213, + }, /* 722 */ + { + 0x22322114, + 0x13215311, + 0x31521221, + }, /* 723 */ + { + 0x23231213, + 0x14125121, + 0x21521312, + }, /* 724 */ + { + 0x33231221, + 0x13216121, + 0x21521411, + }, /* 725 */ + { + 0x21413114, + 0x62311112, + 0x12431114, + }, /* 726 */ + { + 0x22322213, + 0x12311153, + 0x22431122, + }, /* 727 */ + { + 0x32322221, + 0x22311161, + 0x11522114, + }, /* 728 */ + { + 0x21413213, + 0x62311211, + 0x12431213, + }, /* 729 */ + { + 0x31413221, + 0x12311252, + 0x22431221, + }, /* 730 */ + { + 0x23231411, + 0x12311351, + 0x11522213, + }, /* 731 */ + { + 0x21413312, + 0x53221112, + 0x21522221, + }, /* 732 */ + { + 0x22322411, + 0x13221161, + 0x11522312, + }, /* 733 */ + { + 0x21413411, + 0x52312112, + 0x12431411, + }, /* 734 */ + { + 0x14141114, + 0x53221211, + 0x11522411, + }, /* 735 */ + { + 0x24141122, + 0x12312161, + 0x13341122, + }, /* 736 */ + { + 0x13232114, + 0x52312211, + 0x12432122, + }, /* 737 */ + { + 0x14141213, + 0x44131112, + 0x13341221, + }, /* 738 */ + { + 0x24141221, + 0x43222112, + 0x11523122, + }, /* 739 */ + { + 0x12323114, + 0x44131211, + 0x12432221, + }, /* 740 */ + { + 0x13232213, + 0x42313112, + 0x11523221, + }, /* 741 */ + { + 0x23232221, + 0x43222211, + 0x21531113, + }, /* 742 */ + { + 0x11414114, + 0x42313211, + 0x31531121, + }, /* 743 */ + { + 0x12323213, + 0x34132112, + 0x21531212, + }, /* 744 */ + { + 0x22323221, + 0x33223112, + 0x21531311, + }, /* 745 */ + { + 0x14141411, + 0x34132211, + 0x12441113, + }, /* 746 */ + { + 0x11414213, + 0x32314112, + 0x22441121, + }, /* 747 */ + { + 0x21414221, + 0x33223211, + 0x11532113, + }, /* 748 */ + { + 0x13232411, + 0x32314211, + 0x12441212, + }, /* 749 */ + { + 0x11414312, + 0x24133112, + 0x11532212, + }, /* 750 */ + { + 0x14142122, + 0x23224112, + 0x12441311, + }, /* 751 */ + { + 0x13233122, + 0x24133211, + 0x11532311, + }, /* 752 */ + { + 0x14142221, + 0x22315112, + 0x13351121, + }, /* 753 */ + { + 0x12324122, + 0x23224211, + 0x12442121, + }, /* 754 */ + { + 0x13233221, + 0x22315211, + 0x11533121, + }, /* 755 */ + { + 0x11415122, + 0x14134112, + 0x21541112, + }, /* 756 */ + { + 0x12324221, + 0x13225112, + 0x21541211, + }, /* 757 */ + { + 0x11415221, + 0x14134211, + 0x12451112, + }, /* 758 */ + { + 0x41421113, + 0x12316112, + 0x11542112, + }, /* 759 */ + { + 0x51421121, + 0x13225211, + 0x12451211, + }, /* 760 */ + { + 0x41421212, + 0x12316211, + 0x11542211, + }, /* 761 */ + { + 0x41421311, + 0x11411144, + 0x16111142, + }, /* 762 */ + { + 0x32331113, + 0x21411152, + 0x16111241, + }, /* 763 */ + { + 0x42331121, + 0x11411243, + 0x15211133, + }, /* 764 */ + { + 0x31422113, + 0x21411251, + 0x25211141, + }, /* 765 */ + { + 0x41422121, + 0x11411342, + 0x15211232, + }, /* 766 */ + { + 0x31422212, + 0x11411441, + 0x15211331, + }, /* 767 */ + { + 0x32331311, + 0x62321111, + 0x16121141, + }, /* 768 */ + { + 0x31422311, + 0x12321152, + 0x15212141, + }, /* 769 */ + { + 0x23241113, + 0x61412111, + 0x14311124, + }, /* 770 */ + { + 0x33241121, + 0x11412152, + 0x24311132, + }, /* 771 */ + { + 0x22332113, + 0x12321251, + 0x14311223, + }, /* 772 */ + { + 0x23241212, + 0x11412251, + 0x24311231, + }, /* 773 */ + { + 0x21423113, + 0x53231111, + 0x14311322, + }, /* 774 */ + { + 0x22332212, + 0x52322111, + 0x14311421, + }, /* 775 */ + { + 0x23241311, + 0x51413111, + 0x15221132, + }, /* 776 */ + { + 0x21423212, + 0x44141111, + 0x14312132, + }, /* 777 */ + { + 0x22332311, + 0x43232111, + 0x15221231, + }, /* 778 */ + { + 0x21423311, + 0x42323111, + 0x14312231, + }, /* 779 */ + { + 0x14151113, + 0x41414111, + 0x13411115, + }, /* 780 */ + { + 0x24151121, + 0x34142111, + 0x23411123, + }, /* 781 */ + { + 0x13242113, + 0x33233111, + 0x33411131, + }, /* 782 */ + { + 0x23242121, + 0x32324111, + 0x13411214, + }, /* 783 */ + { + 0x12333113, + 0x31415111, + 0x23411222, + }, /* 784 */ + { + 0x13242212, + 0x24143111, + 0x13411313, + }, /* 785 */ + { + 0x14151311, + 0x23234111, + 0x23411321, + }, /* 786 */ + { + 0x11424113, + 0x22325111, + 0x13411412, + }, /* 787 */ + { + 0x12333212, + 0x21416111, + 0x13411511, + }, /* 788 */ + { + 0x13242311, + 0x14144111, + 0x14321123, + }, /* 789 */ + { + 0x11424212, + 0x13235111, + 0x24321131, + }, /* 790 */ + { + 0x12333311, + 0x12326111, + 0x13412123, + }, /* 791 */ + { + 0x11424311, + 0x11421143, + 0x23412131, + }, /* 792 */ + { + 0x13243121, + 0x21421151, + 0x13412222, + }, /* 793 */ + { + 0x11425121, + 0x11421242, + 0x14321321, + }, /* 794 */ + { + 0x41431211, + 0x11421341, + 0x13412321, + }, /* 795 */ + { + 0x31432112, + 0x12331151, + 0x15231131, + }, /* 796 */ + { + 0x31432211, + 0x11422151, + 0x14322131, + }, /* 797 */ + { + 0x22342112, + 0x11431142, + 0x13413131, + }, /* 798 */ + { + 0x21433112, + 0x11431241, + 0x22511114, + }, /* 799 */ + { + 0x21433211, + 0x11441141, + 0x32511122, + }, /* 800 */ + { + 0x13252112, + 0x45111113, + 0x22511213, + }, /* 801 */ + { + 0x12343112, + 0x45111212, + 0x32511221, + }, /* 802 */ + { + 0x11434112, + 0x45111311, + 0x22511312, + }, /* 803 */ + { + 0x11434211, + 0x35112113, + 0x22511411, + }, /* 804 */ + { + 0x15111116, + 0x45112121, + 0x13421114, + }, /* 805 */ + { + 0x15111215, + 0x35112212, + 0x23421122, + }, /* 806 */ + { + 0x25111223, + 0x35112311, + 0x12512114, + }, /* 807 */ + { + 0x15111314, + 0x25113113, + 0x22512122, + }, /* 808 */ + { + 0x15111413, + 0x35113121, + 0x23421221, + }, /* 809 */ + { + 0x15111512, + 0x25113212, + 0x12512213, + }, /* 810 */ + { + 0x15112124, + 0x25113311, + 0x13421312, + }, /* 811 */ + { + 0x15112223, + 0x15114113, + 0x12512312, + }, /* 812 */ + { + 0x15112322, + 0x25114121, + 0x13421411, + }, /* 813 */ + { + 0x15112421, + 0x15114212, + 0x12512411, + }, /* 814 */ + { + 0x15113132, + 0x15114311, + 0x14331122, + }, /* 815 */ + { + 0x15113231, + 0x15115121, + 0x13422122, + }, /* 816 */ + { + 0x24211115, + 0x54211112, + 0x14331221, + }, /* 817 */ + { + 0x24211214, + 0x14211161, + 0x12513122, + }, /* 818 */ + { + 0x34211222, + 0x54211211, + 0x13422221, + }, /* 819 */ + { + 0x24211313, + 0x45121112, + 0x12513221, + }, /* 820 */ + { + 0x34211321, + 0x44212112, + 0x31611113, + }, /* 821 */ + { + 0x24211412, + 0x45121211, + 0x41611121, + }, /* 822 */ + { + 0x24211511, + 0x44212211, + 0x31611212, + }, /* 823 */ + { + 0x15121115, + 0x35122112, + 0x31611311, + }, /* 824 */ + { + 0x25121123, + 0x34213112, + 0x22521113, + }, /* 825 */ + { + 0x14212115, + 0x35122211, + 0x32521121, + }, /* 826 */ + { + 0x24212123, + 0x34213211, + 0x21612113, + }, /* 827 */ + { + 0x25121222, + 0x25123112, + 0x22521212, + }, /* 828 */ + { + 0x14212214, + 0x24214112, + 0x21612212, + }, /* 829 */ + { + 0x24212222, + 0x25123211, + 0x22521311, + }, /* 830 */ + { + 0x14212313, + 0x24214211, + 0x21612311, + }, /* 831 */ + { + 0x24212321, + 0x15124112, + 0x13431113, + }, /* 832 */ + { + 0x14212412, + 0x14215112, + 0x23431121, + }, /* 833 */ + { + 0x15121511, + 0x15124211, + 0x12522113, + }, /* 834 */ + { + 0x14212511, + 0x14215211, + 0x13431212, + }, /* 835 */ + { + 0x15122123, + 0x63311111, + 0x11613113, + }, /* 836 */ + { + 0x25122131, + 0x13311152, + 0x12522212, + }, /* 837 */ + { + 0x14213123, + 0x13311251, + 0x13431311, + }, /* 838 */ + { + 0x24213131, + 0x54221111, + 0x11613212, + }, /* 839 */ + { + 0x14213222, + 0x53312111, + 0x12522311, + }, /* 840 */ + { + 0x15122321, + 0x45131111, + 0x11613311, + }, /* 841 */ + { + 0x14213321, + 0x44222111, + 0x14341121, + }, /* 842 */ + { + 0x15123131, + 0x43313111, + 0x13432121, + }, /* 843 */ + { + 0x14214131, + 0x35132111, + 0x12523121, + }, /* 844 */ + { + 0x33311114, + 0x34223111, + 0x11614121, + }, /* 845 */ + { + 0x33311213, + 0x33314111, + 0x31621112, + }, /* 846 */ + { + 0x33311312, + 0x25133111, + 0x31621211, + }, /* 847 */ + { + 0x33311411, + 0x24224111, + 0x22531112, + }, /* 848 */ + { + 0x24221114, + 0x23315111, + 0x21622112, + }, /* 849 */ + { + 0x23312114, + 0x15134111, + 0x22531211, + }, /* 850 */ + { + 0x33312122, + 0x14225111, + 0x21622211, + }, /* 851 */ + { + 0x34221221, + 0x13316111, + 0x13441112, + }, /* 852 */ + { + 0x23312213, + 0x12411143, + 0x12532112, + }, /* 853 */ + { + 0x33312221, + 0x22411151, + 0x13441211, + }, /* 854 */ + { + 0x23312312, + 0x12411242, + 0x11623112, + }, /* 855 */ + { + 0x24221411, + 0x12411341, + 0x12532211, + }, /* 856 */ + { + 0x23312411, + 0x13321151, + 0x11623211, + }, /* 857 */ + { + 0x15131114, + 0x12412151, + 0x31631111, + }, /* 858 */ + { + 0x14222114, + 0x11511134, + 0x22541111, + }, /* 859 */ + { + 0x15131213, + 0x21511142, + 0x21632111, + }, /* 860 */ + { + 0x25131221, + 0x11511233, + 0x13451111, + }, /* 861 */ + { + 0x13313114, + 0x21511241, + 0x12542111, + }, /* 862 */ + { + 0x14222213, + 0x11511332, + 0x11633111, + }, /* 863 */ + { + 0x15131312, + 0x11511431, + 0x16211132, + }, /* 864 */ + { + 0x13313213, + 0x12421142, + 0x16211231, + }, /* 865 */ + { + 0x14222312, + 0x11512142, + 0x15311123, + }, /* 866 */ + { + 0x15131411, + 0x12421241, + 0x25311131, + }, /* 867 */ + { + 0x13313312, + 0x11512241, + 0x15311222, + }, /* 868 */ + { + 0x14222411, + 0x11521133, + 0x15311321, + }, /* 869 */ + { + 0x15132122, + 0x21521141, + 0x16221131, + }, /* 870 */ + { + 0x14223122, + 0x11521232, + 0x15312131, + }, /* 871 */ + { + 0x15132221, + 0x11521331, + 0x14411114, + }, /* 872 */ + { + 0x13314122, + 0x12431141, + 0x24411122, + }, /* 873 */ + { + 0x14223221, + 0x11522141, + 0x14411213, + }, /* 874 */ + { + 0x13314221, + 0x11531132, + 0x24411221, + }, /* 875 */ + { + 0x42411113, + 0x11531231, + 0x14411312, + }, /* 876 */ + { + 0x42411212, + 0x11541131, + 0x14411411, + }, /* 877 */ + { + 0x42411311, + 0x36112112, + 0x15321122, + }, /* 878 */ + { + 0x33321113, + 0x36112211, + 0x14412122, + }, /* 879 */ + { + 0x32412113, + 0x26113112, + 0x15321221, + }, /* 880 */ + { + 0x42412121, + 0x26113211, + 0x14412221, + }, /* 881 */ + { + 0x32412212, + 0x16114112, + 0x23511113, + }, /* 882 */ + { + 0x33321311, + 0x16114211, + 0x33511121, + }, /* 883 */ + { + 0x32412311, + 0x45212111, + 0x23511212, + }, /* 884 */ + { + 0x24231113, + 0x36122111, + 0x23511311, + }, /* 885 */ + { + 0x34231121, + 0x35213111, + 0x14421113, + }, /* 886 */ + { + 0x23322113, + 0x26123111, + 0x24421121, + }, /* 887 */ + { + 0x33322121, + 0x25214111, + 0x13512113, + }, /* 888 */ + { + 0x22413113, + 0x16124111, + 0x23512121, + }, /* 889 */ + { + 0x23322212, + 0x15215111, + 0x13512212, + }, /* 890 */ + { + 0x24231311, + 0x14311151, + 0x14421311, + }, /* 891 */ + { + 0x22413212, + 0x13411142, + 0x13512311, + }, /* 892 */ + { + 0x23322311, + 0x13411241, + 0x15331121, + }, /* 893 */ + { + 0x22413311, + 0x12511133, + 0x14422121, + }, /* 894 */ + { + 0x15141113, + 0x22511141, + 0x13513121, + }, /* 895 */ + { + 0x25141121, + 0x12511232, + 0x32611112, + }, /* 896 */ + { + 0x14232113, + 0x12511331, + 0x32611211, + }, /* 897 */ + { + 0x24232121, + 0x13421141, + 0x23521112, + }, /* 898 */ + { + 0x13323113, + 0x12512141, + 0x22612112, + }, /* 899 */ + { + 0x14232212, + 0x11611124, + 0x23521211, + }, /* 900 */ + { + 0x15141311, + 0x21611132, + 0x22612211, + }, /* 901 */ + { + 0x12414113, + 0x11611223, + 0x14431112, + }, /* 902 */ + { + 0x13323212, + 0x21611231, + 0x13522112, + }, /* 903 */ + { + 0x14232311, + 0x11611322, + 0x14431211, + }, /* 904 */ + { + 0x12414212, + 0x11611421, + 0x12613112, + }, /* 905 */ + { + 0x13323311, + 0x12521132, + 0x13522211, + }, /* 906 */ + { + 0x15142121, + 0x11612132, + 0x12613211, + }, /* 907 */ + { + 0x14233121, + 0x12521231, + 0x32621111, + }, /* 908 */ + { + 0x13324121, + 0x11612231, + 0x23531111, + }, /* 909 */ + { + 0x12415121, + 0x11621123, + 0x22622111, + }, /* 910 */ + { + 0x51511112, + 0x21621131, + 0x14441111, + }, /* 911 */ + { + 0x51511211, + 0x11621222, + 0x13532111, + }, /* 912 */ + { + 0x42421112, + 0x11621321, + 0x12623111, + }, /* 913 */ + { + 0x41512112, + 0x12531131, + 0x16311122, + }, /* 914 */ + { + 0x42421211, + 0x11622131, + 0x16311221, + }, /* 915 */ + { + 0x41512211, + 0x11631122, + 0x15411113, + }, /* 916 */ + { + 0x33331112, + 0x11631221, + 0x25411121, + }, /* 917 */ + { + 0x32422112, + 0x14411141, + 0x15411212, + }, /* 918 */ + { + 0x33331211, + 0x13511132, + 0x15411311, + }, /* 919 */ + { + 0x31513112, + 0x13511231, + 0x16321121, + }, /* 920 */ + { + 0x32422211, + 0x12611123, + 0x15412121, + }, /* 921 */ + { + 0x31513211, + 0x22611131, + 0x24511112, + }, /* 922 */ + { + 0x24241112, + 0x12611222, + 0x24511211, + }, /* 923 */ + { + 0x23332112, + 0x12611321, + 0x15421112, + }, /* 924 */ + { + 0x24241211, + 0x13521131, + 0x14512112, + }, /* 925 */ + { + 0x22423112, + 0x12612131, + 0x15421211, + }, /* 926 */ + { + 0x23332211, + 0x12621122, + 0x14512211, + }, /* 927 */ + { + 0x21514112, + 0x12621221, + 0x33611111, + }, /* 928 */ +}; + +#endif diff --git a/test/test_convert.c b/test/test_convert.c new file mode 100644 index 0000000..426ac81 --- /dev/null +++ b/test/test_convert.c @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "config.h" +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <zbar.h> +#include "test_images.h" + +#if 0 +static uint32_t formats[] = { + +}; +#endif + +int main(int argc, char *argv[]) +{ + zbar_set_verbosity(10); + + uint32_t srcfmt = fourcc('I', '4', '2', '0'); + if (argc > 1) + srcfmt = *(uint32_t *)argv[1]; + + zbar_image_t *img = zbar_image_create(); + zbar_image_set_size(img, 640, 480); + zbar_image_set_format(img, srcfmt); + if (test_image_bars(img)) + return (2); + + if (zbar_image_write(img, "/tmp/base")) + return (1); + return (0); +} diff --git a/test/test_cpp.cpp b/test/test_cpp.cpp new file mode 100644 index 0000000..1c60ece --- /dev/null +++ b/test/test_cpp.cpp @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ + +// NB do not put anything before this header +// it's here to check that we didn't omit any dependencies +#include <zbar.h> + +int main(int argc, char **argv) +{ + const char *video_dev = "/dev/video0"; + if (argc > 1) + video_dev = argv[1]; + + zbar::Processor proc = zbar::Processor(true, video_dev); + proc.set_visible(); + proc.set_active(); + try { + proc.user_wait(); + } catch (zbar::ClosedError &) { + } + + return (0); +} diff --git a/test/test_cpp_img.cpp b/test/test_cpp_img.cpp new file mode 100644 index 0000000..3b57fcb --- /dev/null +++ b/test/test_cpp_img.cpp @@ -0,0 +1,214 @@ +//------------------------------------------------------------------------ +// Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> +// +// This file is part of the ZBar Bar Code Reader. +// +// The ZBar Bar Code Reader is free software; you can redistribute it +// and/or modify it under the terms of the GNU Lesser Public License as +// published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// The ZBar Bar Code Reader is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser Public License for more details. +// +// You should have received a copy of the GNU Lesser Public License +// along with the ZBar Bar Code Reader; if not, write to the Free +// Software Foundation, Inc., 51 Franklin St, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// http://sourceforge.net/projects/zbar +//------------------------------------------------------------------------ + +// NB do not put anything before this header +// it's here to check that we didn't omit any dependencies +#include <zbar.h> + +#include <iomanip> +#include <iostream> +#include <sstream> +#include "test_images.h" + +bool debug = false; +bool verbose = false; +int errors = 0; +zbar::zbar_symbol_type_t expect_type = zbar::ZBAR_NONE; +std::string expect_data; + +template <class T> inline std::string to_string(const T &t) +{ + std::stringstream ss; + ss << t; + return ss.str(); +} + +static inline int error(const std::string &msg) +{ + errors++; + std::cerr << "ERROR: " << msg << std::endl; + if (debug) + abort(); + return (-1); +} + +static inline int check_loc(const zbar::Image &img, const zbar::Symbol &sym) +{ + int n = 0; + int w = img.get_width(); + int h = img.get_height(); + for (zbar::Symbol::PointIterator p(sym.point_begin()); p != sym.point_end(); + ++p, n++) { + zbar::Symbol::Point q(*p); + if (q.x < 0 || q.x >= w || q.y < 0 || q.y >= h) + error("location point out of range"); + } + return (!n); +} + +static inline int check_symbol(const zbar::Image &img, const zbar::Symbol &sym) +{ + zbar::zbar_symbol_type_t type(sym.get_type()); + std::string data(sym.get_data()); + + bool pass = expect_type && type == expect_type && data == expect_data && + sym.get_data_length() == expect_data.length() && + sym.get_quality() > 4; + if (pass) + pass = !check_loc(img, sym); + + if (verbose || !pass) + std::cerr << "decode Symbol: " << sym << std::endl; + + if (!expect_type) + error("unexpected"); + else if (!pass) + error(std::string("expected: ") + + zbar::zbar_get_symbol_name(expect_type) + " " + expect_data); + + expect_type = zbar::ZBAR_NONE; + expect_data = ""; + return (!pass); +} + +static inline int check_image(const zbar::Image &img) +{ + zbar::SymbolSet syms(img.get_symbols()); + int setn = syms.get_size(), countn = 0; + + int rc = 0; + for (zbar::SymbolIterator sym(syms.symbol_begin()); + sym != syms.symbol_end(); ++sym, ++countn) + rc |= check_symbol(img, *sym); + + if (countn != setn) + rc |= error("SymbolSet size mismatch: exp=" + to_string(setn) + + " act=" + to_string(countn)); + return (rc); +} + +static inline void expect(zbar::zbar_symbol_type_t type, std::string data) +{ + if (expect_type) + error(std::string("missing: ") + zbar_get_symbol_name(expect_type) + + " " + expect_data); + expect_type = type; + expect_data = data; +} + +class Handler : public zbar::Image::Handler +{ + void image_callback(zbar::Image &img); +}; + +void Handler::image_callback(zbar::Image &img) +{ + bool unexpected = !expect_type; + if (unexpected) + error("unexpected image callback"); + check_image(img); +} + +static inline int test_processor() +{ + // create processor w/no video and no window + zbar::Processor proc(debug, NULL); + Handler handler; + proc.set_handler(handler); + if (debug) { + proc.set_visible(); + proc.user_wait(); + } + + // generate barcode test image + zbar::Image rgb3(0, 0, "RGB3"); + + // test cast to C image + if (test_image_ean13(rgb3)) + error("failed to generate image"); + + // test decode + expect(zbar::ZBAR_EAN13, test_image_ean13_data); + proc.process_image(rgb3); + if (debug) + proc.user_wait(); + + expect(zbar::ZBAR_EAN13, test_image_ean13_data); + check_image(rgb3); + + if (rgb3.get_format() != zbar_fourcc('R', 'G', 'B', '3')) + error("image format mismatch"); + + expect(zbar::ZBAR_NONE, ""); + proc.set_config(zbar::ZBAR_EAN13, zbar::ZBAR_CFG_ENABLE, false); + proc.process_image(rgb3); + check_image(rgb3); + if (debug) + proc.user_wait(); + + proc.set_config("ean13.en"); + expect(zbar::ZBAR_EAN13, test_image_ean13_data); + proc << rgb3; + expect(zbar::ZBAR_EAN13, test_image_ean13_data); + check_image(rgb3); + if (debug) + proc.user_wait(); + + { + zbar::Image grey(rgb3.convert(zbar_fourcc('G', 'R', 'E', 'Y'))); + expect(zbar::ZBAR_EAN13, test_image_ean13_data); + proc << grey; + + zbar::Image y800 = grey.convert("Y800"); + expect(zbar::ZBAR_EAN13, test_image_ean13_data); + proc << y800; + } + if (debug) + // check image data retention + proc.user_wait(); + + expect(zbar::ZBAR_NONE, ""); + return (0); +} + +int main(int argc, char **argv) +{ + debug = (argc > 1 && std::string(argv[1]) == "-d"); + verbose = (debug || (argc > 1 && std::string(argv[1]) == "-v")); + + if (test_processor()) { + error("ERROR: Processor test FAILED"); + return (2); + } + + if (test_image_check_cleanup()) + error("cleanup failed"); + + if (errors) { + std::cout << "processor FAILED" << std::endl; + return (2); + } else { + std::cout << "processor PASSED." << std::endl; + return (0); + } +} diff --git a/test/test_dbus.c b/test/test_dbus.c new file mode 100644 index 0000000..60a415e --- /dev/null +++ b/test/test_dbus.c @@ -0,0 +1,254 @@ +/*------------------------------------------------------------------------ + * Copyright 2019 (c) Mauro Carvalho Chehab <mchehab+samsung@kernel.org> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + *------------------------------------------------------------------------*/ + +#include <argp.h> +#include <dbus/dbus.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define ZBAR_INTERFACE "org.linuxtv.Zbar1.Code" +#define ZBAR_SIGNAL_CODE "Code" +#define ZBAR_SIGNAL_TYPE "Type" +#define ZBAR_SIGNAL_DATA "Data" +#define ZBAR_SIGNAL_BINARY_DATA "BinaryData" + +#define PROGRAM_NAME "test_dbus" + +static const char doc[] = "\nTest if ZBar is sending codes via D-Bus\n"; + +static const struct argp_option options[] = { + { "count", 'c', "#codes", 0, "Stop after received #codes", 0 }, + { "time", 't', "#seconds", 0, "Stop after #seconds", 0 }, + { "log", 'l', "#file", 0, "Write log to #file", 0 }, + { "bin-log", 'b', "#file", 0, "Write binary log to #file", 0 }, + { "help", '?', 0, 0, "Give this help list", -1 }, + { "usage", -3, 0, 0, "Give a short usage message", 0 }, + { 0 } +}; + +static int max_msg = 0; +static int timeout = 0; +static FILE *log = NULL; +static FILE *bin_log = NULL; + +static error_t parse_opt(int k, char *optarg, struct argp_state *state) +{ + switch (k) { + case 'c': + max_msg = strtoul(optarg, NULL, 0); + break; + case 't': + timeout = strtoul(optarg, NULL, 0); + break; + case 'l': + log = fopen(optarg, "wb"); + break; + case 'b': + bin_log = fopen(optarg, "wb"); + break; + case '?': + argp_state_help(state, state->out_stream, + ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_DOC); + exit(0); + case -3: + argp_state_help(state, state->out_stream, ARGP_HELP_USAGE); + exit(0); + default: + return ARGP_ERR_UNKNOWN; + }; + return 0; +} + +static const struct argp argp = { + .options = options, + .parser = parse_opt, + .doc = doc, +}; + +int main(int argc, char *argv[]) +{ + DBusMessage *msg; + DBusMessageIter args, entry, dict, val; + DBusConnection *conn; + DBusError err; + char *str, *property; + int count = 0, length = 0; + + if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, 0, 0)) { + argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME); + return -1; + } + + if (!log) + log = fdopen(dup(fileno(stderr)), "w+"); + + if (!bin_log) + bin_log = fdopen(dup(fileno(stderr)), "w+"); + + // initialise the error value + dbus_error_init(&err); + + // connect to the DBUS system bus, and check for errors + conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "Connection Error (%s)\n", err.message); + dbus_error_free(&err); + } + if (!conn) { + fprintf(stderr, "Connection Null\n"); + return -1; + } + + dbus_bus_add_match(conn, "type='signal',interface='" ZBAR_INTERFACE "'", + &err); + dbus_connection_flush(conn); + if (dbus_error_is_set(&err)) { + fprintf(stderr, "Match Error (%s)\n", err.message); + exit(1); + } + + if (timeout) + alarm(timeout); + + /* loop listening for signals being emitted */ + fprintf(stderr, "Waiting for Zbar events\n"); + while (true) { + // non blocking read of the next available message + dbus_connection_read_write(conn, 0); + msg = dbus_connection_pop_message(conn); + + // loop again if we haven't read a message + if (NULL == msg) { + sleep(1); + continue; + } + + // check if the message is a signal from the correct interface and with the + // correct name + if (dbus_message_is_signal(msg, ZBAR_INTERFACE, ZBAR_SIGNAL_CODE)) { + // read the parameters + if (!dbus_message_iter_init(msg, &args)) + fprintf(stderr, "Message has no arguments!\n"); + else if (DBUS_TYPE_ARRAY != dbus_message_iter_get_arg_type(&args)) + fprintf(stderr, "Argument is not array!\n"); + else { + while (dbus_message_iter_get_arg_type(&args) != + DBUS_TYPE_INVALID) { + dbus_message_iter_recurse(&args, &entry); + if (DBUS_TYPE_DICT_ENTRY != + dbus_message_iter_get_arg_type(&entry)) { + fprintf(stderr, "Element is not dict entry!\n"); + } else { + while (dbus_message_iter_get_arg_type(&entry) != + DBUS_TYPE_INVALID) { + dbus_message_iter_recurse(&entry, &dict); + if (DBUS_TYPE_STRING != + dbus_message_iter_get_arg_type(&dict)) { + fprintf(stderr, + "Dict Entry key is not string!\n"); + } else { + dbus_message_iter_get_basic(&dict, &property); + dbus_message_iter_next(&dict); + if (DBUS_TYPE_VARIANT != + dbus_message_iter_get_arg_type(&dict)) { + fprintf( + stderr, + "Dict Entry value is not variant!\n"); + } else { + dbus_message_iter_recurse(&dict, &val); + if (strcmp(property, ZBAR_SIGNAL_TYPE) == + 0) { + if (DBUS_TYPE_STRING != + dbus_message_iter_get_arg_type( + &val)) { + fprintf( + stderr, + "Dict Entry value for barcode type is not string!\n"); + } else { + dbus_message_iter_get_basic(&val, + &str); + fprintf(stderr, "Type = %s\n", str); + } + } else if (strcmp(property, + ZBAR_SIGNAL_DATA) == 0) { + if (DBUS_TYPE_STRING != + dbus_message_iter_get_arg_type( + &val)) { + fprintf( + stderr, + "Dict Entry value for barcode text data is not string!\n"); + } else { + dbus_message_iter_get_basic(&val, + &str); + fprintf(stderr, "Value = %s\n", + str); + fprintf(log, "%s\n", str); + } + } else if (strcmp(property, + ZBAR_SIGNAL_BINARY_DATA) == + 0) { + if (DBUS_TYPE_ARRAY != + dbus_message_iter_get_arg_type( + &val)) { + fprintf( + stderr, + "Dict Entry value for barcode binary data is not array!\n"); + } else { + dbus_message_iter_recurse(&val, + &val); + if (DBUS_TYPE_BYTE != + dbus_message_iter_get_arg_type( + &val)) { + fprintf( + stderr, + "Dict Entry value for barcode binary data is not array of bytes!\n"); + } else { + dbus_message_iter_get_fixed_array( + &val, &str, &length); + fprintf(stderr, + "BinaryData[%d]\n", + length); + fwrite(str, sizeof(*str), + length, bin_log); + } + } + } + } + } + dbus_message_iter_next(&entry); + } + /* If max_msg > 0, stops after receiving 'count' messages */ + if (++count == max_msg) { + dbus_message_unref(msg); + return 0; + } + } + dbus_message_iter_next(&args); + } + } + } + // free the message + dbus_message_unref(msg); + } + + fclose(log); + fclose(bin_log); + + return 0; +} diff --git a/test/test_decode.c b/test/test_decode.c new file mode 100644 index 0000000..aa526f6 --- /dev/null +++ b/test/test_decode.c @@ -0,0 +1,1356 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include <argp.h> +#include <assert.h> +#include <ctype.h> +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <zbar.h> + +zbar_decoder_t *decoder; + +zbar_symbol_type_t expect_sym; +char *expect_data = NULL; + +int rnd_size = 9; /* NB should be odd */ +int wrong = 0, spurious = 0, missing = 0; + +#define zprintf(level, format, ...) \ + do { \ + if (verbosity >= (level)) { \ + fprintf(stderr, format, ##__VA_ARGS__); \ + } \ + } while (0) + +#define PROGRAM_NAME "test_video" + +static const char doc[] = + "\nGenerate barcodes and decode them with ZBar decoding logic\n"; + +static const struct argp_option options[] = { + { "quiet", 'q', 0, 0, "Don't be verbose", 0 }, + { "verbose", 'v', 0, 0, "Increases verbosity level", 0 }, + { "random", 'r', 0, 0, "use a random seed", 0 }, + { "seed", 's', "seed", 0, "sets the random seed", 0 }, + { "number", 'n', "count", 0, "sets the number of interactions", 0 }, + { "help", '?', 0, 0, "Give this help list", -1 }, + { "usage", -3, 0, 0, "Give a short usage message", 0 }, + { 0 } +}; + +unsigned seed = 0, rand_seed = 0; +int verbosity = 1; +int iter = 0, num_iter = 0; /* test iteration */ + +static error_t parse_opt(int k, char *optarg, struct argp_state *state) +{ + switch (k) { + case 'q': + verbosity = 0; + break; + case 'v': + verbosity++; + break; + case 'r': + rand_seed = 1; + break; + case 's': + seed = strtol(optarg, NULL, 0); + break; + case 'n': + num_iter = strtol(optarg, NULL, 0); + break; + case '?': + argp_state_help(state, state->out_stream, + ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_DOC); + exit(0); + case -3: + argp_state_help(state, state->out_stream, ARGP_HELP_USAGE); + exit(0); + default: + return ARGP_ERR_UNKNOWN; + }; + return 0; +} + +static const struct argp argp = { + .options = options, + .parser = parse_opt, + .doc = doc, +}; + +static inline void print_sep(int level) +{ + zprintf(level, + "----------------------------------------------------------\n"); +} + +static void symbol_handler(zbar_decoder_t *decoder) +{ + zbar_symbol_type_t sym = zbar_decoder_get_type(decoder); + if (sym <= ZBAR_PARTIAL || sym == ZBAR_QRCODE) + return; + const char *data = zbar_decoder_get_data(decoder); + + if (sym != expect_sym) { + zprintf(0, "[%d] SEED=%d: warning: expecting %s, got spurious %s\n", + iter, seed, zbar_get_symbol_name(expect_sym), + zbar_get_symbol_name(sym)); + spurious++; + return; + } + + int pass = (sym == expect_sym) && !strcmp(data, expect_data) && + zbar_decoder_get_data_length(decoder) == strlen(data); + pass *= 3; + + zprintf(pass, "decode %s:%s\n", zbar_get_symbol_name(sym), data); + + if (!expect_sym) + zprintf(0, "UNEXPECTED!\n"); + else + zprintf(pass, "expect %s:%s\n", zbar_get_symbol_name(expect_sym), + expect_data); + if (!pass) { + zprintf(0, "[%d] SEED=%d: ERROR: expecting %s (%s), got %s (%s)\n", + iter, seed, expect_data, zbar_get_symbol_name(expect_sym), data, + zbar_get_symbol_name(sym)); + wrong++; + } + + expect_sym = ZBAR_NONE; + free(expect_data); + expect_data = NULL; +} + +static void expect(zbar_symbol_type_t sym, const char *data) +{ + if (expect_sym) { + zprintf(0, "[%d] SEED=%d: missing decode: %s (%s)\n", iter, seed, + zbar_get_symbol_name(expect_sym), expect_data); + missing++; + } + expect_sym = sym; + expect_data = (data) ? strdup(data) : NULL; +} + +static void encode_junk(int n) +{ + if (n > 1) + zprintf(3, "encode random junk...\n"); + int i; + for (i = 0; i < n; i++) + zbar_decode_width(decoder, 20. * (rand() / (RAND_MAX + 1.)) + 1); +} + +#define FWD 1 +#define REV 0 + +static void encode(uint64_t units, int fwd) +{ + zprintf(3, " raw=%x%x%c\n", (unsigned)(units >> 32), + (unsigned)(units & 0xffffffff), (fwd) ? '<' : '>'); + if (!fwd) + while (units && !(units >> 0x3c)) + units <<= 4; + + while (units) { + unsigned char w = (fwd) ? units & 0xf : units >> 0x3c; + zbar_decode_width(decoder, w); + if (fwd) + units >>= 4; + else + units <<= 4; + } +} + +/*------------------------------------------------------------*/ +/* Code 128 encoding */ + +typedef enum code128_char_e +{ + FNC3 = 0x60, + FNC2 = 0x61, + SHIFT = 0x62, + CODE_C = 0x63, + CODE_B = 0x64, + CODE_A = 0x65, + FNC1 = 0x66, + START_A = 0x67, + START_B = 0x68, + START_C = 0x69, + STOP = 0x6a, +} code128_char_t; + +static const unsigned int + code128[107] = { + 0x212222, 0x222122, 0x222221, 0x121223, /* 00 */ + 0x121322, 0x131222, 0x122213, 0x122312, + 0x132212, 0x221213, 0x221312, 0x231212, /* 08 */ + 0x112232, 0x122132, 0x122231, 0x113222, + 0x123122, 0x123221, 0x223211, 0x221132, /* 10 */ + 0x221231, 0x213212, 0x223112, 0x312131, + 0x311222, 0x321122, 0x321221, 0x312212, /* 18 */ + 0x322112, 0x322211, 0x212123, 0x212321, + 0x232121, 0x111323, 0x131123, 0x131321, /* 20 */ + 0x112313, 0x132113, 0x132311, 0x211313, + 0x231113, 0x231311, 0x112133, 0x112331, /* 28 */ + 0x132131, 0x113123, 0x113321, 0x133121, + 0x313121, 0x211331, 0x231131, 0x213113, /* 30 */ + 0x213311, 0x213131, 0x311123, 0x311321, + 0x331121, 0x312113, 0x312311, 0x332111, /* 38 */ + 0x314111, 0x221411, 0x431111, 0x111224, + 0x111422, 0x121124, 0x121421, 0x141122, /* 40 */ + 0x141221, 0x112214, 0x112412, 0x122114, + 0x122411, 0x142112, 0x142211, 0x241211, /* 48 */ + 0x221114, 0x413111, 0x241112, 0x134111, + 0x111242, 0x121142, 0x121241, 0x114212, /* 50 */ + 0x124112, 0x124211, 0x411212, 0x421112, + 0x421211, 0x212141, 0x214121, 0x412121, /* 58 */ + 0x111143, 0x111341, 0x131141, 0x114113, + 0x114311, 0x411113, 0x411311, 0x113141, /* 60 */ + 0x114131, 0x311141, 0x411131, 0xa211412, + 0xa211214, 0xa211232, /* START_A-START_C (67-69) */ + 0x2331112a, /* STOP (6a) */ + }; + +static void encode_code128b(char *data) +{ + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + print_sep(3); + zprintf(2, "CODE-128(B): %s\n", data); + zprintf(3, " encode START_B: %02x", START_B); + encode(code128[START_B], 0); + int i, chk = START_B; + for (i = 0; data[i]; i++) { + zprintf(3, " encode '%c': %02x", data[i], data[i] - 0x20); + encode(code128[data[i] - 0x20], 0); + chk += (i + 1) * (data[i] - 0x20); + } + chk %= 103; + zprintf(3, " encode checksum: %02x", chk); + encode(code128[chk], 0); + zprintf(3, " encode STOP: %02x", STOP); + encode(code128[STOP], 0); + print_sep(3); +} + +static void encode_code128c(char *data) +{ + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + print_sep(3); + zprintf(2, "CODE-128(C): %s\n", data); + zprintf(3, " encode START_C: %02x", START_C); + encode(code128[START_C], 0); + int i, chk = START_C; + for (i = 0; data[i]; i += 2) { + assert(data[i] >= '0'); + assert(data[i + 1] >= '0'); + unsigned char c = (data[i] - '0') * 10 + (data[i + 1] - '0'); + zprintf(3, " encode '%c%c': %02d", data[i], data[i + 1], c); + encode(code128[c], 0); + chk += (i / 2 + 1) * c; + } + chk %= 103; + zprintf(3, " encode checksum: %02x", chk); + encode(code128[chk], 0); + zprintf(3, " encode STOP: %02x", STOP); + encode(code128[STOP], 0); + print_sep(3); +} + +/*------------------------------------------------------------*/ +/* Code 93 encoding */ + +#define CODE93_START_STOP 0x2f + +static const unsigned int code93[47 + 1] = { + 0x131112, 0x111213, 0x111312, 0x111411, /* 00 */ + 0x121113, 0x121212, 0x121311, 0x111114, + 0x131211, 0x141111, 0x211113, 0x211212, /* 08 */ + 0x211311, 0x221112, 0x221211, 0x231111, + 0x112113, 0x112212, 0x112311, 0x122112, /* 10 */ + 0x132111, 0x111123, 0x111222, 0x111321, + 0x121122, 0x131121, 0x212112, 0x212211, /* 18 */ + 0x211122, 0x211221, 0x221121, 0x222111, + 0x112122, 0x112221, 0x122121, 0x123111, /* 20 */ + 0x121131, 0x311112, 0x311211, 0x321111, + 0x112131, 0x113121, 0x211131, 0x121221, /* 28 */ + 0x312111, 0x311121, 0x122211, 0x111141, /* START/STOP (2f) */ +}; + +#define S1 0x2b00 | +#define S2 0x2c00 | +#define S3 0x2d00 | +#define S4 0x2e00 | + +static const unsigned short code93_ext[0x80] = { + S2 'U', S1 'A', S1 'B', S1 'C', S1 'D', S1 'E', S1 'F', S1 'G', S1 'H', + S1 'I', S1 'J', S1 'K', S1 'L', S1 'M', S1 'N', S1 'O', S1 'P', S1 'Q', + S1 'R', S1 'S', S1 'T', S1 'U', S1 'V', S1 'W', S1 'X', S1 'Y', S1 'Z', + S2 'A', S2 'B', S2 'C', S2 'D', S2 'E', 0x26, S3 'A', S3 'B', S3 'C', + 0x27, 0x2a, S3 'F', S3 'G', S3 'H', S3 'I', S3 'J', 0x29, S3 'L', + 0x24, 0x25, 0x28, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, S3 'Z', S2 'F', S2 'G', S2 'H', S2 'I', + S2 'J', S2 'V', 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, + 0x23, S2 'K', S2 'L', S2 'M', S2 'N', S2 'O', S2 'W', S4 'A', S4 'B', + S4 'C', S4 'D', S4 'E', S4 'F', S4 'G', S4 'H', S4 'I', S4 'J', S4 'K', + S4 'L', S4 'M', S4 'N', S4 'O', S4 'P', S4 'Q', S4 'R', S4 'S', S4 'T', + S4 'U', S4 'V', S4 'W', S4 'X', S4 'Y', S4 'Z', S2 'P', S2 'Q', S2 'R', + S2 'S', S2 'T', +}; + +#undef S1 +#undef S2 +#undef S3 +#undef S4 + +static void encode_char93(unsigned char c, int dir) +{ + unsigned ext = code93_ext[c]; + unsigned shift = ext >> 8; + assert(shift < 0x30); + c = ext & 0xff; + if (shift) { + assert(c < 0x80); + c = code93_ext[c]; + } + assert(c < 0x30); + + if (shift) { + encode(code93[(dir) ? shift : c], dir ^ 1); + encode(code93[(dir) ? c : shift], dir ^ 1); + } else + encode(code93[c], dir ^ 1); +} + +static void encode_code93(char *data, int dir) +{ + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + print_sep(3); + + /* calculate checksums */ + int i, j, chk_c = 0, chk_k = 0, n = 0; + for (i = 0; data[i]; i++, n++) { + unsigned c = data[i], ext; + assert(c < 0x80); + ext = code93_ext[c]; + n += ext >> 13; + } + + for (i = 0, j = 0; data[i]; i++, j++) { + unsigned ext = code93_ext[(unsigned)data[i]]; + unsigned shift = ext >> 8; + unsigned c = ext & 0xff; + if (shift) { + chk_c += shift * (((n - 1 - j) % 20) + 1); + chk_k += shift * (((n - j) % 15) + 1); + j++; + c = code93_ext[c]; + } + chk_c += c * (((n - 1 - j) % 20) + 1); + chk_k += c * (((n - j) % 15) + 1); + } + chk_c %= 47; + chk_k += chk_c; + chk_k %= 47; + + zprintf(2, "CODE-93: %s (n=%x C=%02x K=%02x)\n", data, n, chk_c, chk_k); + encode(0xa, 0); /* leading quiet */ + + zprintf(3, " encode %s:", (dir) ? "START" : "STOP"); + if (!dir) + encode(0x1, REV); + encode(code93[CODE93_START_STOP], dir ^ 1); + if (!dir) { + zprintf(3, " encode checksum (K): %02x", chk_k); + encode(code93[chk_k], REV ^ 1); + zprintf(3, " encode checksum (C): %02x", chk_c); + encode(code93[chk_c], REV ^ 1); + } + + n = strlen(data); + for (i = 0; i < n; i++) { + unsigned char c = data[(dir) ? i : (n - i - 1)]; + zprintf(3, " encode '%c':", c); + encode_char93(c, dir); + } + + if (dir) { + zprintf(3, " encode checksum (C): %02x", chk_c); + encode(code93[chk_c], FWD ^ 1); + zprintf(3, " encode checksum (K): %02x", chk_k); + encode(code93[chk_k], FWD ^ 1); + } + zprintf(3, " encode %s:", (dir) ? "STOP" : "START"); + encode(code93[CODE93_START_STOP], dir ^ 1); + if (dir) + encode(0x1, FWD); + + encode(0xa, 0); /* trailing quiet */ + print_sep(3); +} + +/*------------------------------------------------------------*/ +/* Code 39 encoding */ + +static const unsigned int code39[91 - 32] = { + 0x0c4, 0x000, 0x000, 0x000, 0x0a8, 0x02a, 0x000, 0x000, /* 20 */ + 0x000, 0x000, 0x094, 0x08a, 0x000, 0x085, 0x184, 0x0a2, /* 28 */ + 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, /* 30 */ + 0x124, 0x064, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, /* 38 */ + 0x000, 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00d, /* 40 */ + 0x10c, 0x04c, 0x01c, 0x103, 0x043, 0x142, 0x013, 0x112, /* 48 */ + 0x052, 0x007, 0x106, 0x046, 0x016, 0x181, 0x0c1, 0x1c0, /* 50 */ + 0x091, 0x190, 0x0d0, /* 58 */ +}; + +/* FIXME configurable/randomized ratio, ics */ +/* FIXME check digit option, ASCII escapes */ + +static void convert_code39(char *data) +{ + char *src, *dst; + for (src = data, dst = data; *src; src++) { + char c = *src; + if (c >= 'a' && c <= 'z') + *(dst++) = c - ('a' - 'A'); + else if (c == ' ' || c == '$' || c == '%' || c == '+' || c == '-' || + (c >= '.' && c <= '9') || (c >= 'A' && c <= 'Z')) + *(dst++) = c; + else + /* skip (FIXME) */; + } + *dst = 0; +} + +static void encode_char39(unsigned char c, unsigned ics) +{ + assert(0x20 <= c && c <= 0x5a); + unsigned int raw = code39[c - 0x20]; + if (!raw) + return; /* skip (FIXME) */ + + uint64_t enc = 0; + int j; + for (j = 0; j < 9; j++) { + enc = (enc << 4) | ((raw & 0x100) ? 2 : 1); + raw <<= 1; + } + enc = (enc << 4) | ics; + zprintf(3, " encode '%c': %02x%08x: ", c, (unsigned)(enc >> 32), + (unsigned)(enc & 0xffffffff)); + encode(enc, REV); +} + +static void encode_code39(char *data) +{ + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + print_sep(3); + zprintf(2, "CODE-39: %s\n", data); + encode(0xa, 0); /* leading quiet */ + encode_char39('*', 1); + int i; + for (i = 0; data[i]; i++) + if (data[i] != '*') /* skip (FIXME) */ + encode_char39(data[i], 1); + encode_char39('*', 0xa); /* w/trailing quiet */ + print_sep(3); +} + +#if 0 +/*------------------------------------------------------------*/ +/* PDF417 encoding */ + +/* hardcoded test message: "hello world" */ +#define PDF417_ROWS 3 +#define PDF417_COLS 3 +static const unsigned pdf417_msg[PDF417_ROWS][PDF417_COLS] = { + { 007, 817, 131 }, + { 344, 802, 437 }, + { 333, 739, 194 }, +}; + +#define PDF417_START UINT64_C(0x81111113) +#define PDF417_STOP UINT64_C(0x711311121) +#include "pdf417_encode.h" + +static int calc_ind417 (int mod, + int r, + int cols) +{ + mod = (mod + 3) % 3; + int cw = 30 * (r / 3); + if(!mod) + return(cw + cols - 1); + else if(mod == 1) + return(cw + (PDF417_ROWS - 1) % 3); + assert(mod == 2); + return(cw + (PDF417_ROWS - 1) / 3); +} + +static void encode_row417 (int r, + const unsigned *cws, + int cols, + int dir) +{ + int k = r % 3; + + zprintf(3, " [%d] encode %s:", r, (dir) ? "stop" : "start"); + encode((dir) ? PDF417_STOP : PDF417_START, dir); + + int cw = calc_ind417(k + !dir, r, cols); + zprintf(3, " [%d,%c] encode %03d(%d): ", r, (dir) ? 'R' : 'L', cw, k); + encode(pdf417_encode[cw][k], dir); + + int c; + for(c = 0; c < cols; c++) { + cw = cws[c]; + zprintf(3, " [%d,%d] encode %03d(%d): ", r, c, cw, k); + encode(pdf417_encode[cw][k], dir); + } + + cw = calc_ind417(k + dir, r, cols); + zprintf(3, " [%d,%c] encode %03d(%d): ", r, (dir) ? 'L' : 'R', cw, k); + encode(pdf417_encode[cw][k], dir); + + zprintf(3, " [%d] encode %s:", r, (dir) ? "start" : "stop"); + encode((dir) ? PDF417_START : PDF417_STOP, dir); +} + +static void encode_pdf417 (char *data) +{ + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + print_sep(3); + zprintf(2, "PDF417: hello world\n"); + encode(0xa, 0); + + int r; + for(r = 0; r < PDF417_ROWS; r++) { + encode_row417(r, pdf417_msg[r], PDF417_COLS, r & 1); + encode(0xa, 0); + } + + print_sep(3); +} +#endif + +/*------------------------------------------------------------*/ +/* Codabar encoding */ + +static const unsigned int codabar[20] = { + 0x03, 0x06, 0x09, 0x60, 0x12, 0x42, 0x21, 0x24, 0x30, 0x48, + 0x0c, 0x18, 0x45, 0x51, 0x54, 0x15, 0x1a, 0x29, 0x0b, 0x0e, +}; + +static const char codabar_char[0x14] = "0123456789-$:/.+ABCD"; + +/* FIXME configurable/randomized ratio, ics */ +/* FIXME check digit option */ + +static char *convert_codabar(char *src) +{ + unsigned len = strlen(src); + char tmp[4] = { + 0, + }; + if (len < 2) { + unsigned delim = rand() >> 8; + tmp[0] = delim & 3; + if (len) + tmp[1] = src[0]; + tmp[len + 1] = (delim >> 2) & 3; + len += 2; + src = tmp; + } + + char *result = malloc(len + 1); + char *dst = result; + *(dst++) = ((*(src++) - 1) & 0x3) + 'A'; + for (len--; len > 1; len--) { + char c = *(src++); + if (c >= '0' && c <= '9') + *(dst++) = c; + else if (c == '-' || c == '$' || c == ':' || c == '/' || c == '.' || + c == '+') + *(dst++) = c; + else + *(dst++) = codabar_char[c % 0x10]; + } + *(dst++) = ((*(src++) - 1) & 0x3) + 'A'; + *dst = 0; + return (result); +} + +static void encode_codachar(unsigned char c, unsigned ics, int dir) +{ + unsigned int idx; + if (c >= '0' && c <= '9') + idx = c - '0'; + else if (c >= 'A' && c <= 'D') + idx = c - 'A' + 0x10; + else + switch (c) { + case '-': + idx = 0xa; + break; + case '$': + idx = 0xb; + break; + case ':': + idx = 0xc; + break; + case '/': + idx = 0xd; + break; + case '.': + idx = 0xe; + break; + case '+': + idx = 0xf; + break; + default: + assert(0); + } + + assert(idx < 0x14); + unsigned int raw = codabar[idx]; + + uint32_t enc = 0; + int j; + for (j = 0; j < 7; j++, raw <<= 1) + enc = (enc << 4) | ((raw & 0x40) ? 3 : 1); + zprintf(3, " encode '%c': %07x: ", c, enc); + if (dir) + enc = (enc << 4) | ics; + else + enc |= ics << 28; + encode(enc, 1 - dir); +} + +static void encode_codabar(char *data, int dir) +{ + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + print_sep(3); + zprintf(2, "CODABAR: %s\n", data); + encode(0xa, 0); /* leading quiet */ + int i, n = strlen(data); + for (i = 0; i < n; i++) { + int j = (dir) ? i : n - i - 1; + encode_codachar(data[j], (i < n - 1) ? 1 : 0xa, dir); + } + print_sep(3); +} + +/*------------------------------------------------------------*/ +/* Interleaved 2 of 5 encoding */ + +static const unsigned char i25[10] = { + 0x06, 0x11, 0x09, 0x18, 0x05, 0x14, 0x0c, 0x03, 0x12, 0x0a, +}; + +static void encode_i25(char *data, int dir) +{ + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + print_sep(3); + zprintf(2, "Interleaved 2 of 5: %s\n", data); + zprintf(3, " encode start:"); + encode((dir) ? 0xa1111 : 0xa112, 0); + + /* FIXME rev case data reversal */ + int i; + for (i = (strlen(data) & 1) ? -1 : 0; i < 0 || data[i]; i += 2) { + /* encode 2 digits */ + unsigned char c0 = (i < 0) ? 0 : data[i] - '0'; + unsigned char c1 = data[i + 1] - '0'; + zprintf(3, " encode '%d%d':", c0, c1); + assert(c0 < 10); + assert(c1 < 10); + + c0 = i25[c0]; + c1 = i25[c1]; + + /* interleave */ + uint64_t enc = 0; + int j; + for (j = 0; j < 5; j++) { + enc <<= 8; + enc |= (c0 & 1) ? 0x02 : 0x01; + enc |= (c1 & 1) ? 0x20 : 0x10; + c0 >>= 1; + c1 >>= 1; + } + encode(enc, dir); + } + + zprintf(3, " encode end:"); + encode((dir) ? 0x211a : 0x1111a, 0); + print_sep(3); +} + +/*------------------------------------------------------------*/ +/* DataBar encoding */ + +/* character encoder reference algorithm from ISO/IEC 24724:2009 */ + +struct rss_group { + int T_odd, T_even, n_odd, w_max; +}; + +static const struct rss_group databar_groups_outside[] = { { 161, 1, 12, 8 }, + { 80, 10, 10, 6 }, + { 31, 34, 8, 4 }, + { 10, 70, 6, 3 }, + { 1, 126, 4, 1 }, + { + 0, + } }; + +static const struct rss_group databar_groups_inside[] = { { 4, 84, 5, 2 }, + { 20, 35, 7, 4 }, + { 48, 10, 9, 6 }, + { 81, 1, 11, 8 }, + { + 0, + } }; + +static const uint32_t databar_finders[9] = { + 0x38211, 0x35511, 0x33711, 0x31911, 0x27411, + 0x25611, 0x23811, 0x15711, 0x13911, +}; + +int combins(int n, int r) +{ + int i, j; + int maxDenom, minDenom; + int val; + if (n - r > r) { + minDenom = r; + maxDenom = n - r; + } else { + minDenom = n - r; + maxDenom = r; + } + val = 1; + j = 1; + for (i = n; i > maxDenom; i--) { + val *= i; + if (j <= minDenom) { + val /= j; + j++; + } + } + for (; j <= minDenom; j++) + val /= j; + return (val); +} + +void getRSSWidths(int val, int n, int elements, int maxWidth, int noNarrow, + int *widths) +{ + int narrowMask = 0; + int bar; + for (bar = 0; bar < elements - 1; bar++) { + int elmWidth, subVal; + for (elmWidth = 1, narrowMask |= (1 << bar);; + elmWidth++, narrowMask &= ~(1 << bar)) { + subVal = combins(n - elmWidth - 1, elements - bar - 2); + if ((!noNarrow) && !narrowMask && + (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) + subVal -= combins(n - elmWidth - (elements - bar), + elements - bar - 2); + if (elements - bar - 1 > 1) { + int mxwElement, lessVal = 0; + for (mxwElement = n - elmWidth - (elements - bar - 2); + mxwElement > maxWidth; mxwElement--) + lessVal += combins(n - elmWidth - mxwElement - 1, + elements - bar - 3); + subVal -= lessVal * (elements - 1 - bar); + } else if (n - elmWidth > maxWidth) + subVal--; + val -= subVal; + if (val < 0) + break; + } + val += subVal; + n -= elmWidth; + widths[bar] = elmWidth; + } + widths[bar] = n; +} + +static uint64_t encode_databar_char(unsigned val, const struct rss_group *grp, + int nmodules, int nelems, int dir) +{ + int G_sum = 0; + while (1) { + assert(grp->T_odd); + int sum = G_sum + grp->T_odd * grp->T_even; + if (val >= sum) + G_sum = sum; + else + break; + grp++; + } + + zprintf(3, "char=%d", val); + + int V_grp = val - G_sum; + int V_odd, V_even; + if (!dir) { + V_odd = V_grp / grp->T_even; + V_even = V_grp % grp->T_even; + } else { + V_even = V_grp / grp->T_odd; + V_odd = V_grp % grp->T_odd; + } + + zprintf(3, " G_sum=%d T_odd=%d T_even=%d n_odd=%d w_max=%d V_grp=%d\n", + G_sum, grp->T_odd, grp->T_even, grp->n_odd, grp->w_max, V_grp); + + int odd[16]; + getRSSWidths(V_odd, grp->n_odd, nelems, grp->w_max, !dir, odd); + zprintf(3, " V_odd=%d odd=%d%d%d%d", V_odd, odd[0], odd[1], odd[2], + odd[3]); + + int even[16]; + getRSSWidths(V_even, nmodules - grp->n_odd, nelems, 9 - grp->w_max, dir, + even); + zprintf(3, " V_even=%d even=%d%d%d%d", V_even, even[0], even[1], even[2], + even[3]); + + uint64_t units = 0; + int i; + for (i = 0; i < nelems; i++) + units = (units << 8) | (odd[i] << 4) | even[i]; + + zprintf(3, " raw=%" PRIx64 "\n", units); + return (units); +} + +#define SWAP(a, b) \ + do { \ + uint32_t tmp = (a); \ + (a) = (b); \ + (b) = tmp; \ + } while (0); + +static void encode_databar(char *data, int dir) +{ + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + + print_sep(3); + zprintf(2, "DataBar: %s\n", data); + + uint32_t v[4] = { + 0, + }; + int i, j; + for (i = 0; i < 14; i++) { + for (j = 0; j < 4; j++) + v[j] *= 10; + assert(data[i]); + v[0] += data[i] - '0'; + v[1] += v[0] / 1597; + v[0] %= 1597; + v[2] += v[1] / 2841; + v[1] %= 2841; + v[3] += v[2] / 1597; + v[2] %= 1597; + /*printf(" [%d] %c (%d,%d,%d,%d)\n", + i, data[i], v[0], v[1], v[2], v[3]);*/ + } + zprintf(3, "chars=(%d,%d,%d,%d)\n", v[3], v[2], v[1], v[0]); + + uint32_t c[4] = { + encode_databar_char(v[3], databar_groups_outside, 16, 4, 0), + encode_databar_char(v[2], databar_groups_inside, 15, 4, 1), + encode_databar_char(v[1], databar_groups_outside, 16, 4, 0), + encode_databar_char(v[0], databar_groups_inside, 15, 4, 1), + }; + + int chk = 0, w = 1; + for (i = 0; i < 4; i++, chk %= 79, w %= 79) + for (j = 0; j < 8; j++, w *= 3) + chk += ((c[i] >> (28 - j * 4)) & 0xf) * w; + zprintf(3, "chk=%d\n", chk); + + if (chk >= 8) + chk++; + if (chk >= 72) + chk++; + int C_left = chk / 9; + int C_right = chk % 9; + + if (dir == REV) { + SWAP(C_left, C_right); + SWAP(c[0], c[2]); + SWAP(c[1], c[3]); + SWAP(v[0], v[2]); + SWAP(v[1], v[3]); + } + + zprintf(3, " encode start guard:"); + encode_junk(dir); + encode(0x1, FWD); + + zprintf(3, "encode char[0]=%d", v[3]); + encode(c[0], REV); + + zprintf(3, "encode left finder=%d", C_left); + encode(databar_finders[C_left], REV); + + zprintf(3, "encode char[1]=%d", v[2]); + encode(c[1], FWD); + + zprintf(3, "encode char[3]=%d", v[0]); + encode(c[3], REV); + + zprintf(3, "encode right finder=%d", C_right); + encode(databar_finders[C_right], FWD); + + zprintf(3, "encode char[2]=%d", v[1]); + encode(c[2], FWD); + + zprintf(3, " encode end guard:"); + encode(0x1, FWD); + encode_junk(!dir); + print_sep(3); +} + +/*------------------------------------------------------------*/ +/* EAN/UPC encoding */ + +static const unsigned int ean_digits[10] = { + 0x1123, 0x1222, 0x2212, 0x1141, 0x2311, + 0x1321, 0x4111, 0x2131, 0x3121, 0x2113, +}; + +static const unsigned int ean_guard[] = { + 0, 0, 0x11, /* [2] add-on delineator */ + 0x1117, /* [3] normal guard bars */ + 0x2117, /* [4] add-on guard bars */ + 0x11111, /* [5] center guard bars */ + 0x111111 /* [6] "special" guard bars */ +}; + +static const unsigned char ean_parity_encode[] = { + 0x3f, /* AAAAAA = 0 */ + 0x34, /* AABABB = 1 */ + 0x32, /* AABBAB = 2 */ + 0x31, /* AABBBA = 3 */ + 0x2c, /* ABAABB = 4 */ + 0x26, /* ABBAAB = 5 */ + 0x23, /* ABBBAA = 6 */ + 0x2a, /* ABABAB = 7 */ + 0x29, /* ABABBA = 8 */ + 0x25, /* ABBABA = 9 */ +}; + +static const unsigned char addon_parity_encode[] = { + 0x07, /* BBAAA = 0 */ + 0x0b, /* BABAA = 1 */ + 0x0d, /* BAABA = 2 */ + 0x0e, /* BAAAB = 3 */ + 0x13, /* ABBAA = 4 */ + 0x19, /* AABBA = 5 */ + 0x1c, /* AAABB = 6 */ + 0x15, /* ABABA = 7 */ + 0x16, /* ABAAB = 8 */ + 0x1a, /* AABAB = 9 */ +}; + +static void calc_ean_parity(char *data, int n) +{ + int i, chk = 0; + for (i = 0; i < n; i++) { + unsigned char c = data[i] - '0'; + chk += ((i ^ n) & 1) ? c * 3 : c; + } + chk %= 10; + if (chk) + chk = 10 - chk; + data[i++] = '0' + chk; + data[i] = 0; +} + +static void encode_ean13(char *data) +{ + int i; + unsigned char par = ean_parity_encode[data[0] - '0']; + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + + print_sep(3); + zprintf(2, "EAN-13: %s (%02x)\n", data, par); + zprintf(3, " encode start guard:"); + encode(ean_guard[3], FWD); + for (i = 1; i < 7; i++, par <<= 1) { + zprintf(3, " encode %x%c:", (par >> 5) & 1, data[i]); + encode(ean_digits[data[i] - '0'], (par >> 5) & 1); + } + zprintf(3, " encode center guard:"); + encode(ean_guard[5], FWD); + for (; i < 13; i++) { + zprintf(3, " encode %x%c:", 0, data[i]); + encode(ean_digits[data[i] - '0'], FWD); + } + zprintf(3, " encode end guard:"); + encode(ean_guard[3], REV); + print_sep(3); +} + +static void encode_ean8(char *data) +{ + int i; + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + print_sep(3); + zprintf(2, "EAN-8: %s\n", data); + zprintf(3, " encode start guard:"); + encode(ean_guard[3], FWD); + for (i = 0; i < 4; i++) { + zprintf(3, " encode %c:", data[i]); + encode(ean_digits[data[i] - '0'], FWD); + } + zprintf(3, " encode center guard:"); + encode(ean_guard[5], FWD); + for (; i < 8; i++) { + zprintf(3, " encode %c:", data[i]); + encode(ean_digits[data[i] - '0'], FWD); + } + zprintf(3, " encode end guard:"); + encode(ean_guard[3], REV); + print_sep(3); +} + +static void encode_addon(char *data, unsigned par, int n) +{ + int i; + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + + print_sep(3); + zprintf(2, "EAN-%d: %s (par=%02x)\n", n, data, par); + zprintf(3, " encode start guard:"); + encode(ean_guard[4], FWD); + for (i = 0; i < n; i++, par <<= 1) { + zprintf(3, " encode %x%c:", (par >> (n - 1)) & 1, data[i]); + encode(ean_digits[data[i] - '0'], (par >> (n - 1)) & 1); + if (i < n - 1) { + zprintf(3, " encode delineator:"); + encode(ean_guard[2], FWD); + } + } + zprintf(3, " encode trailing qz:"); + encode(0x7, FWD); + print_sep(3); +} + +static void encode_ean5(char *data) +{ + unsigned chk = ((data[0] - '0' + data[2] - '0' + data[4] - '0') * 3 + + (data[1] - '0' + data[3] - '0') * 9) % + 10; + encode_addon(data, addon_parity_encode[chk], 5); +} + +static void encode_ean2(char *data) +{ + unsigned par = (~(10 * (data[0] - '0') + data[1] - '0')) & 3; + encode_addon(data, par, 2); +} + +/*------------------------------------------------------------*/ +/* main test flow */ + +int test_databar_F_1() +{ + expect(ZBAR_DATABAR, "0124012345678905"); + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + encode(0x11, 0); + encode(0x31111333, 0); + encode(0x13911, 0); + encode(0x31131231, 0); + encode(0x11214222, 0); + encode(0x11553, 0); + encode(0x21231313, 0); + encode(0x1, 0); + encode_junk(rnd_size); + return (0); +} + +int test_databar_F_3() +{ + expect(ZBAR_DATABAR_EXP, "1012A"); + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + encode(0x11, 0); + encode(0x11521151, 0); + encode(0x18411, 0); + encode(0x13171121, 0); + encode(0x11521232, 0); + encode(0x11481, 0); + encode(0x23171111, 0); + encode(0x1, 0); + encode_junk(rnd_size); + return (0); +} + +int test_orange() +{ + char data[32] = "0100845963000052"; + expect(ZBAR_DATABAR, data); + assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE); + encode(0x1, 0); + encode(0x23212321, 0); // data[0] + encode(0x31911, 0); // finder[?] = 3 + encode(0x21121215, 1); // data[1] + encode(0x41111133, 0); // data[3] + encode(0x23811, 1); // finder[?] = 6 + encode(0x11215141, 1); // data[2] + encode(0x11, 0); + encode_junk(rnd_size); + + expect(ZBAR_DATABAR, data); + data[1] = '0'; + encode_databar(data + 1, FWD); + encode_junk(rnd_size); + return (0); +} + +int test_numeric(char *data) +{ + char tmp[32] = "01"; + strncpy(tmp + 2, data + 1, 13); + tmp[15] = '\0'; + calc_ean_parity(tmp + 2, 13); + expect(ZBAR_DATABAR, tmp); + + tmp[1] = data[0] & '1'; + encode_databar(tmp + 1, (rand() >> 8) & 1); + + encode_junk(rnd_size); + + data[strlen(data) & ~1] = 0; + expect(ZBAR_CODE128, data); + encode_code128c(data); + + encode_junk(rnd_size); + + expect(ZBAR_I25, data); + encode_i25(data, FWD); + + encode_junk(rnd_size); +#if 0 /* FIXME encoding broken */ + encode_i25(data, REV); + + encode_junk(rnd_size); +#endif + + char *cdb = convert_codabar(data); + expect(ZBAR_CODABAR, cdb); + encode_codabar(cdb, FWD); + encode_junk(rnd_size); + + expect(ZBAR_CODABAR, cdb); + encode_codabar(cdb, REV); + encode_junk(rnd_size); + free(cdb); + + calc_ean_parity(data + 2, 12); + expect(ZBAR_EAN13, data + 2); + encode_ean13(data + 2); + encode_junk(rnd_size); + + calc_ean_parity(data + 7, 7); + expect(ZBAR_EAN8, data + 7); + encode_ean8(data + 7); + + encode_junk(rnd_size); + + data[5] = 0; + expect(ZBAR_EAN5, data); + encode_ean5(data); + + encode_junk(rnd_size); + + data[2] = 0; + expect(ZBAR_EAN2, data); + encode_ean2(data); + encode_junk(rnd_size); + + expect(ZBAR_NONE, NULL); + return (0); +} + +int test_alpha(char *data) +{ + expect(ZBAR_CODE128, data); + encode_code128b(data); + + encode_junk(rnd_size); + + expect(ZBAR_CODE93, data); + encode_code93(data, FWD); + + encode_junk(rnd_size); + + expect(ZBAR_CODE93, data); + encode_code93(data, REV); + + encode_junk(rnd_size); + + char *cdb = convert_codabar(data); + expect(ZBAR_CODABAR, cdb); + encode_codabar(cdb, FWD); + encode_junk(rnd_size); + + expect(ZBAR_CODABAR, cdb); + encode_codabar(cdb, REV); + encode_junk(rnd_size); + free(cdb); + + convert_code39(data); + expect(ZBAR_CODE39, data); + encode_code39(data); + + encode_junk(rnd_size); + +#if 0 /* FIXME decoder unfinished */ + encode_pdf417(data); + + encode_junk(rnd_size); +#endif + + expect(ZBAR_NONE, NULL); + return (0); +} + +int test1() +{ + print_sep(2); + if (!seed) + seed = 0xbabeface; + zprintf(1, "[%d] SEED=%d\n", iter, seed); + srand(seed); + + int i; + char data[32]; + for (i = 0; i < 14; i++) { + data[i] = (rand() % 10) + '0'; + } + data[i] = 0; + + zprintf(1, "testing data: %s\n", data); + + test_numeric(data); + + for (i = 0; i < 10; i++) + data[i] = (rand() % 0x5f) + 0x20; + data[i] = 0; + + zprintf(1, "testing alpha: %s\n", data); + + test_alpha(data); + return (0); +} + +/* FIXME TBD: + * - random module width (!= 1.0) + * - simulate scan speed variance + * - simulate dark "swelling" and light "blooming" + * - inject parity errors + */ + +float percent(int count, int iter) +{ + if (iter <= 1) { + if (count) + return 100.0; + else + return 0.0; + } + return (count * 100.0) / iter; +} + +int main(int argc, char *argv[]) +{ + if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, 0, 0)) { + argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME); + return -1; + } + + if (rand_seed) { + seed = time(NULL); + srand(seed); + seed = (rand() << 8) ^ rand(); + zprintf(0, "Random SEED=%d\n", seed); + } + + decoder = zbar_decoder_create(); + /* allow empty CODE39 symbologies */ + zbar_decoder_set_config(decoder, ZBAR_CODE39, ZBAR_CFG_MIN_LEN, 0); + /* enable addons */ + zbar_decoder_set_config(decoder, ZBAR_EAN2, ZBAR_CFG_ENABLE, 1); + zbar_decoder_set_config(decoder, ZBAR_EAN5, ZBAR_CFG_ENABLE, 1); + zbar_decoder_set_handler(decoder, symbol_handler); + + encode_junk(rnd_size + 1); + + if (num_iter) { + for (iter = 0; iter < num_iter; iter++) { + test1(); + seed = (rand() << 8) ^ rand(); + } + } else { + test_databar_F_1(); + test_databar_F_3(); + test_orange(); + test1(); + } + + zbar_decoder_destroy(decoder); + + if (!wrong && percent(spurious, num_iter) <= 0.01 && + percent(missing, num_iter) <= 0.01) { + if (spurious || missing) + printf( + "decoder PASSED with %d spurious (%02.4f%%) and %d missing(%02.4f%%).\n", + spurious, percent(spurious, num_iter), missing, + percent(missing, num_iter)); + else + printf("decoder PASSED.\n"); + } else { + printf( + "decoder FAILED with %d wrong decoding(%02.4f%%), %d spurious (%02.4f%%) and %d missing(%02.4f%%).\n", + wrong, percent(wrong, num_iter), spurious, + percent(spurious, num_iter), missing, percent(missing, num_iter)); + return 1; + } + return (0); +} diff --git a/test/test_examples.sh.in b/test/test_examples.sh.in new file mode 100644 index 0000000..f4c18e8 --- /dev/null +++ b/test/test_examples.sh.in @@ -0,0 +1,91 @@ +#!/bin/bash + +unset ERR + +DIR="@abs_top_srcdir@" +ZBARIMG="@abs_top_builddir@/zbarimg/zbarimg --nodbus" + +test() +{ + if [ "$2" != "" ]; then + i="$DIR/examples/$2" + j="$1 $2" + else + i="$DIR/examples/$1" + j="$1" + fi; + if [ "$2" != "" ]; then + CMD="$ZBARIMG $1" + else + CMD="$ZBARIMG" + fi + CK=`$CMD "$i" 2>/dev/null|sha1sum|cut -d" " -f1` + ORG=`grep "zbarimg $j" "$DIR/examples/sha1sum"|cut -d " " -f1` + + if [ "$CK" != "$ORG" ]; then + echo "FAILED: $i ($CK instead of $ORG)" + echo -e "\tcmd: $CMD '$i'" + echo -en "\tresults: " + $CMD "$i" 2>/dev/null + ERR=1 + fi +} + +if [ "@ENABLE_CODE128@" == "1" ]; then + test code-128.png +fi + +if [ "@ENABLE_CODE93@" == "1" ]; then + test code-93.png +fi + +if [ "@ENABLE_CODE39@" == "1" ]; then + test code-39.png +fi + +if [ "@ENABLE_CODABAR@" == "1" ]; then + test codabar.png +fi + +if [ "@ENABLE_DATABAR@" == "1" ]; then + test databar.png + test databar-exp.png +fi + +if [ "@ENABLE_EAN@" == "1" ]; then + test -Sean2.enable ean-2.png + test -Sean5.enable ean-5.png + test ean-8.png + test ean-13.png + test -Sisbn10.enable ean-13.png + test -Sisbn13.enable ean-13.png + test -Supca.enable code-upc-a.png +fi + +if [ "@ENABLE_I25@" == "1" ]; then + test i2-5.png +fi + +if [ "@ENABLE_QRCODE@" == "1" ]; then + test qr-code.png + test -Stest-inverted qr-code-inverted.png + test '--raw --oneshot -Sbinary' qr-code-binary.png +fi + +if [ "@ENABLE_SQCODE@" == "1" ]; then + test sqcode1-generated.png + test sqcode1-scanned.png +fi + +# The pdf417 code is incomplete: it doesn't output any results +# +#if [ "@ENABLE_PDF417@" == "1" ]; then +# test code-pdf417.png +#fi + +if [ "$ERR" == "" ]; then + echo "zbarimg PASSED." +else + exit 1 +fi + diff --git a/test/test_gi.py b/test/test_gi.py new file mode 100755 index 0000000..c64f574 --- /dev/null +++ b/test/test_gi.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python3 +#------------------------------------------------------------------------ +# Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net> +# +# This file is part of the ZBar Bar Code Reader. +# +# The ZBar Bar Code Reader is free software; you can redistribute it +# and/or modify it under the terms of the GNU Lesser Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# The ZBar Bar Code Reader is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with the ZBar Bar Code Reader; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA +# +# http://sourceforge.net/projects/zbar +#------------------------------------------------------------------------ +import sys, os, stat + +import gi +gi.require_version('ZBar', '1.0') + +try: + from gi.repository import ZBar, Gtk, GdkPixbuf +except ImportError: + print("No ZBar integration") + sys.exit() + +# To debug vars on a interactive python3: +# >>> import gi +# >>> gi.require_version('ZBar', '1.0') +# >>> from gi.repository import ZBar +# >>> zbar = ZBar.Gtk.new() +# +# >>> zbar.<tab> + +def decoded(zbar, data): + """callback invoked when a barcode is decoded by the zbar widget. + displays the decoded data in the text box + """ + buf = results.props.buffer + end = buf.get_end_iter() + buf.insert(end, data + "\n") + results.scroll_to_iter(end, 0, 0, 0, 0) + +def video_enabled(zbar, param): + """callback invoked when the zbar widget enables or disables + video streaming. updates the status button state to reflect the + current video state + """ + enabled = zbar.get_video_enabled() + if status_button.get_active() != enabled: + status_button.set_active(enabled) + +def video_opened(zbar, param): + """callback invoked when the zbar widget opens or closes a video + device. also called when a device is closed due to error. + updates the status button state to reflect the current video state + """ + opened = zbar.get_video_opened() + status_button.set_sensitive(opened) + set_status_label(opened, zbar.get_video_enabled()) + +def video_changed(widget): + """callback invoked when a new video device is selected from the + drop-down list. sets the new device for the zbar widget, + which will eventually cause it to be opened and enabled + """ + dev = video_list.get_active_text() + if dev[0] == '<': + dev = '' + zbar.set_video_device(dev) + +def status_button_toggled(button): + """callback invoked when the status button changes state + (interactively or programmatically). ensures the zbar widget + video streaming state is consistent and updates the display of the + button to represent the current state + """ + opened = zbar.get_video_opened() + active = status_button.get_active() + if opened and (active != zbar.get_video_enabled()): + zbar.set_video_enabled(active) + set_status_label(opened, active) + if active: + status_image.set_from_icon_name("gtk-yes", Gtk.IconSize.BUTTON) + else: + status_image.set_from_icon_name("Gtk-no", Gtk.IconSize.BUTTON) + +def open_button_clicked(button): + """callback invoked when the 'Open' button is clicked. pops up an + 'Open File' dialog which the user may use to select an image file. + if the image is successfully opened, it is passed to the zbar + widget which displays it and scans it for barcodes. results are + returned using the same hook used to report video results + """ + dialog = Gtk.FileChooserDialog(title = "Open Image File", parent = window, + action = Gtk.FileChooserAction.OPEN) + + dialog.add_buttons("gtk-cancel", Gtk.ResponseType.CANCEL) + dialog.add_buttons("gtk-open", Gtk.ResponseType.ACCEPT) + + global open_file + if open_file: + dialog.set_filename(open_file) + try: + if dialog.run() == Gtk.ResponseType.ACCEPT: + open_file = dialog.get_filename() + pixbuf = GdkPixbuf.Pixbuf.new_from_file(open_file) + if pixbuf: + zbar.scan_image(pixbuf) + finally: + dialog.destroy() + +def set_status_label(opened, enabled): + """update status button label to reflect indicated state.""" + if not opened: + label = "closed" + elif enabled: + label = "enabled" + else: + label = "disabled" + status_button.set_label(label) + +open_file = None +video_device = None +if len(sys.argv) > 1: + video_device = sys.argv[1] + +window = Gtk.Window() +window.set_title("test_pygtk") +window.set_border_width(8) +window.connect("destroy", Gtk.main_quit) + +zbar = ZBar.Gtk.new() + +print(zbar.get_video_device()) + +try: + print(zbar.get_video_device()) +except: + print(ZBar.get_video_device(zbar)) + +zbar.connect("decoded-text", decoded) + +# video device list combo box +video_list = Gtk.ComboBoxText() +video_list.connect("changed", video_changed) + +# enable/disable status button +status_button = Gtk.ToggleButton(name="closed") +status_image = Gtk.Image.new_from_icon_name("gtk-no", Gtk.IconSize.BUTTON) +status_button.set_image(status_image) +status_button.set_sensitive(False) + +# bind status button state and video state +status_button.connect("toggled", status_button_toggled) +zbar.connect("notify::video-enabled", video_enabled) +zbar.connect("notify::video-opened", video_opened) + +# open image file button +open_button = Gtk.Button.new_with_mnemonic(label="Open") +open_button.connect("clicked", open_button_clicked) + +# populate video devices in combo box +video_list.append_text("<none>") +video_list.set_active(0) +for (root, dirs, files) in os.walk("/dev"): + for dev in files: + path = os.path.join(root, dev) + if not os.access(path, os.F_OK): + continue + info = os.stat(path) + if stat.S_ISCHR(info.st_mode) and os.major(info.st_rdev) == 81: + video_list.append_text(path) + if path == video_device: + video_list.set_active(len(video_list.get_model()) - 1) + video_device = None + +if video_device is not None: + video_list.append_text(video_device) + video_list.set_active(len(video_list.get_model()) - 1) + video_device = None + +# combine combo box and buttons horizontally +hbox = Gtk.HBox(spacing=8) +hbox.pack_start(video_list, True, True, 0) +hbox.pack_start(status_button, False, True, 0) +hbox.pack_start(open_button, False, True, 0) + +# text box for holding results +results = Gtk.TextView() +results.set_size_request(320, 64) +results.props.editable = results.props.cursor_visible = False +results.set_left_margin(4) + +# combine inputs, scanner, and results vertically +vbox = Gtk.VBox(spacing=8) +vbox.pack_start(hbox, False, True, 0) +vbox.pack_start(zbar, True, True, 0) +vbox.pack_start(results, False, True, 0) + +window.add(vbox) + +# FIXME: how to fill the geometry parameter? +#geo = {"min_width": 320, "min_height": 240} +#window.set_geometry_hints(geometry_widget=zbar, geometry=geo ) +window.show_all() + +Gtk.main() diff --git a/test/test_images.c b/test/test_images.c new file mode 100644 index 0000000..68a3251 --- /dev/null +++ b/test/test_images.c @@ -0,0 +1,533 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "config.h" +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <zbar.h> +#include "test_images.h" + +typedef enum format_type_e +{ + GRAY, + YUVP, + YVUP, + YUYV, + YVYU, + UYVY, + RGB888, + BGR888, + RGB565B = 0x0565, + RGB565L = 0x1565, + RGB555B = 0x0555, + RGB555L = 0x1555, +} format_type_t; + +typedef struct format_def_s { + uint32_t format; + format_type_t type; + uint8_t bpp; + uint8_t xdiv, ydiv; +} format_def_t; + +typedef union packed_u { + uint32_t u32[3]; + uint16_t u16[6]; + uint8_t u8[12]; +} packed_t; + +/* bar colors */ +static const uint8_t Cr[] = { 0x22, 0x92, 0x80, 0xf0, 0x10, 0x80, 0x6e, 0xde }; +static const uint8_t Cb[] = { 0x36, 0x10, 0x80, 0x5a, 0xa6, 0x80, 0xf0, 0xca }; + +static const format_def_t formats[] = { + { fourcc('G', 'R', 'E', 'Y'), GRAY, 8, 0, 0 }, + { fourcc('Y', '8', '0', '0'), GRAY, 8, 0, 0 }, + { fourcc('Y', '8', ' ', ' '), GRAY, 8, 0, 0 }, + { fourcc('Y', '8', 0, 0), GRAY, 8, 0, 0 }, + + { fourcc('Y', 'U', 'V', '9'), YUVP, 9, 4, 4 }, + { fourcc('Y', 'V', 'U', '9'), YVUP, 9, 4, 4 }, + + { fourcc('I', '4', '2', '0'), YUVP, 12, 2, 2 }, + { fourcc('Y', 'U', '1', '2'), YUVP, 12, 2, 2 }, + { fourcc('Y', 'V', '1', '2'), YVUP, 12, 2, 2 }, + { fourcc('4', '1', '1', 'P'), YUVP, 12, 4, 1 }, + + { fourcc('N', 'V', '1', '2'), YUVP, 12, 2, 2 }, + { fourcc('N', 'V', '2', '1'), YVUP, 12, 2, 2 }, + + { fourcc('4', '2', '2', 'P'), YUVP, 16, 2, 1 }, + + { fourcc('Y', 'U', 'Y', 'V'), YUYV, 16, 2, 1 }, + { fourcc('Y', 'U', 'Y', '2'), YUYV, 16, 2, 1 }, + { fourcc('Y', 'V', 'Y', 'U'), YVYU, 16, 2, 1 }, + { fourcc('U', 'Y', 'V', 'Y'), UYVY, 16, 2, 1 }, + + { + fourcc('R', 'G', 'B', '3'), + RGB888, + 24, + }, + { + fourcc('B', 'G', 'R', '3'), + BGR888, + 24, + }, + { + fourcc(3, 0, 0, 0), + RGB888, + 32, + }, + { + fourcc('R', 'G', 'B', '4'), + RGB888, + 32, + }, + { + fourcc('B', 'G', 'R', '4'), + BGR888, + 32, + }, + { + fourcc('R', 'G', 'B', 'P'), + RGB565L, + 16, + }, + { + fourcc('R', 'G', 'B', 'O'), + RGB555L, + 16, + }, + { + fourcc('R', 'G', 'B', 'R'), + RGB565B, + 16, + }, + { + fourcc('R', 'G', 'B', 'Q'), + RGB555B, + 16, + }, + { 0 } +}; + +static const char *encoded_widths = + "9 111 212241113121211311141132 11111 311213121312121332111132 111 9"; +const char *test_image_ean13_data = "6268964977804"; + +static int allocated_images = 0; + +int test_image_check_cleanup() +{ + if (allocated_images) + fprintf(stderr, "ERROR: %d image data buffers still allocated\n", + allocated_images); + /*else + fprintf(stderr, "all image data buffers freed\n");*/ + return (allocated_images); +} + +static void test_cleanup_handler(zbar_image_t *img) +{ + void *data = (void *)zbar_image_get_data(img); + /*fprintf(stderr, "cleanup image data @%p\n", data);*/ + free(data); + allocated_images--; +} + +static inline const format_def_t *lookup_format(zbar_image_t *img) +{ + uint32_t ifmt = zbar_image_get_format(img); + const format_def_t *fmt; + for (fmt = formats; fmt->format; fmt++) + if (fmt->format == ifmt) + break; + if (!fmt->format) { + fprintf(stderr, "ERROR: no %.4s (%08" PRIx32 ") format\n", + (char *)&ifmt, ifmt); + return (NULL); + } + return (fmt); +} + +static inline const format_def_t *alloc_data(zbar_image_t *img) +{ + allocated_images++; + const format_def_t *fmt = lookup_format(img); + if (!fmt) + return (NULL); + + unsigned w = zbar_image_get_width(img); + unsigned h = zbar_image_get_height(img); + unsigned long planelen = w * h; + unsigned long datalen = planelen * fmt->bpp / 8; + uint8_t *data = malloc(datalen); + + zbar_image_set_data(img, data, datalen, test_cleanup_handler); + + /*fprintf(stderr, "create %.4s(%08"PRIx32") image data %lx bytes @%p\n", + (char*)&fmt->format, fmt->format, datalen, data);*/ + return (fmt); +} + +/* write intensity plane */ +static inline uint8_t *fill_bars_y(uint8_t *p, unsigned w, unsigned h) +{ + unsigned x, y, i; + unsigned y0 = (h + 31) / 30; + for (y = 0; y < y0; y++) + for (x = 0; x < w; x++) + *(p++) = 0xff; + + for (; y < h - y0; y++) + for (x = 0, i = 0; x < w; i++) { + assert(i < 8); + unsigned x0 = (((i + 1) * w) + 7) >> 3; + assert(x0 <= w); + unsigned v = ((((i & 1) ? y : h - y) * 256) + h - 1) / h; + for (; x < x0; x++) + *(p++) = v; + } + + for (; y < h; y++) + for (x = 0; x < w; x++) + *(p++) = 0xff; + + return (p); +} + +/* write Cb (U) or Cr (V) plane */ +static inline uint8_t *fill_bars_uv(uint8_t *p, unsigned w, unsigned h, + const uint8_t *C) +{ + unsigned x, y, i; + unsigned y0 = (h + 31) / 30; + + for (y = 0; y < y0; y++) + for (x = 0; x < w; x++) + *(p++) = 0x80; + + for (; y < h - y0; y++) + for (x = 0, i = 0; x < w; i++) { + assert(i < 8); + unsigned x0 = (((i + 1) * w) + 7) >> 3; + assert(x0 <= w); + for (; x < x0; x++) + *(p++) = C[i]; + } + + for (; y < h; y++) + for (x = 0; x < w; x++) + *(p++) = 0x80; + + return (p); +} + +/* write packed CbCr plane */ +static inline uint8_t *fill_bars_nv(uint8_t *p, unsigned w, unsigned h, + format_type_t order) +{ + unsigned x, y, i; + unsigned y0 = (h + 31) / 30; + + for (y = 0; y < y0; y++) + for (x = 0; x < w; x++) { + *(p++) = 0x80; + *(p++) = 0x80; + } + + for (; y < h - y0; y++) + for (x = 0, i = 0; x < w; i++) { + assert(i < 8); + unsigned x0 = (((i + 1) * w) + 7) >> 3; + assert(x0 <= w); + uint8_t u = (order == YUVP) ? Cb[i] : Cr[i]; + uint8_t v = (order == YUVP) ? Cr[i] : Cb[i]; + for (; x < x0; x++) { + *(p++) = u; + *(p++) = v; + } + } + + for (; y < h; y++) + for (x = 0; x < w; x++) { + *(p++) = 0x80; + *(p++) = 0x80; + } + + return (p); +} + +/* write packed YCbCr plane */ +static inline uint8_t *fill_bars_yuv(uint8_t *p, unsigned w, unsigned h, + format_type_t order) +{ + unsigned x, y, i; + unsigned y0 = (h + 31) / 30; + packed_t yuv; + uint32_t *q = (uint32_t *)p; + w /= 2; + + yuv.u8[0] = yuv.u8[2] = (order == UYVY) ? 0x80 : 0xff; + yuv.u8[1] = yuv.u8[3] = (order == UYVY) ? 0xff : 0x80; + for (y = 0; y < y0; y++) + for (x = 0; x < w; x++) + *(q++) = yuv.u32[0]; + + for (; y < h - y0; y++) + for (x = 0, i = 0; x < w; i++) { + assert(i < 8); + unsigned x0 = (((i + 1) * w) + 7) >> 3; + assert(x0 <= w); + unsigned v = ((((i & 1) ? y : h - y) * 256) + h - 1) / h; + if (order == UYVY) { + yuv.u8[0] = Cb[i]; + yuv.u8[2] = Cr[i]; + yuv.u8[1] = yuv.u8[3] = v; + } else { + yuv.u8[0] = yuv.u8[2] = v; + yuv.u8[1] = (order == YUYV) ? Cb[i] : Cr[i]; + yuv.u8[3] = (order == YVYU) ? Cr[i] : Cb[i]; + } + for (; x < x0; x++) + *(q++) = yuv.u32[0]; + } + + yuv.u8[0] = yuv.u8[2] = (order == UYVY) ? 0x80 : 0xff; + yuv.u8[1] = yuv.u8[3] = (order == UYVY) ? 0xff : 0x80; + for (; y < h; y++) + for (x = 0; x < w; x++) + *(q++) = yuv.u32[0]; + + return ((uint8_t *)q); +} + +static inline uint8_t *fill_bars_rgb(uint8_t *p, unsigned w, unsigned h, + format_type_t order, int bpp) +{ + unsigned x, y, i; + unsigned y0 = (h + 31) / 30; + packed_t rgb; + + unsigned headlen = y0 * w * bpp / 8; + memset(p, 0xff, headlen); + uint32_t *q = (uint32_t *)(p + headlen); + + for (y = y0; y < h - y0; y++) + for (x = 0, i = 0; x < w; i++) { + assert(i < 8); + /* FIXME clean this up... */ + unsigned x0 = (((i + 1) * w) + 7) >> 3; + assert(x0 <= w); + unsigned yi = (i & 1) ? y : h - y; + unsigned v1, v0; + if (yi < h / 2 - 1) { + v1 = ((yi * 0x180) + h - 1) / h + 0x40; + v0 = 0x00; + } else { + v1 = 0xff; + v0 = (((yi - (h / 2)) * 0x180) + h - 1) / h + 0x40; + } + + uint8_t r = (i & 4) ? v1 : v0; + uint8_t g = (i & 2) ? v1 : v0; + uint8_t b = (i & 1) ? v1 : v0; + if (bpp == 32) { + if (order == RGB888) { + rgb.u8[0] = 0xff; + rgb.u8[1] = r; + rgb.u8[2] = g; + rgb.u8[3] = b; + } else { + rgb.u8[0] = b; + rgb.u8[1] = g; + rgb.u8[2] = r; + rgb.u8[3] = 0xff; + } + for (; x < x0; x++) + *(q++) = rgb.u32[0]; + } else if (bpp == 24) { + rgb.u8[0] = rgb.u8[3] = rgb.u8[6] = rgb.u8[9] = + (order == RGB888) ? r : b; + rgb.u8[1] = rgb.u8[4] = rgb.u8[7] = rgb.u8[10] = g; + rgb.u8[2] = rgb.u8[5] = rgb.u8[8] = rgb.u8[11] = + (order == RGB888) ? b : r; + for (; x < x0; x += 4) { + *(q++) = rgb.u32[0]; + *(q++) = rgb.u32[1]; + *(q++) = rgb.u32[2]; + } + } else { + assert(bpp == 16); + r = ((r + 7) / 8) & 0x1f; + b = ((b + 7) / 8) & 0x1f; + if ((order & 0x0fff) == 0x0555) { + g = ((g + 7) / 8) & 0x1f; + rgb.u16[0] = b | (g << 5) | (r << 10); + } else { + g = ((g + 3) / 4) & 0x3f; + rgb.u16[0] = b | (g << 5) | (r << 11); + } + if (order & 0x1000) + rgb.u16[0] = (rgb.u16[0] >> 8) | (rgb.u16[0] << 8); + rgb.u16[1] = rgb.u16[0]; + for (; x < x0; x += 2) + *(q++) = rgb.u32[0]; + } + } + + memset(q, 0xff, headlen); + return (((uint8_t *)q) + headlen); +} + +int test_image_bars(zbar_image_t *img) +{ + const format_def_t *fmt = alloc_data(img); + if (!fmt) + return (-1); + + unsigned w = zbar_image_get_width(img); + unsigned h = zbar_image_get_height(img); + uint8_t *data = (void *)zbar_image_get_data(img); + assert(data); + uint8_t *p = data; + switch (fmt->type) { + case GRAY: + case YUVP: /* planar YUV */ + case YVUP: + p = fill_bars_y(p, w, h); + if (fmt->type != GRAY) { + w = (w + fmt->xdiv - 1) / fmt->xdiv; + h = (h + fmt->ydiv - 1) / fmt->ydiv; + } else + break; + + if (fmt->format == fourcc('N', 'V', '1', '2') || + fmt->format == fourcc('N', 'V', '2', '1')) + p = fill_bars_nv(p, w, h, fmt->type); + else if (fmt->type == YUVP || fmt->type == YVUP) { + p = fill_bars_uv(p, w, h, (fmt->type == YUVP) ? Cb : Cr); + p = fill_bars_uv(p, w, h, (fmt->type == YUVP) ? Cr : Cb); + } + break; + + case YUYV: /* packed YUV */ + case YVYU: + case UYVY: + p = fill_bars_yuv(p, w, h, fmt->type); + break; + + default: /* RGB */ + p = fill_bars_rgb(p, w, h, fmt->type, fmt->bpp); + break; + } + + assert(p == data + zbar_image_get_data_length(img)); + return (0); +} + +int test_image_ean13(zbar_image_t *img) +{ + unsigned w = 114, h = 85; + zbar_image_set_size(img, w, h); + + const format_def_t *fmt = alloc_data(img); + if (!fmt) + return (-1); + + uint8_t *data = (void *)zbar_image_get_data(img); + unsigned int datalen = zbar_image_get_data_length(img); + assert(data && datalen); + + uint8_t *p = data; + /* FIXME randomize? */ + memset(data, 0x80, datalen); + + int nrep = 1, nskip = 0; + switch (fmt->type) { + case YUVP: /* planar YUV */ + case YVUP: + case GRAY: + break; + + case UYVY: /* packed YUV */ + p++; + case YUYV: + case YVYU: + nskip = 1; + break; + + default: /* RGB */ + nrep = fmt->bpp / 8; + } + + int y = 0, x, i; + for (; y < 10 && y < h; y++) + for (x = 0; x < w; x++) { + for (i = 0; i < nrep; i++) + *p++ = 0xff; + p += nskip; + } + + for (; y < h - 10; y++) { + uint8_t color = 0xff; + const char *c; + for (x = 0, c = encoded_widths; *c; c++) { + int dx; + if (*c == ' ') + continue; + for (dx = *c - '0'; dx > 0; dx--) { + for (i = 0; i < nrep; i++) + *p++ = color; + p += nskip; + x++; + } + color = ~color; + } + assert(!color); + for (; x < w; x++) { + for (i = 0; i < nrep; i++) + *p++ = 0xff; + p += nskip; + } + assert(x == w); + } + + for (; y < h; y++) + for (x = 0; x < w; x++) { + for (i = 0; i < nrep; i++) + *p++ = 0xff; + p += nskip; + } + + if (fmt->type == UYVY) + p--; + assert(p == data + datalen); + return (0); +} diff --git a/test/test_images.h b/test/test_images.h new file mode 100644 index 0000000..47ead45 --- /dev/null +++ b/test/test_images.h @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2010 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ +#ifndef _TEST_IMAGES_H_ +#define _TEST_IMAGES_H_ + +#define fourcc zbar_fourcc + +#ifdef __cplusplus + +extern "C" { +int test_image_check_cleanup(void); +int test_image_bars(zbar::zbar_image_t *); +int test_image_ean13(zbar::zbar_image_t *); +} + +#else + +int test_image_check_cleanup(void); +int test_image_bars(zbar_image_t *); +int test_image_ean13(zbar_image_t *); + +#endif + +extern const char *test_image_ean13_data; + +#endif diff --git a/test/test_jpeg.c b/test/test_jpeg.c new file mode 100644 index 0000000..9e1bba6 --- /dev/null +++ b/test/test_jpeg.c @@ -0,0 +1,158 @@ +/*------------------------------------------------------------------------ + * Copyright 2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "config.h" +#include <argp.h> +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#include <zbar.h> + +#include "test_images.h" + +unsigned char jpeg[405] = { + 255, 216, 255, 224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0, + 72, 0, 72, 0, 0, 255, 219, 0, 67, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 255, + 219, 0, 67, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 255, 192, 0, 17, 8, 0, 8, + 0, 8, 3, 1, 17, 0, 2, 17, 1, 3, 17, 1, 255, 196, 0, + 20, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 255, 196, 0, 32, 16, 0, 1, 2, 5, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 20, 22, 0, 8, + 18, 19, 24, 6, 23, 36, 37, 39, 255, 196, 0, 20, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, + 255, 196, 0, 35, 17, 0, 2, 1, 1, 7, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 20, 21, 19, 22, 0, 1, 7, 18, 23, + 36, 38, 3, 4, 35, 37, 52, 255, 218, 0, 12, 3, 1, 0, 2, + 17, 3, 17, 0, 63, 0, 118, 93, 56, 89, 200, 157, 68, 199, 111, + 134, 71, 23, 12, 215, 215, 130, 197, 136, 103, 143, 117, 170, 97, 48, + 42, 244, 202, 12, 216, 179, 211, 183, 29, 252, 24, 42, 160, 197, 45, + 65, 146, 62, 181, 91, 48, 134, 52, 246, 76, 170, 151, 4, 42, 137, + 198, 104, 56, 214, 96, 193, 7, 120, 197, 15, 154, 194, 128, 216, 207, + 170, 114, 197, 220, 215, 36, 130, 123, 155, 219, 184, 172, 222, 150, 146, + 23, 191, 47, 17, 204, 2, 197, 155, 246, 180, 206, 226, 223, 255, 217, +}; + +unsigned char rgb[8 * 8 * 3] = { + 255, 255, 255, 176, 238, 176, 94, 220, 94, 60, 213, 60, 60, 213, 60, + 94, 220, 94, 176, 238, 176, 255, 255, 255, 176, 238, 176, 46, 210, 46, + 10, 102, 10, 17, 204, 17, 17, 204, 17, 10, 102, 10, 46, 210, 46, + 176, 238, 176, 94, 220, 94, 19, 204, 19, 9, 102, 9, 17, 204, 17, + 17, 204, 17, 9, 102, 9, 19, 204, 19, 94, 220, 94, 60, 213, 60, + 17, 204, 17, 9, 102, 9, 17, 204, 17, 17, 204, 17, 9, 102, 9, + 17, 204, 17, 60, 213, 60, 60, 213, 60, 17, 204, 17, 17, 204, 17, + 17, 204, 17, 17, 204, 17, 17, 204, 17, 17, 204, 17, 60, 213, 60, + 94, 220, 94, 10, 102, 10, 17, 204, 17, 17, 204, 17, 17, 204, 17, + 17, 204, 17, 10, 102, 10, 94, 220, 94, 176, 238, 176, 46, 210, 46, + 10, 102, 10, 9, 102, 9, 9, 102, 9, 10, 102, 10, 46, 210, 46, + 176, 238, 176, 255, 255, 255, 176, 238, 176, 94, 220, 94, 60, 213, 60, + 60, 213, 60, 94, 220, 94, 176, 238, 176, 255, 255, 255, +}; + +#define PROGRAM_NAME "test_video" + +static const char doc[] = + "\nTest if ZBar is able to handle a video input (camera)\n"; + +static const struct argp_option options[] = { + { "quiet", 'q', 0, 0, "Don't be verbose", 0 }, + { "help", '?', 0, 0, "Give this help list", -1 }, + { "usage", -3, 0, 0, "Give a short usage message", 0 }, + { 0 } +}; + +static int quiet = 0; + +static error_t parse_opt(int k, char *optarg, struct argp_state *state) +{ + switch (k) { + case 'q': + quiet = 1; + break; + case '?': + argp_state_help(state, state->out_stream, + ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_DOC); + exit(0); + case -3: + argp_state_help(state, state->out_stream, ARGP_HELP_USAGE); + exit(0); + default: + return ARGP_ERR_UNKNOWN; + }; + return 0; +} + +static const struct argp argp = { + .options = options, + .parser = parse_opt, + .doc = doc, +}; + +int main(int argc, char **argv) +{ + if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, 0, 0)) { + argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME); + return -1; + } + if (!quiet) + zbar_set_verbosity(32); + else + zbar_set_verbosity(0); + + zbar_processor_t *proc = zbar_processor_create(0); + assert(proc); + if (zbar_processor_init(proc, NULL, 1)) + return (2); + + zbar_image_t *img = zbar_image_create(); + zbar_image_set_size(img, 8, 8); + zbar_image_set_format(img, fourcc('J', 'P', 'E', 'G')); + zbar_image_set_data(img, jpeg, sizeof(jpeg), NULL); + + zbar_image_t *test = zbar_image_convert(img, fourcc('Y', '8', '0', '0')); + if (!test) + return (2); + if (!quiet) + printf("converted: %d x %d (%lx) %08lx\n", zbar_image_get_width(test), + zbar_image_get_height(test), zbar_image_get_data_length(test), + zbar_image_get_format(test)); + + if (zbar_process_image(proc, test) < 0) + return (3); + if (zbar_processor_set_visible(proc, 1)) + return (4); + + printf("jpeg PASSED.\n"); + return (0); +} diff --git a/test/test_perl.pl b/test/test_perl.pl new file mode 100755 index 0000000..cc28ffb --- /dev/null +++ b/test/test_perl.pl @@ -0,0 +1,47 @@ +#!/usr/bin/env perl +#------------------------------------------------------------------------ +# Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net> +# +# This file is part of the ZBar Bar Code Reader. +# +# The ZBar Bar Code Reader is free software; you can redistribute it +# and/or modify it under the terms of the GNU Lesser Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# The ZBar Bar Code Reader is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with the ZBar Bar Code Reader; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA +# +# http://sourceforge.net/projects/zbar +#------------------------------------------------------------------------ + +use 5.006; +use warnings; +use strict; + +use Barcode::ZBar; + +Barcode::ZBar::set_verbosity(15); + +my $proc = Barcode::ZBar::Processor->new(1); + +$proc->init($ARGV[0] || '/dev/video0'); + +$proc->set_visible(); +$proc->user_wait(2); + +$proc->set_active(); +$proc->user_wait(5); + +$proc->set_active(0); +$proc->user_wait(2); + +$proc->process_one(); +$proc->user_wait(1); diff --git a/test/test_proc.c b/test/test_proc.c new file mode 100644 index 0000000..46eb992 --- /dev/null +++ b/test/test_proc.c @@ -0,0 +1,170 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "config.h" +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <zbar.h> +#include "test_images.h" + +zbar_processor_t *proc = NULL; +int use_threads = 1, use_window = 1; + +int input_wait(int timeout) +{ + if (timeout >= 0) + fprintf(stderr, "waiting %d.%03ds for input...", timeout / 1000, + timeout % 1000); + else + fprintf(stderr, "waiting indefinitely for input..."); + fflush(stderr); + int rc = zbar_processor_user_wait(proc, timeout); + if (rc > 0) + fprintf(stderr, "got input (%02x)\n", rc); + else if (!rc) + fprintf(stderr, "timed out\n"); + else if (zbar_processor_get_error_code(proc) == ZBAR_ERR_CLOSED) + use_window = rc = 0; + fflush(stderr); + return (rc); +} + +int main(int argc, char **argv) +{ + zbar_set_verbosity(127); + char *video_dev = NULL; + uint32_t fmt = 0; + int i, j = 0; + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (!strncmp(argv[i], "-thr", 4)) + use_threads = 0; + else if (!strncmp(argv[i], "-win", 4)) + use_window = 0; + else + return (1); + } else if (!j++) + video_dev = argv[i]; + else if (j++ == 1) { + int n = strlen(argv[i]); + if (n > 4) + n = 4; + memcpy((char *)&fmt, argv[i], n); + } + } + if (!fmt) + fmt = fourcc('B', 'G', 'R', '3'); + + proc = zbar_processor_create(use_threads); + assert(proc); + fprintf(stderr, "created processor (%sthreaded)\n", + (!use_threads) ? "un" : ""); + fflush(stderr); + + if (zbar_processor_init(proc, NULL, 0)) + return (2); + fprintf(stderr, "initialized (video=disabled, window=disabled)\n"); + fflush(stderr); + + zbar_image_t *img = zbar_image_create(); + zbar_image_set_size(img, 640, 480); + zbar_image_set_format(img, fmt); + test_image_bars(img); + + if (zbar_process_image(proc, img) < 0) + return (3); + fprintf(stderr, "processed test image\n"); + fflush(stderr); + + if (zbar_processor_init(proc, video_dev, use_window)) + return (2); + fprintf(stderr, "reinitialized (video=%s, window=%s)\n", + (video_dev) ? video_dev : "disabled", + (use_window) ? "enabled" : "disabled"); + fflush(stderr); + + if (use_window) { + if (zbar_processor_set_visible(proc, 1)) + return (4); + fprintf(stderr, "window visible\n"); + fflush(stderr); + } + + if (input_wait((use_window && !video_dev) ? -1 : 2000) < 0) + return (5); + + if (zbar_process_image(proc, img) < 0) + return (3); + fprintf(stderr, "processed test image\n"); + fflush(stderr); + zbar_image_destroy(img); + + if (input_wait((use_window && !video_dev) ? -1 : 3333) < 0) + return (5); + + if (video_dev) { + if (zbar_processor_set_active(proc, 1)) + return (3); + fprintf(stderr, "video activated\n"); + fflush(stderr); + + if (input_wait((use_window) ? -1 : 4000) < 0) + return (5); + + if (zbar_processor_set_active(proc, 0)) + return (3); + fprintf(stderr, "video deactivated\n"); + fflush(stderr); + + if (input_wait((use_window) ? -1 : 4000) < 0) + return (5); + + /* FIXME test process_one() */ + } + + if (zbar_process_image(proc, NULL)) + return (3); + fprintf(stderr, "flushed image\n"); + fflush(stderr); + + if (input_wait((use_window && !video_dev) ? -1 : 2500) < 0) + return (5); + + fprintf(stderr, "cleaning up...\n"); + fflush(stderr); + + zbar_processor_destroy(proc); + proc = NULL; + if (test_image_check_cleanup()) + return (32); + return (0); +} diff --git a/test/test_pygtk.py b/test/test_pygtk.py new file mode 100755 index 0000000..fc19fa9 --- /dev/null +++ b/test/test_pygtk.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python2 +#------------------------------------------------------------------------ +# Copyright 2008-2009 (c) Jeff Brown <spadix@users.sourceforge.net> +# +# This file is part of the ZBar Bar Code Reader. +# +# The ZBar Bar Code Reader is free software; you can redistribute it +# and/or modify it under the terms of the GNU Lesser Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# The ZBar Bar Code Reader is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with the ZBar Bar Code Reader; if not, write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, +# Boston, MA 02110-1301 USA +# +# http://sourceforge.net/projects/zbar +#------------------------------------------------------------------------ +import sys, os, stat +import pygtk, gtk +import zbarpygtk + +def decoded(zbar, data): + """callback invoked when a barcode is decoded by the zbar widget. + displays the decoded data in the text box + """ + buf = results.props.buffer + end = buf.get_end_iter() + buf.insert(end, data + "\n") + results.scroll_to_iter(end, 0) + +def video_enabled(zbar, param): + """callback invoked when the zbar widget enables or disables + video streaming. updates the status button state to reflect the + current video state + """ + enabled = zbar.get_video_enabled() + if status_button.get_active() != enabled: + status_button.set_active(enabled) + +def video_opened(zbar, param): + """callback invoked when the zbar widget opens or closes a video + device. also called when a device is closed due to error. + updates the status button state to reflect the current video state + """ + opened = zbar.get_video_opened() + status_button.set_sensitive(opened) + set_status_label(opened, zbar.get_video_enabled()) + +def video_changed(widget): + """callback invoked when a new video device is selected from the + drop-down list. sets the new device for the zbar widget, + which will eventually cause it to be opened and enabled + """ + dev = video_list.get_active_text() + if dev[0] == '<': + dev = '' + zbar.set_video_device(dev) + +def status_button_toggled(button): + """callback invoked when the status button changes state + (interactively or programmatically). ensures the zbar widget + video streaming state is consistent and updates the display of the + button to represent the current state + """ + opened = zbar.get_video_opened() + active = status_button.get_active() + if opened and (active != zbar.get_video_enabled()): + zbar.set_video_enabled(active) + set_status_label(opened, active) + if active: + status_image.set_from_stock(gtk.STOCK_YES, gtk.ICON_SIZE_BUTTON) + else: + status_image.set_from_stock(gtk.STOCK_NO, gtk.ICON_SIZE_BUTTON) + +def open_button_clicked(button): + """callback invoked when the 'Open' button is clicked. pops up an + 'Open File' dialog which the user may use to select an image file. + if the image is successfully opened, it is passed to the zbar + widget which displays it and scans it for barcodes. results are + returned using the same hook used to report video results + """ + dialog = gtk.FileChooserDialog("Open Image File", window, + gtk.FILE_CHOOSER_ACTION_OPEN, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT)) + global open_file + if open_file: + dialog.set_filename(open_file) + try: + if dialog.run() == gtk.RESPONSE_ACCEPT: + open_file = dialog.get_filename() + pixbuf = gtk.gdk.pixbuf_new_from_file(open_file) + if pixbuf: + zbar.scan_image(pixbuf) + finally: + dialog.destroy() + +def set_status_label(opened, enabled): + """update status button label to reflect indicated state.""" + if not opened: + label = "closed" + elif enabled: + label = "enabled" + else: + label = "disabled" + status_button.set_label(label) + +open_file = None +video_device = None +if len(sys.argv) > 1: + video_device = sys.argv[1] + +# threads *must* be properly initialized to use zbarpygtk +gtk.gdk.threads_init() +gtk.gdk.threads_enter() + +window = gtk.Window() +window.set_title("test_pygtk") +window.set_border_width(8) +window.connect("destroy", gtk.main_quit) + +zbar = zbarpygtk.Gtk() +zbar.connect("decoded-text", decoded) + +# video device list combo box +video_list = gtk.combo_box_new_text() +video_list.connect("changed", video_changed) + +# enable/disable status button +status_button = gtk.ToggleButton("closed") +status_image = gtk.image_new_from_stock(gtk.STOCK_NO, gtk.ICON_SIZE_BUTTON) +status_button.set_image(status_image) +status_button.set_sensitive(False) + +# bind status button state and video state +status_button.connect("toggled", status_button_toggled) +zbar.connect("notify::video-enabled", video_enabled) +zbar.connect("notify::video-opened", video_opened) + +# open image file button +open_button = gtk.Button(stock=gtk.STOCK_OPEN) +open_button.connect("clicked", open_button_clicked) + +# populate video devices in combo box +video_list.append_text("<none>") +video_list.set_active(0) +for (root, dirs, files) in os.walk("/dev"): + for dev in files: + path = os.path.join(root, dev) + if not os.access(path, os.F_OK): + continue + info = os.stat(path) + if stat.S_ISCHR(info.st_mode) and os.major(info.st_rdev) == 81: + video_list.append_text(path) + if path == video_device: + video_list.set_active(len(video_list.get_model()) - 1) + video_device = None + +if video_device is not None: + video_list.append_text(video_device) + video_list.set_active(len(video_list.get_model()) - 1) + video_device = None + +# combine combo box and buttons horizontally +hbox = gtk.HBox(spacing=8) +hbox.pack_start(video_list) +hbox.pack_start(status_button, expand=False) +hbox.pack_start(open_button, expand=False) + +# text box for holding results +results = gtk.TextView() +results.set_size_request(320, 64) +results.props.editable = results.props.cursor_visible = False +results.set_left_margin(4) + +# combine inputs, scanner, and results vertically +vbox = gtk.VBox(spacing=8) +vbox.pack_start(hbox, expand=False) +vbox.pack_start(zbar) +vbox.pack_start(results, expand=False) + +window.add(vbox) +window.set_geometry_hints(zbar, min_width=320, min_height=240) +window.show_all() + +gtk.main() +gtk.gdk.threads_leave() diff --git a/test/test_python.py b/test/test_python.py new file mode 100755 index 0000000..7ffdf9f --- /dev/null +++ b/test/test_python.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +#------------------------------------------------------------------------ +# Copyright 2019 (c) Mauro Carvalho Chehab <mchehab+samsung@kernel.org> +# +# This file is part of the ZBar Bar Code Reader. +# +# The ZBar Bar Code Reader is free software; you can redistribute it +# and/or modify it under the terms of the GNU Lesser Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# The ZBar Bar Code Reader is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +#------------------------------------------------------------------------ + +from __future__ import print_function +import zbar, sys + +try: + from PIL import Image +except: + try: + import Image + except: + print("No image library on python. Aborting test") + sys.exit() + +if len(sys.argv) < 1 or len(sys.argv) > 3: + print("Usage: %s <file name> [<expected text to check>]") + sys.exit(-1) + +filename = sys.argv[1] + +org_image = Image.open(filename) + +image = org_image.convert(mode='L') + +width = image.size[0] +height = image.size[1] +raw_data = image.tobytes() + +scanner = zbar.ImageScanner() +image = zbar.Image(width=width, height=height, format='Y800', data=raw_data) +scanner.scan(image) + +if len(sys.argv) == 3: + text = sys.argv[2] + + found = False + for symbol in image: + found = True + if symbol.data == text: + print("OK") + else: + print("Expecting %s, received %s" % (text, symbol.data)) + + if not found: + print("Can't process file") +else: + for symbol in image: + print("Decoded as %s" % symbol.data) diff --git a/test/test_video.c b/test/test_video.c new file mode 100644 index 0000000..b8618d6 --- /dev/null +++ b/test/test_video.c @@ -0,0 +1,237 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "config.h" +#include <argp.h> +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <stdio.h> +#include <string.h> +#include <time.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#include <assert.h> + +#include <zbar.h> +#include "test_images.h" + +#ifdef _WIN32 +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif + +zbar_video_t *video; + +#define PROGRAM_NAME "test_video" + +static const char doc[] = + "\nTest if ZBar is able to handle a video input (camera)\n"; + +static const struct argp_option options[] = { + { "quiet", 'q', 0, 0, "Don't be verbose", 0 }, + { "dev", 'd', "devnode", 0, "open devnode for video in", 0 }, + { "format", 'f', "fourcc", 0, "Stop after #seconds", 0 }, + { "help", '?', 0, 0, "Give this help list", -1 }, + { "usage", -3, 0, 0, "Give a short usage message", 0 }, + { 0 } +}; + +static int quiet = 0; +uint32_t vidfmt = fourcc('B', 'G', 'R', '3'); +char *dev = ""; + +static error_t parse_opt(int k, char *optarg, struct argp_state *state) +{ + switch (k) { + case 'q': + quiet = 1; + break; + case 'f': { + int len = strlen(optarg); + if (len > 4) + len = 4; + memcpy((char *)&vidfmt, optarg, len); + if (len < 4) + memset(len + (char *)&vidfmt, 0, 4 - len); + break; + } + case 'd': + dev = optarg; + break; + case '?': + argp_state_help(state, state->out_stream, + ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG | ARGP_HELP_DOC); + exit(0); + case -3: + argp_state_help(state, state->out_stream, ARGP_HELP_USAGE); + exit(0); + default: + return ARGP_ERR_UNKNOWN; + }; + return 0; +} + +static const struct argp argp = { + .options = options, + .parser = parse_opt, + .doc = doc, +}; + +int main(int argc, char *argv[]) +{ + if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, 0, 0)) { + argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME); + return -1; + } + if (!quiet) + zbar_set_verbosity(31); + else + zbar_set_verbosity(0); + + video = zbar_video_create(); + if (!video) { + fprintf(stderr, "unable to allocate memory?!\n"); + return (1); + } + + zbar_video_request_size(video, 640, 480); + + if (zbar_video_open(video, dev)) { + zbar_video_error_spew(video, 0); + fprintf(stderr, + "ERROR: unable to access your video device\n" + "this program requires video capture support using" + " v4l version 1 or 2 or VfW\n" + " - is your video device located at \"%s\"?\n" + " - is your video driver installed? (check dmesg)\n" + " - make sure you have the latest drivers\n" + " - do you have read/write permission to access it?\n" + " - is another application is using it?\n" + " - does the device support video capture?\n" + " - does the device work with other programs?\n", + dev); + return (1); + } + if (!quiet) { + fprintf(stderr, "opened video device: %s (fd=%d)\n", dev, + zbar_video_get_fd(video)); + fflush(stderr); + } + + if (zbar_video_init(video, vidfmt)) { + fprintf(stderr, "ERROR: failed to set format: %.4s(%08x)\n", + (char *)&vidfmt, vidfmt); + return (zbar_video_error_spew(video, 0)); + } + + if (zbar_video_enable(video, 1)) { + fprintf(stderr, "ERROR: starting video stream\n"); + return (zbar_video_error_spew(video, 0)); + } + if (!quiet) { + fprintf(stderr, "started video stream...\n"); + fflush(stderr); + } + + zbar_image_t *image = zbar_video_next_image(video); + if (!image) { + fprintf(stderr, "ERROR: unable to capture image\n"); + return (zbar_video_error_spew(video, 0)); + } + uint32_t format = zbar_image_get_format(image); + unsigned width = zbar_image_get_width(image); + unsigned height = zbar_image_get_height(image); + const uint8_t *data = zbar_image_get_data(image); + if (!quiet) { + fprintf(stderr, "captured image: %d x %d %.4s @%p\n", width, height, + (char *)&format, data); + fflush(stderr); + } + + zbar_image_destroy(image); + + if (!quiet) { + fprintf(stderr, "\nstreaming 100 frames...\n"); + fflush(stderr); + } + + struct timespec start, end; +#if _POSIX_TIMERS > 0 + clock_gettime(CLOCK_REALTIME, &start); +#else + struct timeval ustime; + gettimeofday(&ustime, NULL); + start.tv_nsec = ustime.tv_usec * 1000; + start.tv_sec = ustime.tv_sec; +#endif + + int i; + for (i = 0; i < 100; i++) { + zbar_image_t *image = zbar_video_next_image(video); + if (!image) { + fprintf(stderr, "ERROR: unable to capture image\n"); + return (zbar_video_error_spew(video, 0)); + } + zbar_image_destroy(image); + } + +#if _POSIX_TIMERS > 0 + clock_gettime(CLOCK_REALTIME, &end); +#else + gettimeofday(&ustime, NULL); + end.tv_nsec = ustime.tv_usec * 1000; + end.tv_sec = ustime.tv_sec; +#endif + double ms = (end.tv_sec - start.tv_sec + + (end.tv_nsec - start.tv_nsec) / 1000000000.); + double fps = i / ms; + if (!quiet) { + fprintf(stderr, "\nprocessed %d images in %gs @%gfps\n", i, ms, fps); + fflush(stderr); + } + + if (zbar_video_enable(video, 0)) { + fprintf(stderr, "ERROR: while stopping video stream\n"); + return (zbar_video_error_spew(video, 0)); + } + + if (!quiet) { + fprintf(stderr, "\ncleaning up...\n"); + fflush(stderr); + } + + zbar_video_destroy(video); + + if (test_image_check_cleanup()) + return (32); + + fprintf(stderr, "video PASSED.\n"); + return (0); +} diff --git a/test/test_window.c b/test/test_window.c new file mode 100644 index 0000000..894c8af --- /dev/null +++ b/test/test_window.c @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------ + * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> + * + * This file is part of the ZBar Bar Code Reader. + * + * The ZBar Bar Code Reader is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * The ZBar Bar Code Reader is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser Public License for more details. + * + * You should have received a copy of the GNU Lesser Public License + * along with the ZBar Bar Code Reader; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * http://sourceforge.net/projects/zbar + *------------------------------------------------------------------------*/ + +#include "config.h" +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <stdio.h> +#include <string.h> + +#include <zbar.h> +#include "processor.h" +#include "test_images.h" + +zbar_processor_t proc; + +static void input_wait() +{ + fprintf(stderr, "waiting for input...\n"); + if (_zbar_window_handle_events(&proc, 1) < 0) + zbar_processor_error_spew(&proc, 1); +} + +int main(int argc, char *argv[]) +{ + zbar_set_verbosity(32); + + err_init(&proc.err, ZBAR_MOD_PROCESSOR); + proc.window = zbar_window_create(); + if (!proc.window) { + fprintf(stderr, "unable to allocate memory?!\n"); + return (1); + } + + int width = 640; + int height = 480; + + if (_zbar_window_open(&proc, "zbar window test", width, height) || + zbar_window_attach(proc.window, proc.display, proc.xwin) || + _zbar_window_set_visible(&proc, 1)) { + fprintf(stderr, "failed to open test window\n"); + return (1); + } + input_wait(); + + zbar_image_t *img = zbar_image_create(); + zbar_image_set_size(img, width, height); + zbar_image_set_format(img, fourcc('B', 'G', 'R', '4')); + /*fourcc('I','4','2','0')*/ + /*fourcc('Y','V','1','2')*/ + /*fourcc('U','Y','V','Y')*/ + /*fourcc('Y','U','Y','V')*/ + /*fourcc('R','G','B','3')*/ + /*fourcc('Y','8','0','0')*/ + test_image_bars(img); + + if (zbar_window_draw(proc.window, img) || zbar_window_redraw(proc.window)) { + fprintf(stderr, "error drawing image\n"); + return (1); + } + zbar_image_destroy(img); + img = NULL; + + input_wait(); + + /* FIXME display cmd arg images? or formats? */ + + fprintf(stderr, "cleaning up\n"); + zbar_window_destroy(proc.window); + + /* FIXME destructor check? */ + if (test_image_check_cleanup()) + return (32); + return (0); +} |