Check-in [f086cc43cf]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:added beginning port of libdmtx library with tcl binding
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f086cc43cf3144ad167daa9f29d95ecb10b6c41b
User & Date: chw 2015-08-11 16:57:17.269
Context
2015-08-12
10:15
added upstream changes to tablelist check-in: a5e4e5f7eb user: chw tags: trunk
2015-08-11
16:57
added beginning port of libdmtx library with tcl binding check-in: f086cc43cf user: chw tags: trunk
06:40
use after-idle handler for sound/music finish processing check-in: e6d02b004b user: chw tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Added assets/dmtx0.7.5/android_demo.tcl.
















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# Demo: DMC scanner using dmtx in AndroWish
# August 2015 <chw@ch-werner.de>

package require borg
package require dmtx

. configure -bg black
wm attributes . -fullscreen 1
sdltk screensaver off
sdltk touchtranslate 0
borg screenorientation landscape
bind all <Key-Break> exit
bind all <<DidEnterBackground>> do_pause

if {![borg camera open 0]} {
    label .nocam -text "Sorry, no camera found." -fg red -bg black -bd 0
    pack .nocam -side top -fill both -expand 1
    return
}

borg camera parameters preview-size 640x480
scan [dict get [borg camera parameters] preview-size] "%dx%d" width height

# scale used for dmtx decoder
if {$width > 1280} {
    set img_scale 3
} elseif {$width > 640} {
    set img_scale 2
} else {
    set img_scale 1
}

canvas .c -width $width -height $height -bg black -bd 0 -highlightthickness 0

sdltk root $width $height

pack .c -side top

image create photo cam_img
image create photo old_img
cam_img configure -width 640 -height 480
.c create image 0 0 -anchor nw -image cam_img
.c create text [expr {$width / 2}] 25 -fill #FFFFFF -tags data -anchor n \
    -font TkFixedFont

bind .c <1> start_stop
bind . <<ImageCapture>> {do_capture %x}

proc do_capture {flag} {
    if {$flag} {
	borg camera greyimage cam_img
	if {![catch {dmtx::async_decode cam_img dec_done $::img_scale} err]} {
	    old_img copy cam_img -compositingrule set
	}
    }
}

proc dec_done {flag time data} {
    if {$flag && ([borg camera state] eq "capture")} {
	borg camera stop
	cam_img copy old_img -compositingrule set
	set prdata $data
	regsub -all {[[:cntrl:]]} $prdata "\n" prdata
	.c itemconfigure data -text $prdata
	.c create rectangle {*}[.c bbox data] -fill #666666 -outline #FFFFFF \
	    -width 2 -tags databg
	.c lower databg data
	borg vibrate 100
	borg beep
    }
}

proc start_stop {} {
    if {[borg camera state] ne "capture"} {
	borg camera start
	.c itemconfigure data -text ""
	.c delete databg
    } else {
	borg camera stop
    }
}

proc do_pause {} {
    borg camera stop
    dmtx::async_decode stop
}

borg camera start
Added assets/dmtx0.7.5/pkgIndex.tcl.




>
>
1
2
package ifneeded dmtx 0.7.5 \
    [list load libdmtx[info sharedlibextension] Dmtx]
Added jni/libdmtx/AUTHORS.




>
>
1
2
Mike Laughton
Mackenzie Straight
Added jni/libdmtx/Android.mk.












































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
LOCAL_PATH := $(call my-dir)

##########################
#
# dmtx shared library
#
##########################

include $(CLEAR_VARS)

LOCAL_MODULE := dmtx

tcl_path := $(LOCAL_PATH)/../tcl

include $(tcl_path)/tcl-config.mk

tk_path := $(LOCAL_PATH)/../sdl2tk

include $(tk_path)/tk-config.mk

LOCAL_C_INCLUDES := $(tcl_includes) $(tk_includes) $(LOCAL_PATH)

LOCAL_CFLAGS := $(tcl_cflags) $(tk_cflags) \
	-DHAVE_SYS_TIME_H=1 \
	-DHAVE_GETTIMEOFDAY=1 \
	-DDMTX_VERSION="\"0.7.5\"" \
	-O2

LOCAL_SRC_FILES := dmtx.c tcldmtx.c

LOCAL_LDLIBS :=
LOCAL_STATIC_LIBRARIES :=
LOCAL_SHARED_LIBRARIES := tcl tk

LOCAL_EXPORT_C_INCLUDES += $(LOCAL_C_INCLUDES)

include $(BUILD_SHARED_LIBRARY)

Added jni/libdmtx/ChangeLog.






















































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
Changes for libdmtx
-----------------------------------------------------------------

version 0.7.4 [June 2011]
  library: Relicensed to use Simplified BSD with waiver option
  library: Added new error codes and messages in dmtxencode.c
  library: Added DmtxByteList struct and supporting functions
  library: Changed file header with updated text
  library: Fixed ECC bug for 144x144 case (thanks Huver!)
  library: New Reed Solomon implementation
  library: New repository structure: libdmtx, dmtx-utils, and dmtx-wrappers
  testing: Added test in compare_generated.sh to create directory if needed
  testing: Fix compare_generated.sh to prevent false negatives
  encoder: Review CHK macro strategy
  encoder: New encoding implementation
  encoder: Added Base 256 "encode to end of symbol" single byte header
  encoder: Check ProcessEndOfSymbolTriplet() for same problem fixed in Edifact
  encoder: Clean up PushCTXValues() passFail handling
  encoder: Fixed all encoding bugs reported by compare_generated.sh
  encoder: Fixed encoding bug affecting certain end-of-symbol conditions
  encoder: Replaced "twothirdsbits" encoder concept (major source of headaches)
  encoder: Track intermediate states in "optimize best" to handle all possibilities
  decoder: Use new Edifact decode function that doesn't assume full triplet

version 0.7.2 [September 2009]
  Added initial macro decoding support (thanks Marlon!)
  Fast quad fill for dmtxDecodeMatrixRegion() (thanks Mackenzie!)
  Fixed capacity bug with rectangle requests
  New Vala wrapper (thanks Evan!)
  Wrapper integration in build system (thanks Evan!)
  Add libdmtx-X.X.X.zip as source package option
  Add libdmtx-win32-X.X.X.zip as binary package option
  Add "project" directory to EXTRA_DIST in Makefile.am

version 0.7.0 [March 2009]
  New Java wrapper (thanks Pete and Dikran!)
  New .NET wrapper (thanks Vali and Joe!)
  Added solution and project files for MS Visual Studio 9.0
  Reader support for FNC1 and upper shift (thanks Robin!)
  Support for byte-padded rows through dmtxImageSetProp()
  New no-copy image handling with configurable pixel packing
  Moved image scaling factors to DmtxDecode
  Moved scan cache from DmtxImage to DmtxDecode
  Eliminate types DmtxRgb, DmtxColor3, and DmtxGradient
  API updates for consistent naming and conventions
  Added dmtxEncodeSetProp() and dmtxEncodeGetProp()
  Option to print extended ASCII as UTF-8 (thanks Robin!)
  Fixed diagnostic image output
  Fixed misrepresented capacity in verbose mode
  True vector SVG output bypassing ImageMagick (thanks Richard!)
  Use ImageMagick to write images in major raster formats
  Fixed several bugs and compiler warnings

version 0.6.0 [November 2008]
  dmtxread now scans all major image formats [Olivier]
  New encoding/decoding Ruby wrapper [Romain]
  Reduced memory footprint
  Will scan multiple barcodes per image
  Various platform-specific improvements
  Initial work preparing for custom pixel packing in future
  Begin static analysis cleanup with splint
  New --disable-dmtxread and --disable-dmtxwrite [Romain]
  Ability to specify max/min expected barcode sizes
  New edge neighbor tracking (Hough + 2 way edge cache)
  Info cache to track scan progress and avoid rescanning pixels
  Major reduction in floating point operations
  New informative return codes (found, not found, error)
  Read input from STDIN
  Diagnostic images display trail left by scanning logic
  Option to write output to STDOUT [Olivier]
  PHP wrapper now compiles with recent libdmtx
  Dedicated README.xxx instructions for specific platforms

version 0.5.2 [September 2008]
  Move SetRangeLimit and SetScanRegion into library
  Replace DMTXUTIL_SUCCESS/ERROR with DMTX_SUCCESS/FAILURE
  Add edge threshold filtering
  Add encoding support for 144x144 barcodes
  Fixed encoding case when message starts with two digits
  Fixed bug in range limit option
  Add dynamic image shrinking (pixel skipping)
  Add step-by-step diagnostic image dump (debug build)
  Fixed bug in minimum scan gap setting
  Removed y-flip from internal pixel storage
  Added strict border tests to eliminate false positives
  Added squareness deviation filter
  Implement simplified Hough transform for locating first edge
  Several behind-the-scenes performance enhancements
  Python wrapper update; 15x faster (thanks Jonathan!)
  New PHP wrapper code added
  Various improvements when building for OS X and FreeBSD

version 0.5.1 [July 2008]
  Fixed Extended ASCII encoding bug
  Fixed error correction bug related to multiple interleaved blocks
  Added timeout condition for region detection
  Allow partial and complete disabling of error correction
  Replaced DmtxPixel struct with DmtxRgb for safe pixel copies
  Tighter integration with libfec
  Conditional build logic for libtiff
  Added placeholder for new utility, dmtxquery
  Added unit test program for testing libdmtx internals
  Include local copies of getopt1.c, getopt.c, and getopt.h
  Various things to help compiling in MS VC++
  Lots of holes filled in comments (Doxygen)
  Fixed experimental Data Mosaic decoding
  New Cocoa/iPhone wrapper (thanks Stefan!)

version 0.5 [April 2008]
  Error correction using libfec (thanks Florian!)
  Rework encoding and decoding API for consistency and intuitiveness
  Handle region detection and region decoding as separate tasks
  Pass found regions back to calling app before attempting decode
  Image mask approach (for performance and multi-barcode scans)
  Fix TestForEndOfSymbolEdifact() to handle special cases correctly
  Roll scan pattern into core library (inward breadth-first cross)
  Replace dmtxScanLine() with dmtxScanPixel()
  Implement 4-direction weighted module decisions (eliminates thresholds)
  Add ability to scan portion of image
  Add --diagnose option that dumps image with embedded scan infomation
  Added Z rotation angle (in degrees) to verbose output
  Move ASCII and codeword output to separate --preview option
  Added -R option for setting image print resolution in dpi (PNG only)
  Remove gltest and simpletest from default build target
  Update Subversion to be keyword friendly ($Id$)
  Updated documentation to reflect API and option changes

version 0.4 [December 2007]
  Remove arbitrary sz scaling (100.0) since it doesn't matter anyway
  Fix 4 bottom-right modules in sizes where they are not used (thanks Matthias R.!)
  Replace callback references with preprocessor macros
  Implement remaining encodation schemes for encoding (X12, Base 256, etc...)
  Implement remaining encodation schemes for decoding (X12, Base 256, etc...)
  Implement --auto-best option for best possible encoding efficiency
  Implement multi-region symbols
  Read and write rectangle barcodes
  Use GNU autotools (autoconf, automake, libtool)
  New region detection overhaul
  Include initial version of Python bindings from pydmtx project (thanks Dan!)
  Add decoding functionality through Python
  Add marathon images to project (thanks john@sportcam.net!)
  Fix dmtxread crash when same barcode is found more than 16 times
  Verbose messages describing traits of detected barcodes
  --codewords option to print codewords instead of decoded message
  --newline option to insert newline character at end of output
  Additional output formats (PNG, ASCII, codewords)
  'make test' executes regression tests for encodation

version 0.3 [October 2006]
  Several high-level changes: build process, naming consistency, file layout
  Added new automatic style checks in script directory ("make style")
  Implemented remaining encodation schemes for decode (X12, Base 256, etc...)
  Fixed instability/regressions that were introduced in v0.2 release
  Color sampling now averaged from multiple pixel locations
  Size calibration accuracy improved with new approach
  dmtxread: increased default scanline count, added multi-page TIFF format
  dmtxwrite: bug fixes, implemented -o option
  Improved documentation: deps listed in INSTALL, new man page for dmtxwrite

version 0.2 [June 2006]
  Cleaned up program structure surrounding decoding process
  Improved API for real-world use (no longer just dumping results to STDOUT)
  Added "dmtxread" command line utility
  Added "dmtxwrite" command line utility
  Implemented Reed-Solomon error detection
  Created "simpletest.c" for full circle processing test
  Now using libpng(3) in library to read Data Matrix images
  Improved documentation (somewhat)

version 0.1 [April 2006]
  Initial release
Added jni/libdmtx/KNOWNBUG.
























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Bugs in libdmtx
-----------------------------------------------------------------

1. libdtmx - Core Library
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

While regular encoder works fine, the optimizer feature (--best)
still occasionally generates codeword sequences that are not 100%
legal according to the ISO specification.  Everything still
appears to decode properly, but until I have time to go through
every corner case and validate the behavior this will be treated
as an experimental feature.  For now dmtxwrite will encode using
a straight ASCII scheme by default.

Data Mosaic encoding doesn't produce output for certain sizes:

   $ echo -n foo | dmtxwrite -M    <-- works
   $ echo -n fooo | dmtxwrite -M   <-- doesn't work
   $ echo -n foooo | dmtxwrite -M  <-- works


2. Test Programs
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

multi_test:
  * No known issues (not included in general download)

rotate_test:
  * No known issues (not included in general download)

simple_test:
  * No known issues

unit_test:
  * Missing files   (not included in general download)


3. Scripts in the script directory
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

The check_headers.pl script verifies that every function has
a correctly-formed header comment.  But the test condition is
currently pretty simple, and does not test the first function
appearing in each file.
Added jni/libdmtx/LICENSE.




































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Copyright 2005-2011 Mike Laughton and others. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of the libdmtx project.

--------------------------------------------------------------------------------

ALTERNATE TERMS

Redistributions in binary form, with or without modification, are permitted
without including the above copyright notice, list of conditions, and disclaimer
if express written permission has been obtained from Dragonfly Logic, Inc.
Added jni/libdmtx/Makefile.am.
































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# Packaging commands (all run from libdmtx root):
# $ make distclean
# $ make dist-bzip2
# $ make dist-gzip

AUTOMAKE_OPTIONS = foreign

ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = -Wshadow -Wall -pedantic -ansi

lib_LTLIBRARIES = libdmtx.la
libdmtx_la_SOURCES = dmtx.c
libdmtx_la_CFLAGS = -Wall -pedantic

EXTRA_libdmtx_la_SOURCES = dmtxencode.c dmtxencodestream.c dmtxencodescheme.c \
	dmtxencodeoptimize.c dmtxencodeascii.c dmtxencodec40textx12.c \
	dmtxencodeedifact.c dmtxencodebase256.c dmtxdecode.c dmtxdecodescheme.c \
	dmtxmessage.c dmtxregion.c dmtxsymbol.c dmtxplacemod.c dmtxreedsol.c \
	dmtxscangrid.c dmtximage.c dmtxbytelist.c dmtxtime.c dmtxvector2.c \
	dmtxmatrix3.c dmtxstatic.h

include_HEADERS = dmtx.h

SUBDIRS = . test

dist_man_MANS = man/libdmtx.3

EXTRA_DIST = KNOWNBUG \
	LICENSE \
	README.cygwin \
	README.freebsd \
	README.linux \
	README.mingw \
	README.osx \
	README.unix \
	m4 \
	script/check_all.sh \
	script/check_comments.sh \
	script/check_copyright.sh \
	script/check_headers.pl \
	script/check_license.sh \
	script/check_spacing.sh \
	script/check_splint.sh \
	script/check_todo.sh \
	script/check_whitespace.sh

pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libdmtx.pc
Added jni/libdmtx/NEWS.






















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
26-May-2011: New official download page available
17-Mar-2011: Core library relicensed to Simplified BSD with waiver option
03-Mar-2011: libdmtx code now in SourceForge GIT repositories
29-Nov-2010: libdmtx binaries now available as official Fedora package
18-Nov-2009: Mikko Koppanen released improved PHP bindings for libdmtx
05-Nov-2009: "Onion" released a Gstreamer element using libdmtx
04-Sep-2009: New release: libdmtx-0.7.2 (Release Notes)
06-Aug-2009: Simon Wood released pyDataMatrixScanner at SourceForge
03-Aug-2009: Evan Nemerson added Vala support with a new wrapper
31-Jul-2009: libdmtx Documentation wiki moved to libdmtx.wikidot.com
19-May-2009: libdmtx project discussed in Linux Journal (March 2009)
12-Mar-2009: Python wrapper supports multi-barcode scans (thanks Simon!)
02-Mar-2009: New release: libdmtx-0.7.0 (Release Notes)
31-Jan-2009: Experimental libdmtx Windows binaries now available
23-Nov-2008: New release: libdmtx-0.6.0 (Release Notes)
08-Oct-2008: Olivier Guilyardi added support for all major image formats! (SVN)
04-Sep-2008: New release: libdmtx-0.5.2 (README)
20-Aug-2008: Significant performance gains available in SVN (latest tarball)
01-Jul-2008: New release: libdmtx-0.5.1 (README)
29-Jun-2008: libdmtx.org now hosted on a super efficient fit-PC
03-Jun-2008: New iPhone reader by Stefan Hafeneger (no jailbreak required)
31-May-2008: New libdmtx mailing lists replace forums
30-May-2008: GeoWeb does it again: CameraDMTX for Nokia N60
27-May-2008: Et tu, Cognex?
22-May-2008: Congratulations Cognex! Good guys 2, patent trolls 0
16-Apr-2008: New documentation wiki. Everyone can contribute!
13-Apr-2008: 5th release: libdmtx-0.5.0 (README)
22-Feb-2008: New phone video, this time on Symbian S60
15-Jan-2008: Unofficial .debs now available (thanks pcitizen!)
21-Dec-2007: Check out Martin's iDMTX video!
07-Dec-2007: 4th release: libdmtx-0.4.0 (README)
02-Dec-2007: Good news: Project is ACTIVE - new release soon
16-Aug-2007: Added new screenshots to show progress during freeze
30-Nov-2006: Bad news: Downloads have been halted (explanation)
15-Oct-2006: 3rd release: libdmtx-0.3.0 (README)
13-Sep-2006: Unstable version now available from CVS (instructions)
07-Sep-2006: Now taking feature requests for next release
11-Jun-2006: 2nd release: libdmtx-0.2.0 (view README file before using)
22-Apr-2006: 1st release: libdmtx-0.1.0 (view README file before using)
12-Mar-2006: Project home page changed hosting
24-Jan-2006: ISO/IEC 16022:2000 specification arrived in the mail
25-Nov-2005: Project home page libdmtx.sourceforge.net created
22-Nov-2005: SourceForge project created
Added jni/libdmtx/README.
















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
=================================================================
            libdmtx - Open Source Data Matrix Software
=================================================================

               libdmtx README file (all platforms)

This summary of the libdmtx package applies generally to all
platforms. For instructions regarding your specific platform,
also see the README.xxx file in this directory that matches your
system (e.g., README.linux, README.osx, etc...).


1. Introduction
-----------------------------------------------------------------

libdmtx is a software library that enables programs to read and
write Data Matrix barcodes of the modern ECC200 variety. The
library runs natively on several platforms and can be accessed by
multiple languages using the libdmtx language wrappers. The
utility programs dmtxread and dmtxwrite also provide a command
line interface for libdmtx, and serve as a good reference for
developers writing their own libdmtx-enabled programs.

This package (libdmtx) contains only the core library, and is
distributed under a Simplified BSD license with an alternate
waiver option. See the LICENSE file in the main project directory
for full terms of use and distribution.

The non-library components related to libdmtx are available as
separate downloads, and are distributed under a different license
(typically LGPLv2). Please contact support@dragonflylogic.com if
you require clarification on licensing. It's not complicated, but
it's important to us that all license terms are respected (not
just ours).


2. Project Components
-----------------------------------------------------------------

The libdmtx project serves a diverse audience and contains many
components -- some of which may not be useful to you. Components
fall into one of four categories:

  Description        Package        Audience
  -----------------  -------------  ----------------------
  Core library       libdmtx        libdmtx programs
  Test programs      libdmtx        libdmtx developers
  Utility programs   dmtx-utils     Shell and command line
  Language Wrappers  dmtx-wrappers  Non-C/C++ developers


3. Installation
-----------------------------------------------------------------

libdmtx uses GNU Autotools so installation should be familiar to
free software veterans. If your platform cannot easily run the
Autotools scripts, refer to the appropriate platform-specific
README.xxx located in this directory for alternate instructions.

In theory the following 3 steps would build and install libdmtx
on your system:

  $ ./configure
  $ make
  $ sudo make install

However, you may need to install additional software or make
other changes for these steps to work properly. The details below
will help to address errors and/or customize beyond the defaults.

Problems with "configure" step
----------------------------------------
If you obtained libdmtx from Git you may have received an error
like "./configure: No such file or directory". Run this command
before trying again:

  $ ./autogen.sh

The autogen.sh command requires autoconf, automake, libtool, and
pkgconfig to be installed on your system.

The configure script also offers many options for customizing the
build process, described in detail by running:

  $ ./configure --help

Problems with "make" step
----------------------------------------
Errors encountered during the "make" step are often a result of
missing software dependencies. Install any missing software
mentioned in the error message(s) and try again.

Problems with "sudo make install" step
----------------------------------------
If the 'sudo' command is not configured on your system, you can
alternatively yell "Yeeehaww!" as you log in as root and run it
like this:

  # make install

And finally...
----------------------------------------
If you want to verify that everything is working properly you can
optionally build the test programs:

  $ make check

This command will not perform any tests, but will build the
programs that contain test logic: multi_test, rotate_test,
simple_test, and unit_test.

Note: multi_test and rotate_test contain extra dependencies due
to their graphical nature, and are not terribly useful unless you
need to test the library's internals.


5. Contact
-----------------------------------------------------------------

Project website:       www.libdmtx.org
Documentation wiki:    libdmtx.wikidot.com
SourceForge.net page:  www.sourceforge.net/projects/libdmtx
OhLoh.net page:        www.ohloh.net/projects/libdmtx
Open mailing list:     libdmtx-open_discussion@lists.sourceforge.net
Professional support:  www.dragonflylogic.com/products


6. This Document
-----------------------------------------------------------------

This document is derived from the wiki page located at:

  http://libdmtx.wikidot.com/general-instructions

If you find an error or have additional helpful information,
please edit the wiki directly with your updates.
Added jni/libdmtx/README.cygwin.




























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
=================================================================
            libdmtx - Open Source Data Matrix Software
=================================================================

                  libdmtx README file (Cygwin)

This README.cygwin file contains information on installing and
using libdmtx on Windows in a Cygwin environment. The general
README file, also found in this directory, contains a high level
summary of libdmtx and its components.


1. Installing libdmtx on Windows using Cygwin
-----------------------------------------------------------------

libdmtx can be installed on Cygwin using the instructions
provided in the general README file. However, please see below
for additional details that might benefit users on this platform.


2. Dependencies
-----------------------------------------------------------------

The following packages must be installed to compile libdmtx on
Cygwin:

  * gcc
  * make
  * automake
  * pkg-config

Also, if libdmtx was obtained from Git:

  * autoconf
  * libtool


3. This Document
-----------------------------------------------------------------

This document is derived from the wiki page located at:

  http://libdmtx.wikidot.com/libdmtx-on-windows-using-cygwin

If you find an error or have additional helpful information,
please edit the wiki directly with your updates.
Added jni/libdmtx/README.freebsd.




















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
=================================================================
            libdmtx - Open Source Data Matrix Software
=================================================================

                  libdmtx README file (FreeBSD)

This README.freebsd file contains information on installing and
using libdmtx on FreeBSD. The general README file, also found in
this directory, contains a high level summary of libdmtx and its
components.


1. Installing libdmtx on FreeBSD
-----------------------------------------------------------------

libdmtx can be installed on FreeBSD using the instructions
provided in the general README file. However, please read below
for additional details that might benefit users on this platform.


2. Running configure
-----------------------------------------------------------------

FreeBSD users may need to export the CPPFLAGS and LDFLAGS
variables as follows before running configure:

   $ export CPPFLAGS=-I/usr/local/include
   $ export LDFLAGS=-L/usr/local/lib
   $ ./configure
   $ make
   $ sudo make install


3. This Document
-----------------------------------------------------------------

This document is derived from the wiki page located at:

  http://libdmtx.wikidot.com/libdmtx-on-freebsd

If you find an error or have additional helpful information,
please edit the wiki directly with your updates.
Added jni/libdmtx/README.linux.
















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
=================================================================
            libdmtx - Open Source Data Matrix Software
=================================================================

                 libdmtx README file (GNU/Linux)

This README.linux file contains information on installing and
using libdmtx on GNU/Linux. The general README file, also found
in this directory, contains a high level summary of libdmtx and
its components.


1. Installing libdmtx on GNU/Linux
-----------------------------------------------------------------

libdmtx can be installed on Linux using the instructions provided
in the general README file. However, please see below for
additional details that might benefit users on this platform.


2. Pre-Compiled Binaries
-----------------------------------------------------------------

Many Linux distributions offer pre-compiled libdmtx binaries in
their package repositories. This can be a real time saver if you
aren't required to build from source for other reasons.

Go to http://www.dragonflylogic.com/downloads for a list of all
download options available on your system.


3. This Document
-----------------------------------------------------------------

This document is derived from the wiki page located at:

  http://libdmtx.wikidot.com/libdmtx-on-gnu-linux

If you find an error or have additional helpful information,
please edit the wiki directly with your updates.
Added jni/libdmtx/README.mingw.








































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
=================================================================
            libdmtx - Open Source Data Matrix Software
=================================================================

                   libdmtx README file (MinGW)

This README.mingw file contains information on installing and
using libdmtx using MinGW. The general README file, also found in
this directory, contains a high level summary of libdmtx and its
components.


1. Installing libdmtx on Windows using MinGW and MSYS
-----------------------------------------------------------------

libdmtx can be installed on MinGW using the instructions provided
in the general README file. However, please see below for
additional details that might benefit users on this platform.


2. Installing MinGW and MSYS
-----------------------------------------------------------------

If you haven't done so already, first install MinGW, MSYS, and
all recommended updates to your Windows system. Instructions for
doing this are provided here:

  http://www.mingw.org/wiki/msys


3. Building and installing the core library
-----------------------------------------------------------------

To install libdmtx, download and unpack the libdmtx source to
your MSYS folder. If you accepted the installation defaults this
will be C:\msys\1.0.

Open the MSYS shell and run the following:

  $ ./configure
  $ make
  $ sudo make install

Go to folder .libs:

  $ cd .libs
  $ ls

Now you should see following output:

  libdmtx.a libdmtx.la libdmtx.lai  libdmtx_la-dmtx.o

Finally run:

  $ gcc -shared -o dmtx.dll libdmtx_la-dmtx.o -Wl,--out-implib,libdmtx.a

Now you should have working dmtx.dll in the folder .libs.


4. This Document
-----------------------------------------------------------------

This document is derived from the wiki page located at:

  http://libdmtx.wikidot.com/libdmtx-on-windows-using-mingw

If you find an error or have additional helpful information,
please edit the wiki directly with your updates.
Added jni/libdmtx/README.osx.








































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
=================================================================
            libdmtx - Open Source Data Matrix Software
=================================================================

                 libdmtx README file (Mac OS X)

This README.osx file contains information on installing and using
libdmtx on Mac OS X. The general README file, also found in this
directory, contains a high level summary of libdmtx and its
components.


1. Installing libdmtx on Mac OS X
-----------------------------------------------------------------

libdmtx can be installed on OS X using the instructions provided
in the general README file. However, please see below for
additional details that might benefit users on this platform.


2. Universal Binaries
-----------------------------------------------------------------

You can tweak configure's parameters to build an Universal Binary
version of the library. Recommendations are provided at:

  http://developer.apple.com/technotes/tn2005/tn2137.html


3. Dependencies
-----------------------------------------------------------------

Compiling from Git requires a working autoconf/pkg-config setup:

  * autoconf, automake, libtool, and pkgconfig are required to
    generate the configure script. These packages are available
    from MacPorts.

  * You may run into issues if you mix the autotools packages in
    MacPorts with the ones installed from Xcode Tools. Make sure
    /opt/local/bin appears before /usr/bin in your $PATH.


4. This Document
-----------------------------------------------------------------

This document is derived from the wiki page located at:

  http://libdmtx.wikidot.com/libdmtx-on-mac-os-x

If you find an error or have additional helpful information,
please edit the wiki directly with your updates.
Added jni/libdmtx/README.unix.




























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
=================================================================
            libdmtx - Open Source Data Matrix Software
=================================================================

                   libdmtx README file (Unix)

This README.unix file contains information on installing and
using libdmtx on Unix. The general README file, also found in
this directory, contains a high level summary of libdmtx and its
components.


1. Installing libdmtx on Unix
-----------------------------------------------------------------

libdmtx can be installed on Unix using the instructions provided
in the general README file. However, please see below for
additional details that might benefit users on this platform.


2. Known Issues
-----------------------------------------------------------------

libdmtx is known to work on the following commercial Unix
versions:

   * AIX
   * HP-UX
   * Solaris

However, building libdmtx from source on these operating systems
can be tricky due to their non-GNU conventions. Users may wish to
evaluate the trial binaries available at:

  http://www.dragonflylogic.com/downloads


3. This Document
-----------------------------------------------------------------

This document is derived from the wiki page located at:

  http://libdmtx.wikidot.com/libdmtx-on-unix

If you find an error or have additional helpful information,
please edit the wiki directly with your updates.
Added jni/libdmtx/TODO.












































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
TODO
-----------------------------------------------------------------

version 1.0.0: (planned TBD)
FOCUS: remaining gaps, testing, documentation
  o decoder: Investigate using MMX to optimize inner loops
  o decoder: Investigate using threads to split up image processing
  o testing: Generate metrics in reproducible format to enable historical tracking
  o testing: Investigate option of embedding decoded text into PNG test image comments
  o testing: Tests should compare scanned results to embedded PNG comments
  o testing: 'make test' writes metrics file
  o testing: 'make test' confirms performance

version 0.9.0: (planned TBD)
FOCUS: multiple barcode scanning, structured append, FNC1, macros
  o Implement --auto-fast option using algorithm from spec (lighter & faster?)
  o Structured append reading and writing
  o (test suite) Implement exhaustive comparison between --auto-fast and --auto-best
  o Implement consistent and robust error handling (errno.h + custom)
  o Implement structured append symbols
  o Image quality metric
  o Clean up source file permissions (write script to detect outliers?)

version 0.8.0: (planned TBD)
FOCUS: region detection
  o Use calibration edge alignment to set precise locs for all edges
  o Replace DmtxDirection (e.g., DmtxDirUp) with index range 0-7 (?)
  o Rename outputIdx to outputLength? (Count pad codewords instead of pointer)
  o Rename math types to drop unnecessary numeral (DmtxVector2, DmtxRay2, etc...)
  o Inspect SDL image packing naming conventions (stride vs. pad, etc...)
  o Clean up API for use with external ROI finders
  o Is there a good way to know if dmtxRegionFindNext() timed out or finished file?
  o testing: Test error corrections with controled damage to images
  o library: Add .gitignore for generated files
  o library: Add explicit build targets for debug and release
  o library: Library should never call exit() or assert()
  x encoder: Fixed Data Mosaic encoding bug

version 0.7.4: (02-Jun-2011)
  x library: Relicensed to use Simplified BSD with waiver option
  x library: Added new error codes and messages in dmtxencode.c
  x library: Added DmtxByteList struct and supporting functions
  x library: Changed file header with updated text
  x library: Fixed ECC bug for 144x144 case (thanks Huver!)
  x library: New Reed Solomon implementation
  x library: New repository structure: libdmtx, dmtx-utils, and dmtx-wrappers
  x testing: Added test in compare_generated.sh to create directory if needed
  x testing: Fix compare_generated.sh to prevent false negatives
  x encoder: Review CHK macro strategy
  x encoder: New encoding implementation
  x encoder: Added Base 256 "encode to end of symbol" single byte header
  x encoder: Check ProcessEndOfSymbolTriplet() for same problem fixed in Edifact
  x encoder: Clean up PushCTXValues() passFail handling
  x encoder: Fixed all encoding bugs reported by compare_generated.sh
  x encoder: Fixed encoding bug affecting certain end-of-symbol conditions
  x encoder: Replaced "twothirdsbits" encoder concept (major source of headaches)
  x encoder: Track intermediate states in "optimize best" to handle all possibilities
  x decoder: Use new Edifact decode function that doesn't assume full triplet

version 0.7.2: (04-Sep-2009)
  x Added initial macro decoding support (thanks Marlon!)
  x Fast quad fill for dmtxDecodeMatrixRegion() (thanks Mackenzie!)
  x Fixed capacity bug with rectangle requests
  x Add libdmtx-X.X.X.zip as source package option
  x Add libdmtx-win32-X.X.X.zip as binary package option
  x Add "project" directory to EXTRA_DIST in Makefile.am

version 0.7.0: (02-Mar-2009)
  x Fix 64b->32b int assignment warnings
  x FNC1 and correct upper shift (thanks Robin!)
  x Support byte-padded row sizes via dmtxImageSetProp()
  x Move image scaling factors to DmtxDecode
  x Add DmtxUndefined to replace "-1" for undefined fixes, offset, etc...
  x Update dmtxImageCreate() parameter options
  x Switch DmtxFlipNone represent top-down row order
  x Add dmtxEncodeSetProp() and dmtxEncodeGetProp()
  x Relocate scan cache from DmtxImage to DmtxDecode
  x Remove status from DmtxPixelLoc
  x Configurable pixel packing
  x Removed DmtxRgb, dmtxcolor.c, DmtxColor3, and DmtxGradient
  x DmtxTrue/DmtxFalse replaces DMTX_TRUE/DMTX_FALSE
  x DmtxPass/DmtxFail replaces DMTX_SUCCESS/DMTX_FAILURE
  x Change all major types to use Create() and Destroy() convention
  x Update documentation to reflect API changes
  x Add comment to wiki pages that points to source README
  x Figure out earliest usable Magick version for configure.ac
  x Add simple_test project to libdmtx.sln
  x Rename wiki page to "Windows (VisualC)"
  x Introduce "project" directory for non-autotools platforms
  x Rename "wrappers" directory to "wrapper" for consistency
  x Create a common tasks and release checklist document

version 0.6.0: (23-Nov-2008)
  x Initial work preparing for custom pixel packing in future
  x Begin static analysis cleanup with splint
  x New --disable-dmtxread and --disable-dmtxwrite [Romain]
  x Ability to specify max/min expected barcode sizes
  x New edge neighbor tracking (Hough Transform + 2 way edge cache)
  x Info cache to track scan progress and avoid rescanning pixels
  x Scan multiple barcodes within an image
  x Significantly reduced memory footprint
  x Major reduction in floating point operations
  x Dedicated README.xxx instructions for specific platforms
  x Various improvements for cross platform builds

version 0.5.2: (04-Sep-2008)
  x Move SetRangeLimit and SetScanRegion into library
  x Replace DMTXUTIL_SUCCESS/ERROR with DMTX_SUCCESS/FAILURE
  x Add edge threshold filtering
  x Add encoding support for 144x144 barcodes
  x Fixed encoding case when message starts with two digits
  x Fixed bug in range limit option
  x Add dynamic image shrinking (pixel skipping)
  x Add step-by-step diagnostic image dump (debug build)
  x Fixed bug in minimum scan gap setting
  x Removed y-flip from internal pixel storage
  x Added strict border tests to eliminate false positives
  x Added squareness deviation filter
  x Implement simplified Hough transform for locating first edge
  x Several behind-the-scenes performance enhancements
  x Various improvements when building for OS X and FreeBSD

version 0.5.1: (01-Jul-2008)
  x Fixed Extended ASCII encoding bug
  x Fixed error correction bug related to multiple interleaved blocks
  x Added timeout condition for region detection
  x Allow partial and complete disabling of error correction
  x Replaced DmtxPixel struct with DmtxRgb for safe pixel copies
  x Tighter integration with libfec
  x (test suite) Started unit test executable for low level testing
  x Include local copies of getopt1.c getopt.c getopt.h
  x Various things to help compiling in MS VC++
  x Added missing header comments

version 0.5: (13-Apr-2008)
  x Rework encoding and decoding API for consistency and intuitiveness
  x Handle region detection and region decoding as separate tasks
  x Pass found regions back to calling app before attempting decode
  x Image mask approach (for performance and multi-barcode scans)
  x Remove "2" from functions named *MatrixRegion2*() (whoops)
  x Fix TestForEndOfSymbolEdifact() to handle special cases correctly
  x Roll scan pattern into core library (inward breadth-first cross)
  x Replace dmtxScanLine() with dmtxScanPixel()
  x Implement 4-direction weighted module decisions (eliminates thresholds)
  x Error correction using libfec (thanks Florian!)
  x Remove gltest and simpletest from default build target
  x Update Subversion to be keyword friendly ($Id$)
  x Updated documentation to reflect API and option changes
  x (test suite) Moved all public images to common directory with single copyright file

version 0.4: (07-Dec-2008)
  x Remove arbitrary sz scaling (100.0) since it doesn't matter anyway
  x Fix 4 bottom-right modules in sizes where they are not used (thanks Matthias R.!)
  x Replace callback references with preprocessor macros
  x Implement remaining encodation schemes for encoding (X12, Base 256, etc...)
  x Implement remaining encodation schemes for decoding (X12, Base 256, etc...)
  x Implement --auto-best option for best possible encoding efficiency
  x Implement multi-region symbols
  x Read and write rectangle shaped barcodes
  x Use GNU autotools (autoconf, automake, libtool)
  x New region detection overhaul
  x Fix chcon error in Makefile (right answer might be to use autoconf)
  x (test suite) 'make test' executes regression tests for encodation
  x (test suite) Add marathon images to project (thanks John!)

version 0.3: (15-Oct-2006)
  x Use preprocessor to pull code into one big file before compiling
  x Update Makefile to handle monolithic approach; add targets for test, util, tarball
  x Rename DmtxInfo struct and variables to DmtxDecode (for consistency with DmtxEncode)
  x Merge placement logic into single implementation for both encoding and decoding
  x Deploy codebase to SourceForge CVS
  x Add revision control keywords to source files
  x Implement remaining encodation schemes in dmtxdecode.c (X12, Base 256, etc...)
  x Create separate file for callback functions (allows them to be optional)
  x Move PNG (and other format) logic and dependencies to dmtxread, dmtxwrite, etc...
  x Fix the regressions (crash bugs) introduced during v0.2 structural rework
  x Add multi-page TIFF capabilities to dmtxread
  x Move pure decode calls from dmtxScanLine into a dmtxdecode.c function
  x Sample module color from more than one pixel location
  x Rename DmtxVector3 to DmtxColor3 and merge into dmtxcolor.c
  x Add package/build dependencies to INSTALL file
  x Build coding style test scripts
  x Replace current calibration size estimate with new approach
  x Size step size dynamically according to pixel size

version 0.2: (11-Jun-2006)
  x Move dmtxCapturePixel routine to library code
  x Initial restructuring of code for architectural goodness
  x Improve API for real-world use (and not just dumping results to STDOUT)
  x Implement error detection
  x Create "simpletest.c" for full-circle processing
  x Use libpng(3) in library to read Data Matrix images
  x Slap together some basic documentation

version 0.1: (22-Apr-2006)
  x Cycle texture images with right-click
  x Complete PlotPoint so it handles floating rows and columns
  x Implement right and left directions of FollowEdge
  x Call right and left edge following scans started from vertical step scans
  x Implement 2D vector and matrix functions
  x Trace lines with actual line object (2D ray)
  x Turn corners when encountering the end of a followed line
  x Build 2d transformation to wrap around region, assuming parallelogram
  x Display pane 4 with reverse-transformed image capture
  x Enhance dmtxCapturePixel to use "area averaging" instead of nearest neighbor
  x Figure out why squares are 3 pixels off (to start: draw white gl lines over follower paths)
  x Add callback function for PlotEventPoint(x, y, event_type)
  x Improve follower logic (weighted line fit)
  x dmtxGetPixel: do averaged interpolation followed by a tMin/tMid/tMax cutoff
  x Add in de-skew transformation
  x Refactor vector libraries to consistently list target parameter first
  x Calibrate based on calibration lines
  x Shrink-fit transformation around region

Future Versions:
-----------------------------------------------------------------
  o Capture high-level design in documentation (data flow, module analogies)
  o Try bi-linear approximation (instead of linear) in follower edge detection
  o Implement fixed point math functions for use on mobile platforms
  o Add calibration functionality to remove spherical distortion

Perhaps Never:
-----------------------------------------------------------------
  o Implement pre-ECC200 Data Matrix standards (big effort/low demand)

Website:
-----------------------------------------------------------------
  o Explore using single background image instead of split
  o Add what we currently do, don't do, would like to do in the future
  o Add http://hosted-projects.com/trac/hudora/public/wiki/huBarcode to resources page
Added jni/libdmtx/autogen.sh.




















>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
#!/bin/sh

# Create empty m4 directory if missing
if [[ ! -d "m4" ]]; then
   echo "autogen.sh: creating empty m4 directory"
   mkdir m4
fi

echo "autogen.sh: running autoreconf"
autoreconf --force --install
Added jni/libdmtx/configure.ac.












































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
AC_INIT([libdmtx], [0.7.5], [mike@dragonflylogic.com])
AM_INIT_AUTOMAKE([-Wall -Werror])

AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
   Makefile
   libdmtx.pc
   test/Makefile
   test/simple_test/Makefile
])

AC_PROG_CC
AC_PROG_LIBTOOL
AM_PROG_CC_C_O

AC_SEARCH_LIBS([sin], [m] ,[], AC_MSG_ERROR([libdmtx requires libm]))
AC_SEARCH_LIBS([cos], [m] ,[], AC_MSG_ERROR([libdmtx requires libm]))
AC_SEARCH_LIBS([atan2], [m] ,[], AC_MSG_ERROR([libdmtx requires libm]))

AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_FUNCS([gettimeofday])

case $target_os in
   cygwin*)
      ARCH=cygwin ;;
   darwin*)
      ARCH=macosx ;;
   freebsd*)
      ARCH=freebsd ;;
   linux-gnu*)
      ARCH=linux-gnu ;;
   mingw32*)
      ARCH=mingw32 ;;
esac
AM_CONDITIONAL([TARGET_MACOSX], [test x$ARCH = xmacosx])

AC_OUTPUT
Added jni/libdmtx/dmtx.c.
















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtx.c
 * \brief Main libdmtx source file
 */

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <ctype.h>
#include <limits.h>
#include <float.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <math.h>
#include "dmtx.h"
#include "dmtxstatic.h"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifndef CALLBACK_POINT_PLOT
#define CALLBACK_POINT_PLOT(a,b,c,d)
#endif

#ifndef CALLBACK_POINT_XFRM
#define CALLBACK_POINT_XFRM(a,b,c,d)
#endif

#ifndef CALLBACK_MODULE
#define CALLBACK_MODULE(a,b,c,d,e)
#endif

#ifndef CALLBACK_MATRIX
#define CALLBACK_MATRIX(a)
#endif

#ifndef CALLBACK_FINAL
#define CALLBACK_FINAL(a,b)
#endif

/**
 * Use #include to merge the individual .c source files into a single combined
 * file during preprocessing. This allows the project to be organized in files
 * of like-functionality while still keeping a clean namespace. Specifically,
 * internal functions can be static without losing the ability to access them
 * "externally" from the other source files in this list.
 */

#include "dmtxencode.c"
#include "dmtxencodestream.c"
#include "dmtxencodescheme.c"
#include "dmtxencodeoptimize.c"
#include "dmtxencodeascii.c"
#include "dmtxencodec40textx12.c"
#include "dmtxencodeedifact.c"
#include "dmtxencodebase256.c"

#include "dmtxdecode.c"
#include "dmtxdecodescheme.c"

#include "dmtxmessage.c"
#include "dmtxregion.c"
#include "dmtxsymbol.c"
#include "dmtxplacemod.c"
#include "dmtxreedsol.c"
#include "dmtxscangrid.c"

#include "dmtximage.c"
#include "dmtxbytelist.c"
#include "dmtxtime.c"
#include "dmtxvector2.c"
#include "dmtxmatrix3.c"

extern char *
dmtxVersion(void)
{
   return DmtxVersion;
}
Added jni/libdmtx/dmtx.h.


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtx.h
 * \brief Main libdmtx header
 */

#ifndef __DMTX_H__
#define __DMTX_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Time headers required for DmtxTime struct below */
#include <time.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif

#ifndef M_PI
#define M_PI      3.14159265358979323846
#endif

#ifndef M_PI_2
#define M_PI_2    1.57079632679489661923
#endif

#define DmtxVersion              "0.7.5"

#define DmtxUndefined                 -1

#define DmtxPassFail        unsigned int
#define DmtxPass                       1
#define DmtxFail                       0

#define DmtxBoolean         unsigned int
#define DmtxTrue                       1
#define DmtxFalse                      0

#define DmtxFormatMatrix               0
#define DmtxFormatMosaic               1

#define DmtxSymbolSquareCount         24
#define DmtxSymbolRectCount            6

#define DmtxModuleOff               0x00
#define DmtxModuleOnRed             0x01
#define DmtxModuleOnGreen           0x02
#define DmtxModuleOnBlue            0x04
#define DmtxModuleOnRGB             0x07  /* OnRed | OnGreen | OnBlue */
#define DmtxModuleOn                0x07
#define DmtxModuleUnsure            0x08
#define DmtxModuleAssigned          0x10
#define DmtxModuleVisited           0x20
#define DmtxModuleData              0x40

#define DMTX_CHECK_BOUNDS(l,i) (assert((i) >= 0 && (i) < (l)->length && (l)->length <= (l)->capacity))

typedef enum {
   DmtxStatusEncoding, /* Encoding is currently underway */
   DmtxStatusComplete, /* Encoding is done and everything went well */
   DmtxStatusInvalid,  /* Something bad happened that sometimes happens */
   DmtxStatusFatal     /* Something happened that should never happen */
} DmtxStatus;

typedef enum {
   DmtxSchemeAutoFast        = -2,
   DmtxSchemeAutoBest        = -1,
   DmtxSchemeAscii           =  0,
   DmtxSchemeC40,
   DmtxSchemeText,
   DmtxSchemeX12,
   DmtxSchemeEdifact,
   DmtxSchemeBase256
} DmtxScheme;

typedef enum {
   DmtxSymbolRectAuto        = -3,
   DmtxSymbolSquareAuto      = -2,
   DmtxSymbolShapeAuto       = -1,
   DmtxSymbol10x10           =  0,
   DmtxSymbol12x12,
   DmtxSymbol14x14,
   DmtxSymbol16x16,
   DmtxSymbol18x18,
   DmtxSymbol20x20,
   DmtxSymbol22x22,
   DmtxSymbol24x24,
   DmtxSymbol26x26,
   DmtxSymbol32x32,
   DmtxSymbol36x36,
   DmtxSymbol40x40,
   DmtxSymbol44x44,
   DmtxSymbol48x48,
   DmtxSymbol52x52,
   DmtxSymbol64x64,
   DmtxSymbol72x72,
   DmtxSymbol80x80,
   DmtxSymbol88x88,
   DmtxSymbol96x96,
   DmtxSymbol104x104,
   DmtxSymbol120x120,
   DmtxSymbol132x132,
   DmtxSymbol144x144,
   DmtxSymbol8x18,
   DmtxSymbol8x32,
   DmtxSymbol12x26,
   DmtxSymbol12x36,
   DmtxSymbol16x36,
   DmtxSymbol16x48
} DmtxSymbolSize;

typedef enum {
   DmtxDirNone               = 0x00,
   DmtxDirUp                 = 0x01 << 0,
   DmtxDirLeft               = 0x01 << 1,
   DmtxDirDown               = 0x01 << 2,
   DmtxDirRight              = 0x01 << 3,
   DmtxDirHorizontal         = DmtxDirLeft  | DmtxDirRight,
   DmtxDirVertical           = DmtxDirUp    | DmtxDirDown,
   DmtxDirRightUp            = DmtxDirRight | DmtxDirUp,
   DmtxDirLeftDown           = DmtxDirLeft  | DmtxDirDown
} DmtxDirection;

typedef enum {
   DmtxSymAttribSymbolRows,
   DmtxSymAttribSymbolCols,
   DmtxSymAttribDataRegionRows,
   DmtxSymAttribDataRegionCols,
   DmtxSymAttribHorizDataRegions,
   DmtxSymAttribVertDataRegions,
   DmtxSymAttribMappingMatrixRows,
   DmtxSymAttribMappingMatrixCols,
   DmtxSymAttribInterleavedBlocks,
   DmtxSymAttribBlockErrorWords,
   DmtxSymAttribBlockMaxCorrectable,
   DmtxSymAttribSymbolDataWords,
   DmtxSymAttribSymbolErrorWords,
   DmtxSymAttribSymbolMaxCorrectable
} DmtxSymAttribute;

typedef enum {
   DmtxCorner00              = 0x01 << 0,
   DmtxCorner10              = 0x01 << 1,
   DmtxCorner11              = 0x01 << 2,
   DmtxCorner01              = 0x01 << 3
} DmtxCornerLoc;

typedef enum {
   /* Encoding properties */
   DmtxPropScheme            = 100,
   DmtxPropSizeRequest,
   DmtxPropMarginSize,
   DmtxPropModuleSize,
   /* Decoding properties */
   DmtxPropEdgeMin           = 200,
   DmtxPropEdgeMax,
   DmtxPropScanGap,
   DmtxPropSquareDevn,
   DmtxPropSymbolSize,
   DmtxPropEdgeThresh,
   /* Image properties */
   DmtxPropWidth             = 300,
   DmtxPropHeight,
   DmtxPropPixelPacking,
   DmtxPropBitsPerPixel,
   DmtxPropBytesPerPixel,
   DmtxPropRowPadBytes,
   DmtxPropRowSizeBytes,
   DmtxPropImageFlip,
   DmtxPropChannelCount,
   /* Image modifiers */
   DmtxPropXmin              = 400,
   DmtxPropXmax,
   DmtxPropYmin,
   DmtxPropYmax,
   DmtxPropScale
} DmtxProperty;

typedef enum {
   /* Custom format */
   DmtxPackCustom            = 100,
   /* 1 bpp */
   DmtxPack1bppK             = 200,
   /* 8 bpp grayscale */
   DmtxPack8bppK             = 300,
   /* 16 bpp formats */
   DmtxPack16bppRGB          = 400,
   DmtxPack16bppRGBX,
   DmtxPack16bppXRGB,
   DmtxPack16bppBGR,
   DmtxPack16bppBGRX,
   DmtxPack16bppXBGR,
   DmtxPack16bppYCbCr,
   /* 24 bpp formats */
   DmtxPack24bppRGB          = 500,
   DmtxPack24bppBGR,
   DmtxPack24bppYCbCr,
   /* 32 bpp formats */
   DmtxPack32bppRGBX         = 600,
   DmtxPack32bppXRGB,
   DmtxPack32bppBGRX,
   DmtxPack32bppXBGR,
   DmtxPack32bppCMYK
} DmtxPackOrder;

typedef enum {
  DmtxFlipNone               = 0x00,
  DmtxFlipX                  = 0x01 << 0,
  DmtxFlipY                  = 0x01 << 1
} DmtxFlip;

typedef double DmtxMatrix3[3][3];

/**
 * @struct DmtxPixelLoc
 * @brief DmtxPixelLoc
 */
typedef struct DmtxPixelLoc_struct {
   int X;
   int Y;
} DmtxPixelLoc;

/**
 * @struct DmtxVector2
 * @brief DmtxVector2
 */
typedef struct DmtxVector2_struct {
   double          X;
   double          Y;
} DmtxVector2;

/**
 * @struct DmtxRay2
 * @brief DmtxRay2
 */
typedef struct DmtxRay2_struct {
   double          tMin;
   double          tMax;
   DmtxVector2     p;
   DmtxVector2     v;
} DmtxRay2;

typedef unsigned char DmtxByte;

/**
 * @struct DmtxByteList
 * @brief DmtxByteList
 * Use signed int for length fields instead of size_t to play nicely with RS
 * arithmetic
 */
typedef struct DmtxByteList_struct DmtxByteList;
struct DmtxByteList_struct
{
   int length;
   int capacity;
   DmtxByte *b;
};

typedef struct DmtxEncodeStream_struct DmtxEncodeStream;
struct DmtxEncodeStream_struct
{
   int currentScheme;         /* Current encodation scheme */
   int inputNext;             /* Index of next unprocessed input word in queue */
   int outputChainValueCount; /* Count of output values pushed within current scheme chain */
   int outputChainWordCount;  /* Count of output words pushed within current scheme chain */
   char *reason;              /* Reason for status */
   int sizeIdx;               /* Symbol size of completed stream */
   DmtxStatus status;
   DmtxByteList *input;
   DmtxByteList *output;
};

/**
 * @struct DmtxImage
 * @brief DmtxImage
 */
typedef struct DmtxImage_struct {
   int             width;
   int             height;
   int             pixelPacking;
   int             bitsPerPixel;
   int             bytesPerPixel;
   int             rowPadBytes;
   int             rowSizeBytes;
   int             imageFlip;
   int             channelCount;
   int             channelStart[4];
   int             bitsPerChannel[4];
   unsigned char  *pxl;
} DmtxImage;

/**
 * @struct DmtxPointFlow
 * @brief DmtxPointFlow
 */
typedef struct DmtxPointFlow_struct {
   int             plane;
   int             arrive;
   int             depart;
   int             mag;
   DmtxPixelLoc    loc;
} DmtxPointFlow;

/**
 * @struct DmtxBestLine
 * @brief DmtxBestLine
 */
typedef struct DmtxBestLine_struct {
   int             angle;
   int             hOffset;
   int             mag;
   int             stepBeg;
   int             stepPos;
   int             stepNeg;
   int             distSq;
   double          devn;
   DmtxPixelLoc    locBeg;
   DmtxPixelLoc    locPos;
   DmtxPixelLoc    locNeg;
} DmtxBestLine;

/**
 * @struct DmtxRegion
 * @brief DmtxRegion
 */
typedef struct DmtxRegion_struct {

   /* Trail blazing values */
   int             jumpToPos;     /* */
   int             jumpToNeg;     /* */
   int             stepsTotal;    /* */
   DmtxPixelLoc    finalPos;      /* */
   DmtxPixelLoc    finalNeg;      /* */
   DmtxPixelLoc    boundMin;      /* */
   DmtxPixelLoc    boundMax;      /* */
   DmtxPointFlow   flowBegin;     /* */

   /* Orientation values */
   int             polarity;      /* */
   int             stepR;
   int             stepT;
   DmtxPixelLoc    locR;          /* remove if stepR works above */
   DmtxPixelLoc    locT;          /* remove if stepT works above */

   /* Region fitting values */
   int             leftKnown;     /* known == 1; unknown == 0 */
   int             leftAngle;     /* hough angle of left edge */
   DmtxPixelLoc    leftLoc;       /* known (arbitrary) location on left edge */
   DmtxBestLine    leftLine;      /* */
   int             bottomKnown;   /* known == 1; unknown == 0 */
   int             bottomAngle;   /* hough angle of bottom edge */
   DmtxPixelLoc    bottomLoc;     /* known (arbitrary) location on bottom edge */
   DmtxBestLine    bottomLine;    /* */
   int             topKnown;      /* known == 1; unknown == 0 */
   int             topAngle;      /* hough angle of top edge */
   DmtxPixelLoc    topLoc;        /* known (arbitrary) location on top edge */
   int             rightKnown;    /* known == 1; unknown == 0 */
   int             rightAngle;    /* hough angle of right edge */
   DmtxPixelLoc    rightLoc;      /* known (arbitrary) location on right edge */

   /* Region calibration values */
   int             onColor;       /* */
   int             offColor;      /* */
   int             sizeIdx;       /* Index of arrays that store Data Matrix constants */
   int             symbolRows;    /* Number of total rows in symbol including alignment patterns */
   int             symbolCols;    /* Number of total columns in symbol including alignment patterns */
   int             mappingRows;   /* Number of data rows in symbol */
   int             mappingCols;   /* Number of data columns in symbol */

   /* Transform values */
   DmtxMatrix3     raw2fit;       /* 3x3 transformation from raw image to fitted barcode grid */
   DmtxMatrix3     fit2raw;       /* 3x3 transformation from fitted barcode grid to raw image */
} DmtxRegion;

/**
 * @struct DmtxMessage
 * @brief DmtxMessage
 */
typedef struct DmtxMessage_struct {
   size_t          arraySize;     /* mappingRows * mappingCols */
   size_t          codeSize;      /* Size of encoded data (data words + error words) */
   size_t          outputSize;    /* Size of buffer used to hold decoded data */
   int             outputIdx;     /* Internal index used to store output progress */
   int             padCount;
   unsigned char  *array;         /* Pointer to internal representation of Data Matrix modules */
   unsigned char  *code;          /* Pointer to internal storage of code words (data and error) */
   unsigned char  *output;        /* Pointer to internal storage of decoded output */
} DmtxMessage;

/**
 * @struct DmtxScanGrid
 * @brief DmtxScanGrid
 */
typedef struct DmtxScanGrid_struct {
   /* set once */
   int             minExtent;     /* Smallest cross size used in scan */
   int             maxExtent;     /* Size of bounding grid region (2^N - 1) */
   int             xOffset;       /* Offset to obtain image X coordinate */
   int             yOffset;       /* Offset to obtain image Y coordinate */
   int             xMin;          /* Minimum X in image coordinate system */
   int             xMax;          /* Maximum X in image coordinate system */
   int             yMin;          /* Minimum Y in image coordinate system */
   int             yMax;          /* Maximum Y in image coordinate system */

   /* reset for each level */
   int             total;         /* Total number of crosses at this size */
   int             extent;        /* Length/width of cross in pixels */
   int             jumpSize;      /* Distance in pixels between cross centers */
   int             pixelTotal;    /* Total pixel count within an individual cross path */
   int             startPos;      /* X and Y coordinate of first cross center in pattern */

   /* reset for each cross */
   int             pixelCount;    /* Progress (pixel count) within current cross pattern */
   int             xCenter;       /* X center of current cross pattern */
   int             yCenter;       /* Y center of current cross pattern */
} DmtxScanGrid;

/**
 * @struct DmtxTime
 * @brief DmtxTime
 */
typedef struct DmtxTime_struct {
   time_t          sec;
   unsigned long   usec;
} DmtxTime;

/**
 * @struct DmtxDecode
 * @brief DmtxDecode
 */
typedef struct DmtxDecode_struct {
   /* Options */
   int             edgeMin;
   int             edgeMax;
   int             scanGap;
   double          squareDevn;
   int             sizeIdxExpected;
   int             edgeThresh;

   /* Image modifiers */
   int             xMin;
   int             xMax;
   int             yMin;
   int             yMax;
   int             scale;

   /* Internals */
/* int             cacheComplete; */
   unsigned char  *cache;
   DmtxImage      *image;
   DmtxScanGrid    grid;
} DmtxDecode;

/**
 * @struct DmtxEncode
 * @brief DmtxEncode
 */
typedef struct DmtxEncode_struct {
   int             method;
   int             scheme;
   int             sizeIdxRequest;
   int             marginSize;
   int             moduleSize;
   int             pixelPacking;
   int             imageFlip;
   int             rowPadBytes;
   DmtxMessage    *message;
   DmtxImage      *image;
   DmtxRegion      region;
   DmtxMatrix3     xfrm;  /* XXX still necessary? */
   DmtxMatrix3     rxfrm; /* XXX still necessary? */
} DmtxEncode;

/**
 * @struct DmtxChannel
 * @brief DmtxChannel
 */
typedef struct DmtxChannel_struct {
   int             encScheme;     /* current encodation scheme */
   int             invalid;       /* channel status (invalid if non-zero) */
   unsigned char  *inputPtr;      /* pointer to current input character */
   unsigned char  *inputStop;     /* pointer to position after final input character */
   int             encodedLength; /* encoded length (units of 2/3 bits) */
   int             currentLength; /* current length (units of 2/3 bits) */
   int             firstCodeWord; /* */
   unsigned char   encodedWords[1558];
} DmtxChannel;

/* Wrap in a struct for fast copies */
/**
 * @struct DmtxChannelGroup
 * @brief DmtxChannelGroup
 */
typedef struct DmtxChannelGroup_struct {
   DmtxChannel channel[6];
} DmtxChannelGroup;

/**
 * @struct DmtxTriplet
 * @brief DmtxTriplet
 */
typedef struct DmtxTriplet_struct {
   unsigned char   value[3];
} DmtxTriplet;

/**
 * @struct DmtxQuadruplet
 * @brief DmtxQuadruplet
 */
typedef struct DmtxQuadruplet_struct {
   unsigned char   value[4];
} DmtxQuadruplet;

/* dmtxtime.c */
extern DmtxTime dmtxTimeNow(void);
extern DmtxTime dmtxTimeAdd(DmtxTime t, long msec);
extern int dmtxTimeExceeded(DmtxTime timeout);

/* dmtxencode.c */
extern DmtxEncode *dmtxEncodeCreate(void);
extern DmtxPassFail dmtxEncodeDestroy(DmtxEncode **enc);
extern DmtxPassFail dmtxEncodeSetProp(DmtxEncode *enc, int prop, int value);
extern int dmtxEncodeGetProp(DmtxEncode *enc, int prop);
extern DmtxPassFail dmtxEncodeDataMatrix(DmtxEncode *enc, int n, unsigned char *s);
extern DmtxPassFail dmtxEncodeDataMosaic(DmtxEncode *enc, int n, unsigned char *s);

/* dmtxdecode.c */
extern DmtxDecode *dmtxDecodeCreate(DmtxImage *img, int scale);
extern DmtxPassFail dmtxDecodeDestroy(DmtxDecode **dec);
extern DmtxPassFail dmtxDecodeSetProp(DmtxDecode *dec, int prop, int value);
extern int dmtxDecodeGetProp(DmtxDecode *dec, int prop);
extern /*@exposed@*/ unsigned char *dmtxDecodeGetCache(DmtxDecode *dec, int x, int y);
extern DmtxPassFail dmtxDecodeGetPixelValue(DmtxDecode *dec, int x, int y, int channel, /*@out@*/ int *value);
extern DmtxMessage *dmtxDecodeMatrixRegion(DmtxDecode *dec, DmtxRegion *reg, int fix);
extern DmtxMessage *dmtxDecodeMosaicRegion(DmtxDecode *dec, DmtxRegion *reg, int fix);
extern unsigned char *dmtxDecodeCreateDiagnostic(DmtxDecode *dec, /*@out@*/ int *totalBytes, /*@out@*/ int *headerBytes, int style);

/* dmtxregion.c */
extern DmtxRegion *dmtxRegionCreate(DmtxRegion *reg);
extern DmtxPassFail dmtxRegionDestroy(DmtxRegion **reg);
extern DmtxRegion *dmtxRegionFindNext(DmtxDecode *dec, DmtxTime *timeout);
extern DmtxRegion *dmtxRegionScanPixel(DmtxDecode *dec, int x, int y);
extern DmtxPassFail dmtxRegionUpdateCorners(DmtxDecode *dec, DmtxRegion *reg, DmtxVector2 p00,
      DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01);
extern DmtxPassFail dmtxRegionUpdateXfrms(DmtxDecode *dec, DmtxRegion *reg);

/* dmtxmessage.c */
extern DmtxMessage *dmtxMessageCreate(int sizeIdx, int symbolFormat);
extern DmtxPassFail dmtxMessageDestroy(DmtxMessage **msg);

/* dmtximage.c */
extern DmtxImage *dmtxImageCreate(unsigned char *pxl, int width, int height, int pack);
extern DmtxPassFail dmtxImageDestroy(DmtxImage **img);
extern DmtxPassFail dmtxImageSetChannel(DmtxImage *img, int channelStart, int bitsPerChannel);
extern DmtxPassFail dmtxImageSetProp(DmtxImage *img, int prop, int value);
extern int dmtxImageGetProp(DmtxImage *img, int prop);
extern int dmtxImageGetByteOffset(DmtxImage *img, int x, int y);
extern DmtxPassFail dmtxImageGetPixelValue(DmtxImage *img, int x, int y, int channel, /*@out@*/ int *value);
extern DmtxPassFail dmtxImageSetPixelValue(DmtxImage *img, int x, int y, int channel, int value);
extern DmtxBoolean dmtxImageContainsInt(DmtxImage *img, int margin, int x, int y);
extern DmtxBoolean dmtxImageContainsFloat(DmtxImage *img, double x, double y);

/* dmtxvector2.c */
extern DmtxVector2 *dmtxVector2AddTo(DmtxVector2 *v1, const DmtxVector2 *v2);
extern DmtxVector2 *dmtxVector2Add(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2);
extern DmtxVector2 *dmtxVector2SubFrom(DmtxVector2 *v1, const DmtxVector2 *v2);
extern DmtxVector2 *dmtxVector2Sub(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2);
extern DmtxVector2 *dmtxVector2ScaleBy(DmtxVector2 *v, double s);
extern DmtxVector2 *dmtxVector2Scale(/*@out@*/ DmtxVector2 *vOut, const DmtxVector2 *v, double s);
extern double dmtxVector2Cross(const DmtxVector2 *v1, const DmtxVector2 *v2);
extern double dmtxVector2Norm(DmtxVector2 *v);
extern double dmtxVector2Dot(const DmtxVector2 *v1, const DmtxVector2 *v2);
extern double dmtxVector2Mag(const DmtxVector2 *v);
extern double dmtxDistanceFromRay2(const DmtxRay2 *r, const DmtxVector2 *q);
extern double dmtxDistanceAlongRay2(const DmtxRay2 *r, const DmtxVector2 *q);
extern DmtxPassFail dmtxRay2Intersect(/*@out@*/ DmtxVector2 *point, const DmtxRay2 *p0, const DmtxRay2 *p1);
extern DmtxPassFail dmtxPointAlongRay2(/*@out@*/ DmtxVector2 *point, const DmtxRay2 *r, double t);

/* dmtxmatrix3.c */
extern void dmtxMatrix3Copy(/*@out@*/ DmtxMatrix3 m0, DmtxMatrix3 m1);
extern void dmtxMatrix3Identity(/*@out@*/ DmtxMatrix3 m);
extern void dmtxMatrix3Translate(/*@out@*/ DmtxMatrix3 m, double tx, double ty);
extern void dmtxMatrix3Rotate(/*@out@*/ DmtxMatrix3 m, double angle);
extern void dmtxMatrix3Scale(/*@out@*/ DmtxMatrix3 m, double sx, double sy);
extern void dmtxMatrix3Shear(/*@out@*/ DmtxMatrix3 m, double shx, double shy);
extern void dmtxMatrix3LineSkewTop(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz);
extern void dmtxMatrix3LineSkewTopInv(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz);
extern void dmtxMatrix3LineSkewSide(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz);
extern void dmtxMatrix3LineSkewSideInv(/*@out@*/ DmtxMatrix3 m, double b0, double b1, double sz);
extern void dmtxMatrix3Multiply(/*@out@*/ DmtxMatrix3 mOut, DmtxMatrix3 m0, DmtxMatrix3 m1);
extern void dmtxMatrix3MultiplyBy(DmtxMatrix3 m0, DmtxMatrix3 m1);
extern int dmtxMatrix3VMultiply(/*@out@*/ DmtxVector2 *vOut, DmtxVector2 *vIn, DmtxMatrix3 m);
extern int dmtxMatrix3VMultiplyBy(DmtxVector2 *v, DmtxMatrix3 m);
extern void dmtxMatrix3Print(DmtxMatrix3 m);

/* dmtxsymbol.c */
extern int dmtxSymbolModuleStatus(DmtxMessage *mapping, int sizeIdx, int row, int col);
extern int dmtxGetSymbolAttribute(int attribute, int sizeIdx);
extern int dmtxGetBlockDataSize(int sizeIdx, int blockIdx);

/* dmtxbytelist.c */
extern DmtxByteList dmtxByteListBuild(DmtxByte *storage, int capacity);
extern void dmtxByteListInit(DmtxByteList *list, int length, DmtxByte value, DmtxPassFail *passFail);
extern void dmtxByteListClear(DmtxByteList *list);
extern DmtxBoolean dmtxByteListHasCapacity(DmtxByteList *list);
extern void dmtxByteListCopy(DmtxByteList *dst, const DmtxByteList *src, DmtxPassFail *passFail);
extern void dmtxByteListPush(DmtxByteList *list, DmtxByte value, DmtxPassFail *passFail);
extern DmtxByte dmtxByteListPop(DmtxByteList *list, DmtxPassFail *passFail);
extern void dmtxByteListPrint(DmtxByteList *list, char *prefix);

extern char *dmtxVersion(void);

#ifdef __cplusplus
}
#endif

#endif
Added jni/libdmtx/dmtxbytelist.c.






















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file file.c
 */

/**
 *
 *
 */
extern DmtxByteList
dmtxByteListBuild(DmtxByte *storage, int capacity)
{
   DmtxByteList list;

   list.b = storage;
   list.capacity = capacity;
   list.length = 0;

   return list;
}

/**
 *
 *
 */
extern void
dmtxByteListInit(DmtxByteList *list, int length, DmtxByte value, DmtxPassFail *passFail)
{
   if(length > list->capacity)
   {
      *passFail = DmtxFail;
   }
   else
   {
      list->length = length;
      memset(list->b, value, sizeof(DmtxByte) * list->capacity);
      *passFail = DmtxPass;
   }
}

/**
 *
 *
 */
extern void
dmtxByteListClear(DmtxByteList *list)
{
   memset(list->b, 0x00, sizeof(DmtxByte) * list->capacity);
   list->length = 0;
}

/**
 *
 *
 */
extern DmtxBoolean
dmtxByteListHasCapacity(DmtxByteList *list)
{
   return (list->length < list->capacity) ? DmtxTrue : DmtxFalse;
}

/**
 *
 *
 */
extern void
dmtxByteListCopy(DmtxByteList *dst, const DmtxByteList *src, DmtxPassFail *passFail)
{
   int length;

   if(dst->capacity < src->length)
   {
      *passFail = DmtxFail; /* dst must be large enough to hold src data */
   }
   else
   {
      /* Copy as many bytes as dst can hold or src can provide (smaller of two) */
      length = (dst->capacity < src->capacity) ? dst->capacity : src->capacity;

      dst->length = src->length;
      memcpy(dst->b, src->b, sizeof(unsigned char) * length);
      *passFail = DmtxPass;
   }
}

/**
 *
 *
 */
extern void
dmtxByteListPush(DmtxByteList *list, DmtxByte value, DmtxPassFail *passFail)
{
   if(list->length >= list->capacity)
   {
      *passFail = DmtxFail;
   }
   else
   {
      list->b[list->length++] = value;
      *passFail = DmtxPass;
   }
}

/**
 *
 *
 */
extern DmtxByte
dmtxByteListPop(DmtxByteList *list, DmtxPassFail *passFail)
{
   *passFail = (list->length > 0) ? DmtxPass : DmtxFail;

   return list->b[--(list->length)];
}

/**
 *
 *
 */
extern void
dmtxByteListPrint(DmtxByteList *list, char *prefix)
{
   int i;

   if(prefix != NULL)
      fprintf(stdout, "%s", prefix);

   for(i = 0; i < list->length; i++)
      fprintf(stdout, " %d", list->b[i]);

   fputc('\n', stdout);
}
Added jni/libdmtx/dmtxdecode.c.


























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 * Copyright 2009 Mackenzie Straight. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxdecode.c
 * \brief Decode regions
 */

/**
 * \brief  Initialize decode struct with default values
 * \param  img
 * \return Initialized DmtxDecode struct
 */
extern DmtxDecode *
dmtxDecodeCreate(DmtxImage *img, int scale)
{
   DmtxDecode *dec;
   int width, height;

   dec = (DmtxDecode *)calloc(1, sizeof(DmtxDecode));
   if(dec == NULL)
      return NULL;

   width = dmtxImageGetProp(img, DmtxPropWidth) / scale;
   height = dmtxImageGetProp(img, DmtxPropHeight) / scale;

   dec->edgeMin = DmtxUndefined;
   dec->edgeMax = DmtxUndefined;
   dec->scanGap = 1;
   dec->squareDevn = cos(50 * (M_PI/180));
   dec->sizeIdxExpected = DmtxSymbolShapeAuto;
   dec->edgeThresh = 10;

   dec->xMin = 0;
   dec->xMax = width - 1;
   dec->yMin = 0;
   dec->yMax = height - 1;
   dec->scale = scale;

   dec->cache = (unsigned char *)calloc(width * height, sizeof(unsigned char));
   if(dec->cache == NULL) {
      free(dec);
      return NULL;
   }

   dec->image = img;
   dec->grid = InitScanGrid(dec);

   return dec;
}

/**
 * \brief  Deinitialize decode struct
 * \param  dec
 * \return void
 */
extern DmtxPassFail
dmtxDecodeDestroy(DmtxDecode **dec)
{
   if(dec == NULL || *dec == NULL)
      return DmtxFail;

   if((*dec)->cache != NULL)
      free((*dec)->cache);

   free(*dec);

   *dec = NULL;

   return DmtxPass;
}

/**
 * \brief  Set decoding behavior property
 * \param  dec
 * \param  prop
 * \param  value
 * \return DmtxPass | DmtxFail
 */
extern DmtxPassFail
dmtxDecodeSetProp(DmtxDecode *dec, int prop, int value)
{
   switch(prop) {
      case DmtxPropEdgeMin:
         dec->edgeMin = value;
         break;
      case DmtxPropEdgeMax:
         dec->edgeMax = value;
         break;
      case DmtxPropScanGap:
         dec->scanGap = value; /* XXX Should this be scaled? */
         break;
      case DmtxPropSquareDevn:
         dec->squareDevn = cos(value * (M_PI/180.0));
         break;
      case DmtxPropSymbolSize:
         dec->sizeIdxExpected = value;
         break;
      case DmtxPropEdgeThresh:
         dec->edgeThresh = value;
         break;
      /* Min and Max values arrive unscaled */
      case DmtxPropXmin:
         dec->xMin = value / dec->scale;
         break;
      case DmtxPropXmax:
         dec->xMax = value / dec->scale;
         break;
      case DmtxPropYmin:
         dec->yMin = value / dec->scale;
         break;
      case DmtxPropYmax:
         dec->yMax = value / dec->scale;
         break;
      default:
         break;
   }

   if(dec->squareDevn <= 0.0 || dec->squareDevn >= 1.0)
      return DmtxFail;

   if(dec->scanGap < 1)
      return DmtxFail;

   if(dec->edgeThresh < 1 || dec->edgeThresh > 100)
      return DmtxFail;

   /* Reinitialize scangrid in case any inputs changed */
   dec->grid = InitScanGrid(dec);

   return DmtxPass;
}

/**
 * \brief  Get decoding behavior property
 * \param  dec
 * \param  prop
 * \return value
 */
extern int
dmtxDecodeGetProp(DmtxDecode *dec, int prop)
{
   switch(prop) {
      case DmtxPropEdgeMin:
         return dec->edgeMin;
      case DmtxPropEdgeMax:
         return dec->edgeMax;
      case DmtxPropScanGap:
         return dec->scanGap;
      case DmtxPropSquareDevn:
         return (int)(acos(dec->squareDevn) * 180.0/M_PI);
      case DmtxPropSymbolSize:
         return dec->sizeIdxExpected;
      case DmtxPropEdgeThresh:
         return dec->edgeThresh;
      case DmtxPropXmin:
         return dec->xMin;
      case DmtxPropXmax:
         return dec->xMax;
      case DmtxPropYmin:
         return dec->yMin;
      case DmtxPropYmax:
         return dec->yMax;
      case DmtxPropScale:
         return dec->scale;
      case DmtxPropWidth:
         return dmtxImageGetProp(dec->image, DmtxPropWidth) / dec->scale;
      case DmtxPropHeight:
         return dmtxImageGetProp(dec->image, DmtxPropHeight) / dec->scale;
      default:
         break;
   }

   return DmtxUndefined;
}

/**
 * \brief  Returns xxx
 * \param  img
 * \param  Scaled x coordinate
 * \param  Scaled y coordinate
 * \return Scaled pixel offset
 */
extern unsigned char *
dmtxDecodeGetCache(DmtxDecode *dec, int x, int y)
{
   int width, height;

   assert(dec != NULL);

/* if(dec.cacheComplete == DmtxFalse)
      CacheImage(); */

   width = dmtxDecodeGetProp(dec, DmtxPropWidth);
   height = dmtxDecodeGetProp(dec, DmtxPropHeight);

   if(x < 0 || x >= width || y < 0 || y >= height)
      return NULL;

   return &(dec->cache[y * width + x]);
}

/**
 *
 *
 */
extern DmtxPassFail
dmtxDecodeGetPixelValue(DmtxDecode *dec, int x, int y, int channel, int *value)
{
   int xUnscaled, yUnscaled;
   DmtxPassFail err;

   xUnscaled = x * dec->scale;
   yUnscaled = y * dec->scale;

/* Remove spherical lens distortion */
/* int width, height;
   double radiusPow2, radiusPow4;
   double factor;
   DmtxVector2 pointShifted;
   DmtxVector2 correctedPoint;

   width = dmtxImageGetProp(img, DmtxPropWidth);
   height = dmtxImageGetProp(img, DmtxPropHeight);

   pointShifted.X = point.X - width/2.0;
   pointShifted.Y = point.Y - height/2.0;

   radiusPow2 = pointShifted.X * pointShifted.X + pointShifted.Y * pointShifted.Y;
   radiusPow4 = radiusPow2 * radiusPow2;

   factor = 1 + (k1 * radiusPow2) + (k2 * radiusPow4);

   correctedPoint.X = pointShifted.X * factor + width/2.0;
   correctedPoint.Y = pointShifted.Y * factor + height/2.0;

   return correctedPoint; */

   err = dmtxImageGetPixelValue(dec->image, xUnscaled, yUnscaled, channel, value);

   return err;
}

/**
 * \brief  Fill the region covered by the quadrilateral given by (p0,p1,p2,p3) in the cache.
 */
static void
CacheFillQuad(DmtxDecode *dec, DmtxPixelLoc p0, DmtxPixelLoc p1, DmtxPixelLoc p2, DmtxPixelLoc p3)
{
   DmtxBresLine lines[4];
   DmtxPixelLoc pEmpty = { 0, 0 };
   unsigned char *cache;
   int *scanlineMin, *scanlineMax;
   int minY, maxY, sizeY, posY, posX;
   int i, idx;

   lines[0] = BresLineInit(p0, p1, pEmpty);
   lines[1] = BresLineInit(p1, p2, pEmpty);
   lines[2] = BresLineInit(p2, p3, pEmpty);
   lines[3] = BresLineInit(p3, p0, pEmpty);

   minY = dec->yMax;
   maxY = 0;

   minY = min(minY, p0.Y); maxY = max(maxY, p0.Y);
   minY = min(minY, p1.Y); maxY = max(maxY, p1.Y);
   minY = min(minY, p2.Y); maxY = max(maxY, p2.Y);
   minY = min(minY, p3.Y); maxY = max(maxY, p3.Y);

   sizeY = maxY - minY + 1;

   scanlineMin = (int *)malloc(sizeY * sizeof(int));
   scanlineMax = (int *)calloc(sizeY, sizeof(int));

   assert(scanlineMin); /* XXX handle this better */
   assert(scanlineMax); /* XXX handle this better */

   for(i = 0; i < sizeY; i++)
      scanlineMin[i] = dec->xMax;

   for(i = 0; i < 4; i++) {
      while(lines[i].loc.X != lines[i].loc1.X || lines[i].loc.Y != lines[i].loc1.Y) {
         idx = lines[i].loc.Y - minY;
         scanlineMin[idx] = min(scanlineMin[idx], lines[i].loc.X);
         scanlineMax[idx] = max(scanlineMax[idx], lines[i].loc.X);
         BresLineStep(lines + i, 1, 0);
      }
   }

   for(posY = minY; posY < maxY && posY < dec->yMax; posY++) {
      idx = posY - minY;
      for(posX = scanlineMin[idx]; posX < scanlineMax[idx] && posX < dec->xMax; posX++) {
         cache = dmtxDecodeGetCache(dec, posX, posY);
         if(cache != NULL)
            *cache |= 0x80;
      }
   }

   free(scanlineMin);
   free(scanlineMax);
}

/**
 * \brief  Convert fitted Data Matrix region into a decoded message
 * \param  dec
 * \param  reg
 * \param  fix
 * \return Decoded message
 */
extern DmtxMessage *
dmtxDecodeMatrixRegion(DmtxDecode *dec, DmtxRegion *reg, int fix)
{
   DmtxMessage *msg;
   DmtxVector2 topLeft, topRight, bottomLeft, bottomRight;
   DmtxPixelLoc pxTopLeft, pxTopRight, pxBottomLeft, pxBottomRight;

   msg = dmtxMessageCreate(reg->sizeIdx, DmtxFormatMatrix);
   if(msg == NULL)
      return NULL;

   if(PopulateArrayFromMatrix(dec, reg, msg) != DmtxPass) {
      dmtxMessageDestroy(&msg);
      return NULL;
   }

   /* maybe place remaining logic into new dmtxDecodePopulatedArray()
      function so other people can pass in their own arrays */

   ModulePlacementEcc200(msg->array, msg->code,
         reg->sizeIdx, DmtxModuleOnRed | DmtxModuleOnGreen | DmtxModuleOnBlue);

   if(RsDecode(msg->code, reg->sizeIdx, fix) == DmtxFail)
   {
      dmtxMessageDestroy(&msg);
      return NULL;
   }

   topLeft.X = bottomLeft.X = topLeft.Y = topRight.Y = -0.1;
   topRight.X = bottomRight.X = bottomLeft.Y = bottomRight.Y = 1.1;

   dmtxMatrix3VMultiplyBy(&topLeft, reg->fit2raw);
   dmtxMatrix3VMultiplyBy(&topRight, reg->fit2raw);
   dmtxMatrix3VMultiplyBy(&bottomLeft, reg->fit2raw);
   dmtxMatrix3VMultiplyBy(&bottomRight, reg->fit2raw);

   pxTopLeft.X = (int)(0.5 + topLeft.X);
   pxTopLeft.Y = (int)(0.5 + topLeft.Y);
   pxBottomLeft.X = (int)(0.5 + bottomLeft.X);
   pxBottomLeft.Y = (int)(0.5 + bottomLeft.Y);
   pxTopRight.X = (int)(0.5 + topRight.X);
   pxTopRight.Y = (int)(0.5 + topRight.Y);
   pxBottomRight.X = (int)(0.5 + bottomRight.X);
   pxBottomRight.Y = (int)(0.5 + bottomRight.Y);

   CacheFillQuad(dec, pxTopLeft, pxTopRight, pxBottomRight, pxBottomLeft);

   DecodeDataStream(msg, reg->sizeIdx, NULL);

   return msg;
}

/**
 * \brief  Convert fitted Data Mosaic region into a decoded message
 * \param  dec
 * \param  reg
 * \param  fix
 * \return Decoded message
 */
extern DmtxMessage *
dmtxDecodeMosaicRegion(DmtxDecode *dec, DmtxRegion *reg, int fix)
{
   int offset;
   int colorPlane;
   DmtxMessage *oMsg, *rMsg, *gMsg, *bMsg;

   colorPlane = reg->flowBegin.plane;

   /**
    * Consider performing a color cube fit here to identify exact RGB of
    * all 6 "cube-like" corners based on pixels located within region. Then
    * force each sample pixel to the "cube-like" corner based o which one
    * is nearest "sqrt(dr^2+dg^2+db^2)" (except sqrt is unnecessary).
    * colorPlane = reg->flowBegin.plane;
    *
    * To find RGB values of primary colors, perform something like a
    * histogram except instead of going from black to color N, go from
    * (127,127,127) to color. Use color bins along with distance to
    * identify value. An additional method will be required to get actual
    * RGB instead of just a plane in 3D. */

   reg->flowBegin.plane = 0; /* kind of a hack */
   rMsg = dmtxDecodeMatrixRegion(dec, reg, fix);

   reg->flowBegin.plane = 1; /* kind of a hack */
   gMsg = dmtxDecodeMatrixRegion(dec, reg, fix);

   reg->flowBegin.plane = 2; /* kind of a hack */
   bMsg = dmtxDecodeMatrixRegion(dec, reg, fix);

   reg->flowBegin.plane = colorPlane;

   oMsg = dmtxMessageCreate(reg->sizeIdx, DmtxFormatMosaic);

   if(oMsg == NULL || rMsg == NULL || gMsg == NULL || bMsg == NULL) {
      dmtxMessageDestroy(&oMsg);
      dmtxMessageDestroy(&rMsg);
      dmtxMessageDestroy(&gMsg);
      dmtxMessageDestroy(&bMsg);
      return NULL;
   }

   offset = 0;
   memcpy(oMsg->output + offset, rMsg->output, rMsg->outputIdx);
   offset += rMsg->outputIdx;
   memcpy(oMsg->output + offset, gMsg->output, gMsg->outputIdx);
   offset += gMsg->outputIdx;
   memcpy(oMsg->output + offset, bMsg->output, bMsg->outputIdx);
   offset += bMsg->outputIdx;

   oMsg->outputIdx = offset;

   dmtxMessageDestroy(&rMsg);
   dmtxMessageDestroy(&gMsg);
   dmtxMessageDestroy(&bMsg);

   return oMsg;
}

/**
 *
 *
 */
extern unsigned char *
dmtxDecodeCreateDiagnostic(DmtxDecode *dec, int *totalBytes, int *headerBytes, int style)
{
   int i, row, col;
   int width, height;
   int widthDigits, heightDigits;
   int count, channelCount;
   int rgb[3];
   double shade;
   unsigned char *pnm, *output, *cache;

   width = dmtxDecodeGetProp(dec, DmtxPropWidth);
   height = dmtxDecodeGetProp(dec, DmtxPropHeight);
   channelCount = dmtxImageGetProp(dec->image, DmtxPropChannelCount);

   style = 1; /* this doesn't mean anything yet */

   /* Count width digits */
   for(widthDigits = 0, i = width; i > 0; i /= 10)
      widthDigits++;

   /* Count height digits */
   for(heightDigits = 0, i = height; i > 0; i /= 10)
      heightDigits++;

   *headerBytes = widthDigits + heightDigits + 9;
   *totalBytes = *headerBytes + width * height * 3;

   pnm = (unsigned char *)malloc(*totalBytes);
   if(pnm == NULL)
      return NULL;

#ifdef _VISUALC_
   count = sprintf_s((char *)pnm, *headerBytes + 1, "P6\n%d %d\n255\n", width, height);
#else
   count = snprintf((char *)pnm, *headerBytes + 1, "P6\n%d %d\n255\n", width, height);
#endif

   if(count != *headerBytes) {
      free(pnm);
      return NULL;
   }

   output = pnm + (*headerBytes);
   for(row = height - 1; row >= 0; row--) {
      for(col = 0; col < width; col++) {
         cache = dmtxDecodeGetCache(dec, col, row);
         if(cache == NULL) {
            rgb[0] = 0;
            rgb[1] = 0;
            rgb[2] = 128;
         }
         else if(*cache & 0x40) {
            rgb[0] = 255;
            rgb[1] = 0;
            rgb[2] = 0;
         }
         else {
            shade = (*cache & 0x80) ? 0.0 : 0.7;
            for(i = 0; i < 3; i++) {
               if(i < channelCount)
                  dmtxDecodeGetPixelValue(dec, col, row, i, &rgb[i]);
               else
                  dmtxDecodeGetPixelValue(dec, col, row, 0, &rgb[i]);

               rgb[i] += (int)(shade * (double)(255 - rgb[i]) + 0.5);
               if(rgb[i] > 255)
                  rgb[i] = 255;
            }
         }
         *(output++) = (unsigned char)rgb[0];
         *(output++) = (unsigned char)rgb[1];
         *(output++) = (unsigned char)rgb[2];
      }
   }
   assert(output == pnm + *totalBytes);

   return pnm;
}

/**
 * \brief  Increment counters used to determine module values
 * \param  img
 * \param  reg
 * \param  tally
 * \param  xOrigin
 * \param  yOrigin
 * \param  mapWidth
 * \param  mapHeight
 * \param  dir
 * \return void
 */
static void
TallyModuleJumps(DmtxDecode *dec, DmtxRegion *reg, int tally[][24], int xOrigin, int yOrigin, int mapWidth, int mapHeight, DmtxDirection dir)
{
   int extent, weight;
   int travelStep;
   int symbolRow, symbolCol;
   int mapRow, mapCol;
   int lineStart, lineStop;
   int travelStart, travelStop;
   int *line, *travel;
   int jumpThreshold;
   int darkOnLight;
   int color;
   int statusPrev, statusModule;
   int tPrev, tModule;

   assert(dir == DmtxDirUp || dir == DmtxDirLeft || dir == DmtxDirDown || dir == DmtxDirRight);

   travelStep = (dir == DmtxDirUp || dir == DmtxDirRight) ? 1 : -1;

   /* Abstract row and column progress using pointers to allow grid
      traversal in all 4 directions using same logic */

   if((dir & DmtxDirHorizontal) != 0x00) {
      line = &symbolRow;
      travel = &symbolCol;
      extent = mapWidth;
      lineStart = yOrigin;
      lineStop = yOrigin + mapHeight;
      travelStart = (travelStep == 1) ? xOrigin - 1 : xOrigin + mapWidth;
      travelStop = (travelStep == 1) ? xOrigin + mapWidth : xOrigin - 1;
   }
   else {
      assert(dir & DmtxDirVertical);
      line = &symbolCol;
      travel = &symbolRow;
      extent = mapHeight;
      lineStart = xOrigin;
      lineStop = xOrigin + mapWidth;
      travelStart = (travelStep == 1) ? yOrigin - 1: yOrigin + mapHeight;
      travelStop = (travelStep == 1) ? yOrigin + mapHeight : yOrigin - 1;
   }


   darkOnLight = (int)(reg->offColor > reg->onColor);
   jumpThreshold = abs((int)(0.4 * (reg->offColor - reg->onColor) + 0.5));

   assert(jumpThreshold >= 0);

   for(*line = lineStart; *line < lineStop; (*line)++) {

      /* Capture tModule for each leading border module as normal but
         decide status based on predictable barcode border pattern */

      *travel = travelStart;
      color = ReadModuleColor(dec, reg, symbolRow, symbolCol, reg->sizeIdx, reg->flowBegin.plane);
      tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor;

      statusModule = (travelStep == 1 || (*line & 0x01) == 0) ? DmtxModuleOnRGB : DmtxModuleOff;

      weight = extent;

      while((*travel += travelStep) != travelStop) {

         tPrev = tModule;
         statusPrev = statusModule;

         /* For normal data-bearing modules capture color and decide
            module status based on comparison to previous "known" module */

         color = ReadModuleColor(dec, reg, symbolRow, symbolCol, reg->sizeIdx, reg->flowBegin.plane);
         tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor;

         if(statusPrev == DmtxModuleOnRGB) {
            if(tModule < tPrev - jumpThreshold)
               statusModule = DmtxModuleOff;
            else
               statusModule = DmtxModuleOnRGB;
         }
         else if(statusPrev == DmtxModuleOff) {
            if(tModule > tPrev + jumpThreshold)
               statusModule = DmtxModuleOnRGB;
            else
               statusModule = DmtxModuleOff;
         }

         mapRow = symbolRow - yOrigin;
         mapCol = symbolCol - xOrigin;
         assert(mapRow < 24 && mapCol < 24);

         if(statusModule == DmtxModuleOnRGB)
            tally[mapRow][mapCol] += (2 * weight);

         weight--;
      }

      assert(weight == 0);
   }
}

/**
 * \brief  Populate array with codeword values based on module colors
 * \param  msg
 * \param  img
 * \param  reg
 * \return DmtxPass | DmtxFail
 */
static DmtxPassFail
PopulateArrayFromMatrix(DmtxDecode *dec, DmtxRegion *reg, DmtxMessage *msg)
{
   int weightFactor;
   int mapWidth, mapHeight;
   int xRegionTotal, yRegionTotal;
   int xRegionCount, yRegionCount;
   int xOrigin, yOrigin;
   int mapCol, mapRow;
   int colTmp, rowTmp, idx;
   int tally[24][24]; /* Large enough to map largest single region */

/* memset(msg->array, 0x00, msg->arraySize); */

   /* Capture number of regions present in barcode */
   xRegionTotal = dmtxGetSymbolAttribute(DmtxSymAttribHorizDataRegions, reg->sizeIdx);
   yRegionTotal = dmtxGetSymbolAttribute(DmtxSymAttribVertDataRegions, reg->sizeIdx);

   /* Capture region dimensions (not including border modules) */
   mapWidth = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionCols, reg->sizeIdx);
   mapHeight = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionRows, reg->sizeIdx);

   weightFactor = 2 * (mapHeight + mapWidth + 2);
   assert(weightFactor > 0);

   /* Tally module changes for each region in each direction */
   for(yRegionCount = 0; yRegionCount < yRegionTotal; yRegionCount++) {

      /* Y location of mapping region origin in symbol coordinates */
      yOrigin = yRegionCount * (mapHeight + 2) + 1;

      for(xRegionCount = 0; xRegionCount < xRegionTotal; xRegionCount++) {

         /* X location of mapping region origin in symbol coordinates */
         xOrigin = xRegionCount * (mapWidth + 2) + 1;

         memset(tally, 0x00, 24 * 24 * sizeof(int));
         TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirUp);
         TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirLeft);
         TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirDown);
         TallyModuleJumps(dec, reg, tally, xOrigin, yOrigin, mapWidth, mapHeight, DmtxDirRight);

         /* Decide module status based on final tallies */
         for(mapRow = 0; mapRow < mapHeight; mapRow++) {
            for(mapCol = 0; mapCol < mapWidth; mapCol++) {

               rowTmp = (yRegionCount * mapHeight) + mapRow;
               rowTmp = yRegionTotal * mapHeight - rowTmp - 1;
               colTmp = (xRegionCount * mapWidth) + mapCol;
               idx = (rowTmp * xRegionTotal * mapWidth) + colTmp;

               if(tally[mapRow][mapCol]/(double)weightFactor >= 0.5)
                  msg->array[idx] = DmtxModuleOnRGB;
               else
                  msg->array[idx] = DmtxModuleOff;

               msg->array[idx] |= DmtxModuleAssigned;
            }
         }
      }
   }

   return DmtxPass;
}
Added jni/libdmtx/dmtxdecodescheme.c.










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxdecodescheme.c
 */

/**
 * \brief  Translate encoded data stream into final output
 * \param  msg
 * \param  sizeIdx
 * \param  outputStart
 * \return void
 */
static void
DecodeDataStream(DmtxMessage *msg, int sizeIdx, unsigned char *outputStart)
{
   DmtxBoolean macro = DmtxFalse;
   DmtxScheme encScheme;
   unsigned char *ptr, *dataEnd;

   msg->output = (outputStart == NULL) ? msg->output : outputStart;
   msg->outputIdx = 0;

   ptr = msg->code;
   dataEnd = ptr + dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);

   /* Print macro header if first codeword triggers it */
   if(*ptr == DmtxValue05Macro || *ptr == DmtxValue06Macro) {
      PushOutputMacroHeader(msg, *ptr);
      macro = DmtxTrue;
   }

   while(ptr < dataEnd) {

      encScheme = GetEncodationScheme(*ptr);
      if(encScheme != DmtxSchemeAscii)
         ptr++;

      switch(encScheme) {
         case DmtxSchemeAscii:
            ptr = DecodeSchemeAscii(msg, ptr, dataEnd);
            break;
         case DmtxSchemeC40:
         case DmtxSchemeText:
            ptr = DecodeSchemeC40Text(msg, ptr, dataEnd, encScheme);
            break;
         case DmtxSchemeX12:
            ptr = DecodeSchemeX12(msg, ptr, dataEnd);
            break;
         case DmtxSchemeEdifact:
            ptr = DecodeSchemeEdifact(msg, ptr, dataEnd);
            break;
         case DmtxSchemeBase256:
            ptr = DecodeSchemeBase256(msg, ptr, dataEnd);
            break;
         default:
            /* error */
            break;
      }
   }

   /* Print macro trailer if required */
   if(macro == DmtxTrue)
      PushOutputMacroTrailer(msg);
}

/**
 * \brief  Determine next encodation scheme
 * \param  encScheme
 * \param  cw
 * \return Pointer to next undecoded codeword
 */
static int
GetEncodationScheme(unsigned char cw)
{
   DmtxScheme encScheme;

   switch(cw) {
      case DmtxValueC40Latch:
         encScheme = DmtxSchemeC40;
         break;
      case DmtxValueTextLatch:
         encScheme = DmtxSchemeText;
         break;
      case DmtxValueX12Latch:
         encScheme = DmtxSchemeX12;
         break;
      case DmtxValueEdifactLatch:
         encScheme = DmtxSchemeEdifact;
         break;
      case DmtxValueBase256Latch:
         encScheme = DmtxSchemeBase256;
         break;
      default:
         encScheme = DmtxSchemeAscii;
         break;
   }

   return encScheme;
}

/**
 *
 *
 */
static void
PushOutputWord(DmtxMessage *msg, int value)
{
   assert(value >= 0 && value < 256);

   msg->output[msg->outputIdx++] = (unsigned char)value;
}

/**
 *
 *
 */
static void
PushOutputC40TextWord(DmtxMessage *msg, C40TextState *state, int value)
{
   assert(value >= 0 && value < 256);

   msg->output[msg->outputIdx] = (unsigned char)value;

   if(state->upperShift == DmtxTrue) {
      assert(value < 128);
      msg->output[msg->outputIdx] += 128;
   }

   msg->outputIdx++;

   state->shift = DmtxC40TextBasicSet;
   state->upperShift = DmtxFalse;
}

/**
 *
 *
 */
static void
PushOutputMacroHeader(DmtxMessage *msg, int macroType)
{
   PushOutputWord(msg, '[');
   PushOutputWord(msg, ')');
   PushOutputWord(msg, '>');
   PushOutputWord(msg, 30); /* ASCII RS */
   PushOutputWord(msg, '0');

   assert(macroType == DmtxValue05Macro || macroType == DmtxValue06Macro);
   if(macroType == DmtxValue05Macro)
      PushOutputWord(msg, '5');
   else
      PushOutputWord(msg, '6');

   PushOutputWord(msg, 29); /* ASCII GS */
}

/**
 *
 *
 */
static void
PushOutputMacroTrailer(DmtxMessage *msg)
{
   PushOutputWord(msg, 30); /* ASCII RS */
   PushOutputWord(msg, 4);  /* ASCII EOT */
}

/**
 * \brief  Decode stream assuming standard ASCII encodation
 * \param  msg
 * \param  ptr
 * \param  dataEnd
 * \return Pointer to next undecoded codeword
 */
static unsigned char *
DecodeSchemeAscii(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd)
{
   int upperShift;
   int codeword, digits;

   upperShift = DmtxFalse;

   while(ptr < dataEnd) {

      codeword = (int)(*ptr);

      if(GetEncodationScheme(*ptr) != DmtxSchemeAscii)
         return ptr;
      else
         ptr++;

      if(upperShift == DmtxTrue) {
         PushOutputWord(msg, codeword + 127);
         upperShift = DmtxFalse;
      }
      else if(codeword == DmtxValueAsciiUpperShift) {
         upperShift = DmtxTrue;
      }
      else if(codeword == DmtxValueAsciiPad) {
         assert(dataEnd >= ptr);
         assert(dataEnd - ptr <= INT_MAX);
         msg->padCount = (int)(dataEnd - ptr);
         return dataEnd;
      }
      else if(codeword <= 128) {
         PushOutputWord(msg, codeword - 1);
      }
      else if(codeword <= 229) {
         digits = codeword - 130;
         PushOutputWord(msg, digits/10 + '0');
         PushOutputWord(msg, digits - (digits/10)*10 + '0');
      }
   }

   return ptr;
}

/**
 * \brief  Decode stream assuming C40 or Text encodation
 * \param  msg
 * \param  ptr
 * \param  dataEnd
 * \param  encScheme
 * \return Pointer to next undecoded codeword
 */
static unsigned char *
DecodeSchemeC40Text(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd, DmtxScheme encScheme)
{
   int i;
   int packed;
   int c40Values[3];
   C40TextState state;

   state.shift = DmtxC40TextBasicSet;
   state.upperShift = DmtxFalse;

   assert(encScheme == DmtxSchemeC40 || encScheme == DmtxSchemeText);

   /* Unlatch is implied if only one codeword remains */
   if(dataEnd - ptr < 2)
      return ptr;

   while(ptr < dataEnd) {

      /* FIXME Also check that ptr+1 is safe to access */
      packed = (*ptr << 8) | *(ptr+1);
      c40Values[0] = ((packed - 1)/1600);
      c40Values[1] = ((packed - 1)/40) % 40;
      c40Values[2] =  (packed - 1) % 40;
      ptr += 2;

      for(i = 0; i < 3; i++) {
         if(state.shift == DmtxC40TextBasicSet) { /* Basic set */
            if(c40Values[i] <= 2) {
               state.shift = c40Values[i] + 1;
            }
            else if(c40Values[i] == 3) {
               PushOutputC40TextWord(msg, &state, ' ');
            }
            else if(c40Values[i] <= 13) {
               PushOutputC40TextWord(msg, &state, c40Values[i] - 13 + '9'); /* 0-9 */
            }
            else if(c40Values[i] <= 39) {
               if(encScheme == DmtxSchemeC40) {
                  PushOutputC40TextWord(msg, &state, c40Values[i] - 39 + 'Z'); /* A-Z */
               }
               else if(encScheme == DmtxSchemeText) {
                  PushOutputC40TextWord(msg, &state, c40Values[i] - 39 + 'z'); /* a-z */
               }
            }
         }
         else if(state.shift == DmtxC40TextShift1) { /* Shift 1 set */
            PushOutputC40TextWord(msg, &state, c40Values[i]); /* ASCII 0 - 31 */
         }
         else if(state.shift == DmtxC40TextShift2) { /* Shift 2 set */
            if(c40Values[i] <= 14) {
               PushOutputC40TextWord(msg, &state, c40Values[i] + 33); /* ASCII 33 - 47 */
            }
            else if(c40Values[i] <= 21) {
               PushOutputC40TextWord(msg, &state, c40Values[i] + 43); /* ASCII 58 - 64 */
            }
            else if(c40Values[i] <= 26) {
               PushOutputC40TextWord(msg, &state, c40Values[i] + 69); /* ASCII 91 - 95 */
            }
            else if(c40Values[i] == 27) {
               PushOutputC40TextWord(msg, &state, 0x1d); /* FNC1 -- XXX depends on position? */
            }
            else if(c40Values[i] == 30) {
               state.upperShift = DmtxTrue;
               state.shift = DmtxC40TextBasicSet;
            }
         }
         else if(state.shift == DmtxC40TextShift3) { /* Shift 3 set */
            if(encScheme == DmtxSchemeC40) {
               PushOutputC40TextWord(msg, &state, c40Values[i] + 96);
            }
            else if(encScheme == DmtxSchemeText) {
               if(c40Values[i] == 0)
                  PushOutputC40TextWord(msg, &state, c40Values[i] + 96);
               else if(c40Values[i] <= 26)
                  PushOutputC40TextWord(msg, &state, c40Values[i] - 26 + 'Z'); /* A-Z */
               else
                  PushOutputC40TextWord(msg, &state, c40Values[i] - 31 + 127); /* { | } ~ DEL */
            }
         }
      }

      /* Unlatch if codeword 254 follows 2 codewords in C40/Text encodation */
      if(*ptr == DmtxValueCTXUnlatch)
         return ptr + 1;

      /* Unlatch is implied if only one codeword remains */
      if(dataEnd - ptr < 2)
         return ptr;
   }

   return ptr;
}

/**
 * \brief  Decode stream assuming X12 encodation
 * \param  msg
 * \param  ptr
 * \param  dataEnd
 * \return Pointer to next undecoded codeword
 */
static unsigned char *
DecodeSchemeX12(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd)
{
   int i;
   int packed;
   int x12Values[3];

   /* Unlatch is implied if only one codeword remains */
   if(dataEnd - ptr < 2)
      return ptr;

   while(ptr < dataEnd) {

      /* FIXME Also check that ptr+1 is safe to access */
      packed = (*ptr << 8) | *(ptr+1);
      x12Values[0] = ((packed - 1)/1600);
      x12Values[1] = ((packed - 1)/40) % 40;
      x12Values[2] =  (packed - 1) % 40;
      ptr += 2;

      for(i = 0; i < 3; i++) {
         if(x12Values[i] == 0)
            PushOutputWord(msg, 13);
         else if(x12Values[i] == 1)
            PushOutputWord(msg, 42);
         else if(x12Values[i] == 2)
            PushOutputWord(msg, 62);
         else if(x12Values[i] == 3)
            PushOutputWord(msg, 32);
         else if(x12Values[i] <= 13)
            PushOutputWord(msg, x12Values[i] + 44);
         else if(x12Values[i] <= 90)
            PushOutputWord(msg, x12Values[i] + 51);
      }

      /* Unlatch if codeword 254 follows 2 codewords in C40/Text encodation */
      if(*ptr == DmtxValueCTXUnlatch)
         return ptr + 1;

      /* Unlatch is implied if only one codeword remains */
      if(dataEnd - ptr < 2)
         return ptr;
   }

   return ptr;
}

/**
 * \brief  Decode stream assuming EDIFACT encodation
 * \param  msg
 * \param  ptr
 * \param  dataEnd
 * \return Pointer to next undecoded codeword
 */
static unsigned char *
DecodeSchemeEdifact(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd)
{
   int i;
   unsigned char unpacked[4];

   /* Unlatch is implied if fewer than 3 codewords remain */
   if(dataEnd - ptr < 3)
      return ptr;

   while(ptr < dataEnd) {

      /* FIXME Also check that ptr+2 is safe to access -- shouldn't be a
         problem because I'm guessing you can guarantee there will always
         be at least 3 error codewords */
      unpacked[0] = (*ptr & 0xfc) >> 2;
      unpacked[1] = (*ptr & 0x03) << 4 | (*(ptr+1) & 0xf0) >> 4;
      unpacked[2] = (*(ptr+1) & 0x0f) << 2 | (*(ptr+2) & 0xc0) >> 6;
      unpacked[3] = *(ptr+2) & 0x3f;

      for(i = 0; i < 4; i++) {

         /* Advance input ptr (4th value comes from already-read 3rd byte) */
         if(i < 3)
            ptr++;

         /* Test for unlatch condition */
         if(unpacked[i] == DmtxValueEdifactUnlatch) {
            assert(msg->output[msg->outputIdx] == 0); /* XXX dirty why? */
            return ptr;
         }

         PushOutputWord(msg, unpacked[i] ^ (((unpacked[i] & 0x20) ^ 0x20) << 1));
      }

      /* Unlatch is implied if fewer than 3 codewords remain */
      if(dataEnd - ptr < 3)
         return ptr;
   }

   return ptr;

/* XXX the following version should be safer, but requires testing before replacing the old version
   int bits = 0;
   int bitCount = 0;
   int value;

   while(ptr < dataEnd) {

      if(bitCount < 6) {
         bits = (bits << 8) | *(ptr++);
         bitCount += 8;
      }

      value = bits >> (bitCount - 6);
      bits -= (value << (bitCount - 6));
      bitCount -= 6;

      if(value == 0x1f) {
         assert(bits == 0); // should be padded with zero-value bits
         return ptr;
      }
      PushOutputWord(msg, value ^ (((value & 0x20) ^ 0x20) << 1));

      // Unlatch implied if just completed triplet and 1 or 2 words are left
      if(bitCount == 0 && dataEnd - ptr - 1 > 0 && dataEnd - ptr - 1 < 3)
         return ptr;
   }

   assert(bits == 0); // should be padded with zero-value bits
   assert(bitCount == 0); // should be padded with zero-value bits
   return ptr;
*/
}

/**
 * \brief  Decode stream assuming Base 256 encodation
 * \param  msg
 * \param  ptr
 * \param  dataEnd
 * \return Pointer to next undecoded codeword
 */
static unsigned char *
DecodeSchemeBase256(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd)
{
   int d0, d1;
   int idx;
   unsigned char *ptrEnd;

   /* Find positional index used for unrandomizing */
   assert(ptr + 1 >= msg->code);
   assert(ptr + 1 - msg->code <= INT_MAX);
   idx = (int)(ptr + 1 - msg->code);

   d0 = UnRandomize255State(*(ptr++), idx++);
   if(d0 == 0) {
      ptrEnd = dataEnd;
   }
   else if(d0 <= 249) {
      ptrEnd = ptr + d0;
   }
   else {
      d1 = UnRandomize255State(*(ptr++), idx++);
      ptrEnd = ptr + (d0 - 249) * 250 + d1;
   }

   if(ptrEnd > dataEnd)
      exit(40); /* XXX needs cleaner error handling */

   while(ptr < ptrEnd)
      PushOutputWord(msg, UnRandomize255State(*(ptr++), idx++));

   return ptr;
}
Added jni/libdmtx/dmtxencode.c.
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxencode.c
 * \brief Base encoding logic
 */

#undef ISDIGIT
#define ISDIGIT(n) (n > 47 && n < 58)

/**
 * \brief  Initialize encode struct with default values
 * \return Initialized DmtxEncode struct
 */
extern DmtxEncode *
dmtxEncodeCreate(void)
{
   DmtxEncode *enc;

   enc = (DmtxEncode *)calloc(1, sizeof(DmtxEncode));
   if(enc == NULL)
      return NULL;

   enc->scheme = DmtxSchemeAscii;
   enc->sizeIdxRequest = DmtxSymbolSquareAuto;
   enc->marginSize = 10;
   enc->moduleSize = 5;
   enc->pixelPacking = DmtxPack24bppRGB;
   enc->imageFlip = DmtxFlipNone;
   enc->rowPadBytes = 0;

   /* Initialize background color to white */
/* enc.region.gradient.ray.p.R = 255.0;
   enc.region.gradient.ray.p.G = 255.0;
   enc.region.gradient.ray.p.B = 255.0; */

   /* Initialize foreground color to black */
/* enc.region.gradient.tMin = 0.0;
   enc.region.gradient.tMax = xyz; */

   dmtxMatrix3Identity(enc->xfrm);

   return enc;
}

/**
 * \brief  Deinitialize encode struct
 * \param  enc
 * \return void
 */
extern DmtxPassFail
dmtxEncodeDestroy(DmtxEncode **enc)
{
   if(enc == NULL || *enc == NULL)
      return DmtxFail;

   /* Free pixel array allocated in dmtxEncodeDataMatrix() */
   if((*enc)->image != NULL && (*enc)->image->pxl != NULL) {
      free((*enc)->image->pxl);
      (*enc)->image->pxl = NULL;
   }

   dmtxImageDestroy(&((*enc)->image));
   dmtxMessageDestroy(&((*enc)->message));

   free(*enc);

   *enc = NULL;

   return DmtxPass;
}

/**
 * \brief  Set encoding behavior property
 * \param  enc
 * \param  prop
 * \param  value
 * \return DmtxPass | DmtxFail
 */
extern DmtxPassFail
dmtxEncodeSetProp(DmtxEncode *enc, int prop, int value)
{
   switch(prop) {

      /* Encoding details */
      case DmtxPropScheme:
         enc->scheme = value;
         break;
      case DmtxPropSizeRequest:
         if(value == DmtxSymbolShapeAuto)
            return DmtxFail;
         enc->sizeIdxRequest = value;
         break;

      /* Presentation details */
      case DmtxPropMarginSize:
         enc->marginSize = value;
         break;
      case DmtxPropModuleSize:
         enc->moduleSize = value;
         break;

      /* Image properties */
      case DmtxPropPixelPacking:
         enc->pixelPacking = value;
         break;
      case DmtxPropImageFlip:
         enc->imageFlip = value;
         break;
      case DmtxPropRowPadBytes:
         enc->rowPadBytes = value;
      default:
         break;
   }

   return DmtxPass;
}

/**
 * \brief  Get encoding behavior property
 * \param  enc
 * \param  prop
 * \return value
 */
extern int
dmtxEncodeGetProp(DmtxEncode *enc, int prop)
{
   switch(prop) {
      case DmtxPropMarginSize:
         return enc->marginSize;
      case DmtxPropModuleSize:
         return enc->moduleSize;
      case DmtxPropScheme:
         return enc->scheme;
      default:
         break;
   }

   return DmtxUndefined;
}

/**
 * \brief  Convert message into Data Matrix image
 * \param  enc
 * \param  inputSize
 * \param  inputString
 * \param  sizeIdxRequest
 * \return DmtxPass | DmtxFail
 */
extern DmtxPassFail
dmtxEncodeDataMatrix(DmtxEncode *enc, int inputSize, unsigned char *inputString)
{
   int sizeIdx;
   int width, height, bitsPerPixel;
   unsigned char *pxl;
   DmtxByte outputStorage[4096];
   DmtxByteList output = dmtxByteListBuild(outputStorage, sizeof(outputStorage));
   DmtxByteList input = dmtxByteListBuild(inputString, inputSize);

   input.length = inputSize;

   /* Future: stream = StreamInit() ... */
   /* Future: EncodeDataCodewords(&stream) ... */

   /* Encode input string into data codewords */
   sizeIdx = EncodeDataCodewords(&input, &output, enc->sizeIdxRequest, enc->scheme);
   if(sizeIdx == DmtxUndefined || output.length <= 0)
      return DmtxFail;

   /* EncodeDataCodewords() should have updated any auto sizeIdx to a real one */
   assert(sizeIdx != DmtxSymbolSquareAuto && sizeIdx != DmtxSymbolRectAuto);

   /* XXX we can remove a lot of this redundant data */
   enc->region.sizeIdx = sizeIdx;
   enc->region.symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
   enc->region.symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx);
   enc->region.mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx);
   enc->region.mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx);

   /* Allocate memory for message and array */
   enc->message = dmtxMessageCreate(sizeIdx, DmtxFormatMatrix);
   enc->message->padCount = 0; /* XXX this needs to be added back */
   memcpy(enc->message->code, output.b, output.length);

   /* Generate error correction codewords */
   RsEncode(enc->message, enc->region.sizeIdx);

   /* Module placement in region */
   ModulePlacementEcc200(enc->message->array, enc->message->code,
         enc->region.sizeIdx, DmtxModuleOnRGB);

   width = 2 * enc->marginSize + (enc->region.symbolCols * enc->moduleSize);
   height = 2 * enc->marginSize + (enc->region.symbolRows * enc->moduleSize);
   bitsPerPixel = GetBitsPerPixel(enc->pixelPacking);
   if(bitsPerPixel == DmtxUndefined)
      return DmtxFail;
   assert(bitsPerPixel % 8 == 0);

   /* Allocate memory for the image to be generated */
   pxl = (unsigned char *)malloc(width * height * (bitsPerPixel/8) + enc->rowPadBytes);
   if(pxl == NULL) {
      perror("pixel malloc error");
      return DmtxFail;
   }

   enc->image = dmtxImageCreate(pxl, width, height, enc->pixelPacking);
   if(enc->image == NULL) {
      perror("image malloc error");
      return DmtxFail;
   }

   dmtxImageSetProp(enc->image, DmtxPropImageFlip, enc->imageFlip);
   dmtxImageSetProp(enc->image, DmtxPropRowPadBytes, enc->rowPadBytes);

   /* Insert finder and aligment pattern modules */
   PrintPattern(enc);

   return DmtxPass;
}

/**
 * \brief  Convert message into Data Mosaic image
 *
 *  1) count how many codewords it would take to encode the whole thing
 *  2) take ceiling N of codeword count divided by 3
 *  3) using minimum symbol size that can accomodate N codewords:
 *  4) create several barcodes over iterations of increasing numbers of
 *     input codewords until you go one too far
 *  5) if codewords remain after filling R, G, and B barcodes then go back
 *     to 3 and try with next larger size
 *  6) take the 3 different images you created and write out a new barcode
 *
 * \param  enc
 * \param  inputSize
 * \param  inputString
 * \param  sizeIdxRequest
 * \return DmtxPass | DmtxFail
 */
extern DmtxPassFail
dmtxEncodeDataMosaic(DmtxEncode *enc, int inputSize, unsigned char *inputString)
{
   unsigned char *inputStringR, *inputStringG, *inputStringB;
   int tmpInputSize;
   int inputSizeR, inputSizeG, inputSizeB;
   int sizeIdxAttempt, sizeIdxFirst, sizeIdxLast;
   int row, col, mappingRows, mappingCols;
   DmtxEncode *encR, *encG, *encB;

   /* Use 1/3 (ceiling) of inputSize establish input size target */
   tmpInputSize = (inputSize + 2) / 3;
   inputSizeR = tmpInputSize;
   inputSizeG = tmpInputSize;
   inputSizeB = inputSize - (inputSizeR + inputSizeG);

   inputStringR = inputString;
   inputStringG = inputStringR + inputSizeR;
   inputStringB = inputStringG + inputSizeG;

   /* Use 1/3 (floor) of dataWordCount establish first symbol size attempt */
   sizeIdxFirst = FindSymbolSize(tmpInputSize, enc->sizeIdxRequest);
   if(sizeIdxFirst == DmtxUndefined)
      return DmtxFail;

   /* Set the last possible symbol size for this symbol shape or specific size request */
   if(enc->sizeIdxRequest == DmtxSymbolSquareAuto)
      sizeIdxLast = DmtxSymbolSquareCount - 1;
   else if(enc->sizeIdxRequest == DmtxSymbolRectAuto)
      sizeIdxLast = DmtxSymbolSquareCount + DmtxSymbolRectCount - 1;
   else
      sizeIdxLast = sizeIdxFirst;

   encR = encG = encB = NULL;

   /* Try increasing symbol sizes until 3 of them can hold all input values */
   for(sizeIdxAttempt = sizeIdxFirst; sizeIdxAttempt <= sizeIdxLast; sizeIdxAttempt++)
   {
      dmtxEncodeDestroy(&encR);
      dmtxEncodeDestroy(&encG);
      dmtxEncodeDestroy(&encB);

      encR = dmtxEncodeCreate();
      encG = dmtxEncodeCreate();
      encB = dmtxEncodeCreate();

      /* Copy all settings from master DmtxEncode, including pointer to image
         and message, which is initially null */
      *encR = *encG = *encB = *enc;

      dmtxEncodeSetProp(encR, DmtxPropSizeRequest, sizeIdxAttempt);
      dmtxEncodeSetProp(encG, DmtxPropSizeRequest, sizeIdxAttempt);
      dmtxEncodeSetProp(encB, DmtxPropSizeRequest, sizeIdxAttempt);

      /* RED LAYER - Holds temporary copy */
      dmtxEncodeDataMatrix(encR, inputSizeR, inputStringR);
      if(encR->region.sizeIdx != sizeIdxAttempt)
         continue;

      /* GREEN LAYER - Holds temporary copy */
      dmtxEncodeDataMatrix(encG, inputSizeG, inputStringG);
      if(encG->region.sizeIdx != sizeIdxAttempt)
         continue;

      /* BLUE LAYER - Holds temporary copy */
      dmtxEncodeDataMatrix(encB, inputSizeB, inputStringB);
      if(encB->region.sizeIdx != sizeIdxAttempt)
         continue;

      /* If we get this far we found a fit */
      break;
   }

   if(encR == NULL || encG == NULL || encB == NULL)
   {
      dmtxEncodeDestroy(&encR);
      dmtxEncodeDestroy(&encG);
      dmtxEncodeDestroy(&encB);
      return DmtxFail;
   }

   /* Now we have the correct sizeIdxAttempt, and they all fit into the desired size */

   /* Perform the red portion of the final encode to set internals correctly */
   dmtxEncodeSetProp(enc, DmtxPropSizeRequest, sizeIdxAttempt);
   dmtxEncodeDataMatrix(enc, inputSizeR, inputStringR);

   /* Zero out the array and overwrite the bits in 3 passes */
   mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdxAttempt);
   mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdxAttempt);
   memset(enc->message->array, 0x00, sizeof(unsigned char) *
         enc->region.mappingRows * enc->region.mappingCols);

   ModulePlacementEcc200(enc->message->array, encR->message->code, sizeIdxAttempt, DmtxModuleOnRed);

   /* Reset DmtxModuleAssigned and DMX_MODULE_VISITED bits */
   for(row = 0; row < mappingRows; row++) {
      for(col = 0; col < mappingCols; col++) {
         enc->message->array[row*mappingCols+col] &= (0xff ^ (DmtxModuleAssigned | DmtxModuleVisited));
      }
   }

   ModulePlacementEcc200(enc->message->array, encG->message->code, sizeIdxAttempt, DmtxModuleOnGreen);

   /* Reset DmtxModuleAssigned and DMX_MODULE_VISITED bits */
   for(row = 0; row < mappingRows; row++) {
      for(col = 0; col < mappingCols; col++) {
         enc->message->array[row*mappingCols+col] &= (0xff ^ (DmtxModuleAssigned | DmtxModuleVisited));
      }
   }

   ModulePlacementEcc200(enc->message->array, encB->message->code, sizeIdxAttempt, DmtxModuleOnBlue);

   /* Destroy encR, encG, and encB */
   dmtxEncodeDestroy(&encR);
   dmtxEncodeDestroy(&encG);
   dmtxEncodeDestroy(&encB);

   PrintPattern(enc);

   return DmtxPass;
}

/**
 * \brief  Convert input into message using specific encodation scheme
 * \param  buf
 * \param  inputString
 * \param  inputSize
 * \param  scheme
 * \param  sizeIdx
 * \return Count of encoded data words
 *
 * Future: pass DmtxEncode to this function with an error reason field, which
 *         goes to EncodeSingle... too
 */
static int
EncodeDataCodewords(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest, DmtxScheme scheme)
{
   int sizeIdx;

   /* Encode input string into data codewords */
   switch(scheme)
   {
      case DmtxSchemeAutoBest:
         sizeIdx = EncodeOptimizeBest(input, output, sizeIdxRequest);
         break;
      case DmtxSchemeAutoFast:
         sizeIdx = DmtxUndefined; /* EncodeAutoFast(input, output, sizeIdxRequest, passFail); */
         break;
      default:
         sizeIdx = EncodeSingleScheme(input, output, sizeIdxRequest, scheme);
         break;
   }

   return sizeIdx;
}

/**
 * \brief  Write encoded message to image
 * \param  enc
 * \return void
 */
static void
PrintPattern(DmtxEncode *enc)
{
   int i, j;
   int symbolRow, symbolCol;
   int pixelRow, pixelCol;
   int moduleStatus;
   size_t rowSize, height;
   int rgb[3];
   double sxy, txy;
   DmtxMatrix3 m1, m2;
   DmtxVector2 vIn, vOut;

   txy = enc->marginSize;
   sxy = 1.0/enc->moduleSize;

   dmtxMatrix3Translate(m1, -txy, -txy);
   dmtxMatrix3Scale(m2, sxy, -sxy);
   dmtxMatrix3Multiply(enc->xfrm, m1, m2);

   dmtxMatrix3Translate(m1, txy, txy);
   dmtxMatrix3Scale(m2, enc->moduleSize, enc->moduleSize);
   dmtxMatrix3Multiply(enc->rxfrm, m2, m1);

   rowSize = dmtxImageGetProp(enc->image, DmtxPropRowSizeBytes);
   height = dmtxImageGetProp(enc->image, DmtxPropHeight);

   memset(enc->image->pxl, 0xff, rowSize * height);

   for(symbolRow = 0; symbolRow < enc->region.symbolRows; symbolRow++) {
      for(symbolCol = 0; symbolCol < enc->region.symbolCols; symbolCol++) {

         vIn.X = symbolCol;
         vIn.Y = symbolRow;

         dmtxMatrix3VMultiply(&vOut, &vIn, enc->rxfrm);

         pixelCol = (int)(vOut.X);
         pixelRow = (int)(vOut.Y);

         moduleStatus = dmtxSymbolModuleStatus(enc->message,
               enc->region.sizeIdx, symbolRow, symbolCol);

         for(i = pixelRow; i < pixelRow + enc->moduleSize; i++) {
            for(j = pixelCol; j < pixelCol + enc->moduleSize; j++) {
               rgb[0] = ((moduleStatus & DmtxModuleOnRed) != 0x00) ? 0 : 255;
               rgb[1] = ((moduleStatus & DmtxModuleOnGreen) != 0x00) ? 0 : 255;
               rgb[2] = ((moduleStatus & DmtxModuleOnBlue) != 0x00) ? 0 : 255;
/*             dmtxImageSetRgb(enc->image, j, i, rgb); */
               dmtxImageSetPixelValue(enc->image, j, i, 0, rgb[0]);
               dmtxImageSetPixelValue(enc->image, j, i, 1, rgb[1]);
               dmtxImageSetPixelValue(enc->image, j, i, 2, rgb[2]);
            }
         }

      }
   }
}
Added jni/libdmtx/dmtxencodeascii.c.
























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2011 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxencodeascii.c
 * \brief ASCII encoding rules
 */

/**
 * Simple single scheme encoding uses "Normal"
 * The optimizer needs to track "Expanded" and "Compact" streams separately, so they
 * are called explicitly.
 *
 *   Normal:   Automatically collapses 2 consecutive digits into one codeword
 *   Expanded: Uses a whole codeword to represent a digit (never collapses)
 *   Compact:  Collapses 2 digits into a single codeword or marks the stream
 *             invalid if either values are not digits
 *
 * \param stream
 * \param option [Expanded|Compact|Normal]
 */
static void
EncodeNextChunkAscii(DmtxEncodeStream *stream, int option)
{
   DmtxByte v0, v1;
   DmtxBoolean compactDigits;

   if(StreamInputHasNext(stream))
   {
      v0 = StreamInputAdvanceNext(stream); CHKERR;

      if((option == DmtxEncodeCompact || option == DmtxEncodeNormal) &&
            StreamInputHasNext(stream))
      {
         v1 = StreamInputPeekNext(stream); CHKERR;
         compactDigits = (ISDIGIT(v0) && ISDIGIT(v1)) ? DmtxTrue : DmtxFalse;
      }
      else /* option == DmtxEncodeFull */
      {
         v1 = 0;
         compactDigits = DmtxFalse;
      }

      if(compactDigits == DmtxTrue)
      {
         /* Two adjacent digit chars: Make peek progress official and encode */
         StreamInputAdvanceNext(stream); CHKERR;
         AppendValueAscii(stream, 10 * (v0-'0') + (v1-'0') + 130); CHKERR;
      }
      else if(option == DmtxEncodeCompact)
      {
         /* Can't compact non-digits */
         StreamMarkInvalid(stream, DmtxErrorCantCompactNonDigits);
      }
      else
      {
         /* Encode single ASCII value */
         if(v0 < 128)
         {
            /* Regular ASCII */
            AppendValueAscii(stream, v0 + 1); CHKERR;
         }
         else
         {
            /* Extended ASCII */
            AppendValueAscii(stream, DmtxValueAsciiUpperShift); CHKERR;
            AppendValueAscii(stream, v0 - 127); CHKERR;
         }
      }
   }
}

/**
 * this code is separated from EncodeNextChunkAscii() because it needs to be
 * called directly elsewhere
 */
static void
AppendValueAscii(DmtxEncodeStream *stream, DmtxByte value)
{
   CHKSCHEME(DmtxSchemeAscii);

   StreamOutputChainAppend(stream, value); CHKERR;
   stream->outputChainValueCount++;
}

/**
 *
 *
 */
static void
CompleteIfDoneAscii(DmtxEncodeStream *stream, int sizeIdxRequest)
{
   int sizeIdx;

   if(stream->status == DmtxStatusComplete)
      return;

   if(!StreamInputHasNext(stream))
   {
      sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE;
      PadRemainingInAscii(stream, sizeIdx); CHKERR;
      StreamMarkComplete(stream, sizeIdx);
   }
}

/**
 * Can we just receive a length to pad here? I don't like receiving
 * sizeIdxRequest (or sizeIdx) this late in the game
 */
static void
PadRemainingInAscii(DmtxEncodeStream *stream, int sizeIdx)
{
   int symbolRemaining;
   DmtxByte padValue;

   CHKSCHEME(DmtxSchemeAscii);
   CHKSIZE;

   symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx);

   /* First pad character is not randomized */
   if(symbolRemaining > 0)
   {
      padValue = DmtxValueAsciiPad;
      StreamOutputChainAppend(stream, padValue); CHKERR;
      symbolRemaining--;
   }

   /* All remaining pad characters are randomized based on character position */
   while(symbolRemaining > 0)
   {
      padValue = Randomize253State(DmtxValueAsciiPad, stream->output->length + 1);
      StreamOutputChainAppend(stream, padValue); CHKERR;
      symbolRemaining--;
   }
}

/**
 * consider receiving instantiated DmtxByteList instead of the output components
 */
static DmtxByteList
EncodeTmpRemainingInAscii(DmtxEncodeStream *stream, DmtxByte *storage,
      int capacity, DmtxPassFail *passFail)
{
   DmtxEncodeStream streamAscii;
   DmtxByteList output = dmtxByteListBuild(storage, capacity);

   /* Create temporary copy of stream that writes to storage */
   streamAscii = *stream;
   streamAscii.currentScheme = DmtxSchemeAscii;
   streamAscii.outputChainValueCount = 0;
   streamAscii.outputChainWordCount = 0;
   streamAscii.reason = NULL;
   streamAscii.sizeIdx = DmtxUndefined;
   streamAscii.status = DmtxStatusEncoding;
   streamAscii.output = &output;

   while(dmtxByteListHasCapacity(streamAscii.output))
   {
      if(StreamInputHasNext(&streamAscii))
         EncodeNextChunkAscii(&streamAscii, DmtxEncodeNormal); /* No CHKERR */
      else
         break;
   }

   /*
    * We stopped encoding before attempting to write beyond output boundary so
    * any stream errors are truly unexpected. The passFail status indicates
    * whether output.length can be trusted by the calling function.
    */

   if(streamAscii.status == DmtxStatusInvalid || streamAscii.status == DmtxStatusFatal)
      *passFail = DmtxFail;
   else
      *passFail = DmtxPass;

   return output;
}

/**
 * \brief  Randomize 253 state
 * \param  codewordValue
 * \param  codewordPosition
 * \return Randomized value
 */
static DmtxByte
Randomize253State(DmtxByte cwValue, int cwPosition)
{
   int pseudoRandom, tmp;

   pseudoRandom = ((149 * cwPosition) % 253) + 1;
   tmp = cwValue + pseudoRandom;
   if(tmp > 254)
      tmp -= 254;

   assert(tmp >= 0 && tmp < 256);

   return (DmtxByte)tmp;
}
Added jni/libdmtx/dmtxencodebase256.c.










































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2011 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxencodebase256.c
 * \brief Base 256 encoding rules
 */

/**
 *
 *
 */
static void
EncodeNextChunkBase256(DmtxEncodeStream *stream)
{
   DmtxByte value;

   if(StreamInputHasNext(stream))
   {
      value = StreamInputAdvanceNext(stream); CHKERR;
      AppendValueBase256(stream, value); CHKERR;
   }
}

/**
 *
 *
 */
static void
AppendValueBase256(DmtxEncodeStream *stream, DmtxByte value)
{
   CHKSCHEME(DmtxSchemeBase256);

   StreamOutputChainAppend(stream, Randomize255State(value, stream->output->length + 1)); CHKERR;
   stream->outputChainValueCount++;

   UpdateBase256ChainHeader(stream, DmtxUndefined); CHKERR;
}

/**
 * check remaining symbol capacity and remaining codewords
 * if the chain can finish perfectly at the end of symbol data words there is a
 * special one-byte length header value that can be used (i think ... read the
 * spec again before commiting to anything)
 */
static void
CompleteIfDoneBase256(DmtxEncodeStream *stream, int sizeIdxRequest)
{
   int sizeIdx;
   int headerByteCount, outputLength, symbolRemaining;

   if(stream->status == DmtxStatusComplete)
      return;

   if(!StreamInputHasNext(stream))
   {
      headerByteCount = stream->outputChainWordCount - stream->outputChainValueCount;
      assert(headerByteCount == 1 || headerByteCount == 2);

      /* Check for special case where every last symbol word is used */
      if(headerByteCount == 2)
      {
         /* Find symbol size as if headerByteCount was only 1 */
         outputLength = stream->output->length - 1;
         sizeIdx = FindSymbolSize(outputLength, sizeIdxRequest); /* No CHKSIZE */
         if(sizeIdx != DmtxUndefined)
         {
            symbolRemaining = GetRemainingSymbolCapacity(outputLength, sizeIdx);

            if(symbolRemaining == 0)
            {
               /* Perfect fit -- complete encoding */
               UpdateBase256ChainHeader(stream, sizeIdx); CHKERR;
               StreamMarkComplete(stream, sizeIdx);
               return;
            }
         }
      }

      /* Normal case */
      sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE;
      EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchImplicit);
      PadRemainingInAscii(stream, sizeIdx);
      StreamMarkComplete(stream, sizeIdx);
   }
}

/**
 *
 *
 */
static void
UpdateBase256ChainHeader(DmtxEncodeStream *stream, int perfectSizeIdx)
{
   int headerIndex;
   int outputLength;
   int headerByteCount;
   int symbolDataWords;
   DmtxBoolean perfectFit;
   DmtxByte headerValue0;
   DmtxByte headerValue1;

   outputLength = stream->outputChainValueCount;
   headerIndex = stream->output->length - stream->outputChainWordCount;
   headerByteCount = stream->outputChainWordCount - stream->outputChainValueCount;
   perfectFit = (perfectSizeIdx == DmtxUndefined) ? DmtxFalse : DmtxTrue;

   /*
    * If requested perfect fit verify symbol capacity against final length
    */

   if(perfectFit)
   {
      symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, perfectSizeIdx);
      if(symbolDataWords != stream->output->length - 1)
      {
         StreamMarkFatal(stream, DmtxErrorUnknown);
         return;
      }
   }

   /*
    * Adjust header to hold correct number of bytes, not worrying about the
    * values held there until below. Note: Header bytes are not considered
    * scheme "values" so we can insert or remove them without updating the
    * outputChainValueCount.
    */

   if(headerByteCount == 0 && stream->outputChainWordCount == 0)
   {
      /* No output words written yet -- insert single header byte */
      StreamOutputChainAppend(stream, 0); CHKERR;
      headerByteCount++;
   }
   else if(!perfectFit && headerByteCount == 1 && outputLength > 249)
   {
      /* Beyond 249 bytes requires a second header byte */
      Base256OutputChainInsertFirst(stream); CHKERR;
      headerByteCount++;
   }
   else if(perfectFit && headerByteCount == 2)
   {
      /* Encoding to exact end of symbol only requires single byte */
      Base256OutputChainRemoveFirst(stream); CHKERR;
      headerByteCount--;
   }

   /*
    * Encode header byte(s) with current length
    */

   if(!perfectFit && headerByteCount == 1 && outputLength <= 249)
   {
      /* Normal condition for chain length < 250 bytes */
      headerValue0 = Randomize255State(outputLength, headerIndex + 1);
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;
   }
   else if(!perfectFit && headerByteCount == 2 && outputLength > 249)
   {
      /* Normal condition for chain length >= 250 bytes */
      headerValue0 = Randomize255State(outputLength/250 + 249, headerIndex + 1);
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;

      headerValue1 = Randomize255State(outputLength%250, headerIndex + 2);
      StreamOutputSet(stream, headerIndex + 1, headerValue1); CHKERR;
   }
   else if(perfectFit && headerByteCount == 1)
   {
      /* Special condition when Base 256 stays in effect to end of symbol */
      headerValue0 = Randomize255State(0, headerIndex + 1); /* XXX replace magic value 0? */
      StreamOutputSet(stream, headerIndex, headerValue0); CHKERR;
   }
   else
   {
      StreamMarkFatal(stream, DmtxErrorUnknown);
      return;
   }
}

/**
 * insert element at beginning of chain, shifting all following elements forward by one
 * used for binary length changes
 */
static void
Base256OutputChainInsertFirst(DmtxEncodeStream *stream)
{
   DmtxByte value;
   DmtxPassFail passFail;
   int i, chainStart;

   chainStart = stream->output->length - stream->outputChainWordCount;
   dmtxByteListPush(stream->output, 0, &passFail);
   if(passFail == DmtxPass)
   {
      for(i = stream->output->length - 1; i > chainStart; i--)
      {
         value = UnRandomize255State(stream->output->b[i-1], i);
         stream->output->b[i] = Randomize255State(value, i + 1);
      }

      stream->outputChainWordCount++;
   }
   else
   {
      StreamMarkFatal(stream, DmtxErrorUnknown);
   }
}

/**
 * remove first element from chain, shifting all following elements back by one
 * used for binary length changes end condition
 */
static void
Base256OutputChainRemoveFirst(DmtxEncodeStream *stream)
{
   DmtxByte value;
   DmtxPassFail passFail;
   int i, chainStart;

   chainStart = stream->output->length - stream->outputChainWordCount;

   for(i = chainStart; i < stream->output->length - 1; i++)
   {
      value = UnRandomize255State(stream->output->b[i+1], i+2);
      stream->output->b[i] = Randomize255State(value, i + 1);
   }

   dmtxByteListPop(stream->output, &passFail);
   if(passFail == DmtxPass)
      stream->outputChainWordCount--;
   else
      StreamMarkFatal(stream, DmtxErrorUnknown);
}

/**
 * \brief  Randomize 255 state
 * \param  value
 * \param  position
 * \return Randomized value
 */
static DmtxByte
Randomize255State(DmtxByte value, int position)
{
   int pseudoRandom, tmp;

   pseudoRandom = ((149 * position) % 255) + 1;
   tmp = value + pseudoRandom;

   return (tmp <= 255) ? tmp : tmp - 256;
}

/**
 * \brief  Unrandomize 255 state
 * \param  value
 * \param  idx
 * \return Unrandomized value
 */
static unsigned char
UnRandomize255State(unsigned char value, int idx)
{
   int pseudoRandom;
   int tmp;

   pseudoRandom = ((149 * idx) % 255) + 1;
   tmp = value - pseudoRandom;
   if(tmp < 0)
      tmp += 256;

   assert(tmp >= 0 && tmp < 256);

   return (unsigned char)tmp;
}
Added jni/libdmtx/dmtxencodec40textx12.c.


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2011 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxencodec40textx12.c
 * \brief C40/Text/X12 encoding rules
 */

#undef CHKERR
#define CHKERR { if(stream->status != DmtxStatusEncoding) { return; } }

#undef CHKSIZE
#define CHKSIZE { if(sizeIdx == DmtxUndefined) { StreamMarkInvalid(stream, DmtxErrorUnknown); return; } }

#undef CHKPASS
#define CHKPASS { if(passFail == DmtxFail) { StreamMarkFatal(stream, DmtxErrorUnknown); return; } }

#undef RETURN_IF_FAIL
#define RETURN_IF_FAIL { if(*passFail == DmtxFail) return; }

/**
 *
 *
 */
static void
EncodeNextChunkCTX(DmtxEncodeStream *stream, int sizeIdxRequest)
{
   DmtxPassFail passFail;
   DmtxByte inputValue;
   DmtxByte valueListStorage[6];
   DmtxByteList valueList = dmtxByteListBuild(valueListStorage, sizeof(valueListStorage));

   while(StreamInputHasNext(stream))
   {
      inputValue = StreamInputAdvanceNext(stream); CHKERR;

      /* Expand next input value into up to 4 CTX values and add to valueList */
      PushCTXValues(&valueList, inputValue, stream->currentScheme, &passFail);
      if(passFail == DmtxFail)
      {
         /* XXX Perhaps PushCTXValues should return this error code */
         StreamMarkInvalid(stream, DmtxErrorUnsupportedCharacter);
         return;
      }

      /* If there at least 3 CTX values available encode them to output */
      while(valueList.length >= 3)
      {
         AppendValuesCTX(stream, &valueList); CHKERR;
         ShiftValueListBy3(&valueList, &passFail); CHKPASS;
      }

      /* Finished on byte boundary -- done with current chunk */
      if(valueList.length == 0)
         break;
   }

   /*
    * Special case: If all input values have been consumed and 1 or 2 unwritten
    * C40/Text/X12 values remain, finish encoding the symbol according to the
    * established end-of-symbol conditions.
    */
   if(!StreamInputHasNext(stream) && valueList.length > 0)
   {
      if(stream->currentScheme == DmtxSchemeX12)
      {
         CompletePartialX12(stream, &valueList, sizeIdxRequest); CHKERR;
      }
      else
      {
         CompletePartialC40Text(stream, &valueList, sizeIdxRequest); CHKERR;
      }
   }
}

/**
 *
 *
 */
static void
AppendValuesCTX(DmtxEncodeStream *stream, DmtxByteList *valueList)
{
   int pairValue;
   DmtxByte cw0, cw1;

   if(!IsCTX(stream->currentScheme))
   {
      StreamMarkFatal(stream, DmtxErrorUnexpectedScheme);
      return;
   }

   if(valueList->length < 3)
   {
      StreamMarkFatal(stream, DmtxErrorIncompleteValueList);
      return;
   }

   /* Build codewords from computed value */
   pairValue = (1600 * valueList->b[0]) + (40 * valueList->b[1]) + valueList->b[2] + 1;
   cw0 = pairValue / 256;
   cw1 = pairValue % 256;

   /* Append 2 codewords */
   StreamOutputChainAppend(stream, cw0); CHKERR;
   StreamOutputChainAppend(stream, cw1); CHKERR;

   /* Update count for 3 encoded values */
   stream->outputChainValueCount += 3;
}

/**
 *
 *
 */
static void
AppendUnlatchCTX(DmtxEncodeStream *stream)
{
   if(!IsCTX(stream->currentScheme))
   {
      StreamMarkFatal(stream, DmtxErrorUnexpectedScheme);
      return;
   }

   /* Verify we are on byte boundary */
   if(stream->outputChainValueCount % 3 != 0)
   {
      StreamMarkInvalid(stream, DmtxErrorNotOnByteBoundary);
      return;
   }

   StreamOutputChainAppend(stream, DmtxValueCTXUnlatch); CHKERR;

   stream->outputChainValueCount++;
}

/**
 * Complete C40/Text/X12 encoding if it matches a known end-of-symbol condition.
 *
 *   Term  Trip  Symbol  Codeword
 *   Cond  Size  Remain  Sequence
 *   ----  ----  ------  -----------------------
 *    (a)     3       2  Special case
 *            -       -  UNLATCH [PAD]
 */
static void
CompleteIfDoneCTX(DmtxEncodeStream *stream, int sizeIdxRequest)
{
   int sizeIdx;
   int symbolRemaining;

   if(stream->status == DmtxStatusComplete)
      return;

   if(!StreamInputHasNext(stream))
   {
      sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE;
      symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx);

      if(symbolRemaining > 0)
      {
         EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR;
         PadRemainingInAscii(stream, sizeIdx);
      }

      StreamMarkComplete(stream, sizeIdx);
   }
}

/**
 * The remaining values can exist in 3 possible cases:
 *
 *   a) 1 C40/Text/X12 remaining == 1 data
 *   b) 2 C40/Text/X12 remaining == 1 shift + 1 data
 *   c) 2 C40/Text/X12 remaining == 1 data +  1 data
 *
 * To distinguish between cases (b) and (c), encode the final input value to
 * C40/Text/X12 in a temporary location and check the resulting length. If
 * it expands to multiple values it represents (b); otherwise it is (c). This
 * accounts for both shift and upper shift conditions.
 *
 * Note that in cases (a) and (c) the final C40/Text/X12 value encoded in the
 * previous chunk may have been a shift value, but this will be ignored by
 * the decoder due to the implicit shift to ASCII. <-- what if symbol is much
 * larger though?
 *
 *   Term    Value  Symbol  Codeword
 *   Cond    Count  Remain  Sequence
 *   ----  -------  ------  ------------------------
 *    (b)    C40 2       2  C40+C40+0
 *    (d)  ASCII 1       1  ASCII (implicit unlatch)
 *    (c)  ASCII 1       2  UNLATCH ASCII
 *               -       -  UNLATCH (finish ASCII)
 */
static void
CompletePartialC40Text(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest)
{
   int i;
   int sizeIdx1, sizeIdx2;
   int symbolRemaining1, symbolRemaining2;
   DmtxPassFail passFail;
   DmtxByte inputValue;
   DmtxByte outputTmpStorage[4];
   DmtxByteList outputTmp = dmtxByteListBuild(outputTmpStorage, sizeof(outputTmpStorage));

   if(stream->currentScheme != DmtxSchemeC40 && stream->currentScheme != DmtxSchemeText)
   {
      StreamMarkFatal(stream, DmtxErrorUnexpectedScheme);
      return;
   }

   /* Should have exactly one or two input values left */
   assert(valueList->length == 1 || valueList->length == 2);

   sizeIdx1 = FindSymbolSize(stream->output->length + 1, sizeIdxRequest);
   sizeIdx2 = FindSymbolSize(stream->output->length + 2, sizeIdxRequest);

   symbolRemaining1 = GetRemainingSymbolCapacity(stream->output->length, sizeIdx1);
   symbolRemaining2 = GetRemainingSymbolCapacity(stream->output->length, sizeIdx2);

   if(valueList->length == 2 && symbolRemaining2 == 2)
   {
      /* End of symbol condition (b) -- Use Shift1 to pad final list value */
      dmtxByteListPush(valueList, DmtxValueCTXShift1, &passFail); CHKPASS;
      AppendValuesCTX(stream, valueList); CHKERR;
      StreamMarkComplete(stream, sizeIdx2);
   }
   else
   {
      /*
       * Rollback progress of previously consumed input value(s) since ASCII
       * encoder will be used to finish the symbol. 2 rollbacks are needed if
       * valueList holds 2 data words (i.e., not shifts or upper shifts).
       */

      StreamInputAdvancePrev(stream); CHKERR;
      inputValue = StreamInputPeekNext(stream); CHKERR;

      /* Test-encode most recently consumed input value to C40/Text/X12 */
      PushCTXValues(&outputTmp, inputValue, stream->currentScheme, &passFail);
      if(valueList->length == 2 && outputTmp.length == 1)
         StreamInputAdvancePrev(stream); CHKERR;

      /* Re-use outputTmp to hold ASCII representation of 1-2 input values */
      /* XXX Refactor how the DmtxByteList is passed back here */
      outputTmp = EncodeTmpRemainingInAscii(stream, outputTmpStorage,
            sizeof(outputTmpStorage), &passFail);

      if(passFail == DmtxFail)
      {
         StreamMarkFatal(stream, DmtxErrorUnknown);
         return;
      }

      if(outputTmp.length == 1 && symbolRemaining1 == 1)
      {
         /* End of symbol condition (d) */
         EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchImplicit); CHKERR;
         AppendValueAscii(stream, outputTmp.b[0]); CHKERR;

         /* Register progress since encoding happened outside normal path */
         stream->inputNext = stream->input->length;
         StreamMarkComplete(stream, sizeIdx1);
      }
      else
      {
         /* Finish in ASCII (c) */
         EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR;
         for(i = 0; i < outputTmp.length; i++)
            AppendValueAscii(stream, outputTmp.b[i]); CHKERR;

         sizeIdx1 = FindSymbolSize(stream->output->length, sizeIdxRequest);
         PadRemainingInAscii(stream, sizeIdx1);

         /* Register progress since encoding happened outside normal path */
         stream->inputNext = stream->input->length;
         StreamMarkComplete(stream, sizeIdx1);
      }
   }
}

/**
 * Partial chunks are not valid in X12. Encode using ASCII instead, using
 * an implied unlatch if there is exactly one ascii codeword and one symbol
 * codeword remaining. Otherwise use explicit unlatch.
 */
static void
CompletePartialX12(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest)
{
   int i;
   int sizeIdx;
   int symbolRemaining;
   DmtxPassFail passFail;
   DmtxByte outputTmpStorage[2];
   DmtxByteList outputTmp;

   if(stream->currentScheme != DmtxSchemeX12)
   {
      StreamMarkFatal(stream, DmtxErrorUnexpectedScheme);
      return;
   }

   /* Should have exactly one or two input values left */
   assert(valueList->length == 1 || valueList->length == 2);

   /* Roll back input progress */
   for(i = 0; i < valueList->length; i++)
   {
      StreamInputAdvancePrev(stream); CHKERR;
   }

   /* Encode up to 2 codewords to a temporary stream */
   outputTmp = EncodeTmpRemainingInAscii(stream, outputTmpStorage,
         sizeof(outputTmpStorage), &passFail);

   sizeIdx = FindSymbolSize(stream->output->length + 1, sizeIdxRequest);
   symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx);

   if(outputTmp.length == 1 && symbolRemaining == 1)
   {
      /* End of symbol condition (XXX) */
      EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchImplicit); CHKERR;
      AppendValueAscii(stream, outputTmp.b[0]); CHKERR;

      /* Register progress since encoding happened outside normal path */
      stream->inputNext = stream->input->length;
      StreamMarkComplete(stream, sizeIdx);
   }
   else
   {
      /* Finish in ASCII (XXX) */
      EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR;
      for(i = 0; i < outputTmp.length; i++)
         AppendValueAscii(stream, outputTmp.b[i]); CHKERR;

      sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest);
      PadRemainingInAscii(stream, sizeIdx);

      /* Register progress since encoding happened outside normal path */
      stream->inputNext = stream->input->length;
      StreamMarkComplete(stream, sizeIdx);
   }
}

/**
 * Return DmtxTrue 1 or 2 X12 values remain, otherwise DmtxFalse
 */
static DmtxBoolean
PartialX12ChunkRemains(DmtxEncodeStream *stream)
{
   DmtxEncodeStream streamTmp;
   DmtxByte inputValue;
   DmtxByte valueListStorage[6];
   DmtxByteList valueList = dmtxByteListBuild(valueListStorage, sizeof(valueListStorage));
   DmtxPassFail passFail;

   /* Create temporary copy of stream to track test input progress */
   streamTmp = *stream;
   streamTmp.currentScheme = DmtxSchemeX12;
   streamTmp.outputChainValueCount = 0;
   streamTmp.outputChainWordCount = 0;
   streamTmp.reason = NULL;
   streamTmp.sizeIdx = DmtxUndefined;
   streamTmp.status = DmtxStatusEncoding;
   streamTmp.output = NULL;

   while(StreamInputHasNext(&streamTmp))
   {
      inputValue = StreamInputAdvanceNext(&streamTmp);
      if(stream->status != DmtxStatusEncoding)
      {
         StreamMarkInvalid(stream, DmtxErrorUnknown);
         return DmtxFalse;
      }

      /* Expand next input value into up to 4 CTX values and add to valueList */
      PushCTXValues(&valueList, inputValue, streamTmp.currentScheme, &passFail);
      if(passFail == DmtxFail)
      {
         StreamMarkInvalid(stream, DmtxErrorUnknown);
         return DmtxFalse;
      }

      /* Not a final partial chunk */
      if(valueList.length >= 3)
         return DmtxFalse;
   }

   return (valueList.length == 0) ? DmtxFalse : DmtxTrue;
}

/**
 *
 *
 */
static void
PushCTXValues(DmtxByteList *valueList, DmtxByte inputValue, int targetScheme,
      DmtxPassFail *passFail)
{
   assert(valueList->length <= 2);

   /* Handle extended ASCII with Upper Shift character */
   if(inputValue > 127)
   {
      if(targetScheme == DmtxSchemeX12)
      {
         *passFail = DmtxFail;
         return;
      }
      else
      {
         dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail); RETURN_IF_FAIL;
         dmtxByteListPush(valueList, 30, passFail); RETURN_IF_FAIL;
         inputValue -= 128;
      }
   }

   /* Handle all other characters according to encodation scheme */
   if(targetScheme == DmtxSchemeX12)
   {
      if(inputValue == 13)
      {
         dmtxByteListPush(valueList, 0, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue == 42)
      {
         dmtxByteListPush(valueList, 1, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue == 62)
      {
         dmtxByteListPush(valueList, 2, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue == 32)
      {
         dmtxByteListPush(valueList, 3, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue >= 48 && inputValue <= 57)
      {
         dmtxByteListPush(valueList, inputValue - 44, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue >= 65 && inputValue <= 90)
      {
         dmtxByteListPush(valueList, inputValue - 51, passFail); RETURN_IF_FAIL;
      }
      else
      {
         *passFail = DmtxFail;
         return;
      }
   }
   else
   {
      /* targetScheme is C40 or Text */
      if(inputValue <= 31)
      {
         dmtxByteListPush(valueList, DmtxValueCTXShift1, passFail); RETURN_IF_FAIL;
         dmtxByteListPush(valueList, inputValue, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue == 32)
      {
         dmtxByteListPush(valueList, 3, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue <= 47)
      {
         dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail); RETURN_IF_FAIL;
         dmtxByteListPush(valueList, inputValue - 33, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue <= 57)
      {
         dmtxByteListPush(valueList, inputValue - 44, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue <= 64)
      {
         dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail); RETURN_IF_FAIL;
         dmtxByteListPush(valueList, inputValue - 43, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue <= 90 && targetScheme == DmtxSchemeC40)
      {
         dmtxByteListPush(valueList, inputValue - 51, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue <= 90 && targetScheme == DmtxSchemeText)
      {
         dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail); RETURN_IF_FAIL;
         dmtxByteListPush(valueList, inputValue - 64, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue <= 95)
      {
         dmtxByteListPush(valueList, DmtxValueCTXShift2, passFail); RETURN_IF_FAIL;
         dmtxByteListPush(valueList, inputValue - 69, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue == 96 && targetScheme == DmtxSchemeText)
      {
         dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail); RETURN_IF_FAIL;
         dmtxByteListPush(valueList, 0, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue <= 122 && targetScheme == DmtxSchemeText)
      {
         dmtxByteListPush(valueList, inputValue - 83, passFail); RETURN_IF_FAIL;
      }
      else if(inputValue <= 127)
      {
         dmtxByteListPush(valueList, DmtxValueCTXShift3, passFail); RETURN_IF_FAIL;
         dmtxByteListPush(valueList, inputValue - 96, passFail); RETURN_IF_FAIL;
      }
      else
      {
         *passFail = DmtxFail;
         return;
      }
   }

   *passFail = DmtxPass;
}

/**
 *
 *
 */
static DmtxBoolean
IsCTX(int scheme)
{
   DmtxBoolean isCTX;

   if(scheme == DmtxSchemeC40 || scheme == DmtxSchemeText || scheme == DmtxSchemeX12)
      isCTX = DmtxTrue;
   else
      isCTX = DmtxFalse;

   return isCTX;
}

/**
 *
 *
 */
static void
ShiftValueListBy3(DmtxByteList *list, DmtxPassFail *passFail)
{
   int i;

   /* Shift values */
   for(i = 0; i < list->length - 3; i++)
      list->b[i] = list->b[i+3];

   /* Shorten list by 3 (or less) */
   for(i = 0; i < 3; i++)
   {
      dmtxByteListPop(list, passFail);
      if(*passFail == DmtxFail)
         return;

      if(list->length == 0)
         break;
   }

   *passFail = DmtxPass;
}
Added jni/libdmtx/dmtxencodeedifact.c.












































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2011 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxencodeedifact.c
 * \brief Edifact encoding rules
 */

/**
 *
 *
 */
static void
EncodeNextChunkEdifact(DmtxEncodeStream *stream)
{
   DmtxByte value;

   if(StreamInputHasNext(stream))
   {
      value = StreamInputAdvanceNext(stream); CHKERR;
      AppendValueEdifact(stream, value); CHKERR;
   }
}

/**
 *
 *
 */
static void
AppendValueEdifact(DmtxEncodeStream *stream, DmtxByte value)
{
   DmtxByte edifactValue, previousOutput;

   CHKSCHEME(DmtxSchemeEdifact);

   if(value < 31 || value > 94)
   {
      StreamMarkInvalid(stream, DmtxChannelUnsupportedChar);
      return;
   }

   edifactValue = (value & 0x3f) << 2;

   switch(stream->outputChainValueCount % 4)
   {
      case 0:
         StreamOutputChainAppend(stream, edifactValue); CHKERR;
         break;
      case 1:
         previousOutput = StreamOutputChainRemoveLast(stream); CHKERR;
         StreamOutputChainAppend(stream, previousOutput | (edifactValue >> 6)); CHKERR;
         StreamOutputChainAppend(stream, edifactValue << 2); CHKERR;
         break;
      case 2:
         previousOutput = StreamOutputChainRemoveLast(stream); CHKERR;
         StreamOutputChainAppend(stream, previousOutput | (edifactValue >> 4)); CHKERR;
         StreamOutputChainAppend(stream, edifactValue << 4); CHKERR;
         break;
      case 3:
         previousOutput = StreamOutputChainRemoveLast(stream); CHKERR;
         StreamOutputChainAppend(stream, previousOutput | (edifactValue >> 2)); CHKERR;
         break;
   }

   stream->outputChainValueCount++;
}

/**
 * Complete EDIFACT encoding if it matches a known end-of-symbol condition.
 *
 *   Term  Clean  Symbol  ASCII   Codeword
 *   Cond  Bound  Remain  Remain  Sequence
 *   ----  -----  ------  ------  -----------
 *    (a)      Y       0       0  [none]
 *    (b)      Y       1       0  PAD
 *    (c)      Y       1       1  ASCII
 *    (d)      Y       2       0  PAD PAD
 *    (e)      Y       2       1  ASCII PAD
 *    (f)      Y       2       2  ASCII ASCII
 *             -       -       0  UNLATCH
 *
 * If not matching any of the above, continue without doing anything.
 */
static void
CompleteIfDoneEdifact(DmtxEncodeStream *stream, int sizeIdxRequest)
{
   int i;
   int sizeIdx;
   int symbolRemaining;
   DmtxBoolean cleanBoundary;
   DmtxPassFail passFail;
   DmtxByte outputTmpStorage[3];
   DmtxByteList outputTmp;

   if(stream->status == DmtxStatusComplete)
      return;

   /*
    * If we just completed a triplet (cleanBoundary), 1 or 2 symbol codewords
    * remain, and our remaining inputs (if any) represented in ASCII would fit
    * in the remaining space, encode them in ASCII with an implicit unlatch.
    */

   cleanBoundary = (stream->outputChainValueCount % 4 == 0) ? DmtxTrue : DmtxFalse;

   if(cleanBoundary == DmtxTrue)
   {
      /* Encode up to 3 codewords to a temporary stream */
      outputTmp = EncodeTmpRemainingInAscii(stream, outputTmpStorage,
            sizeof(outputTmpStorage), &passFail);

      if(passFail == DmtxFail)
      {
         StreamMarkFatal(stream, DmtxErrorUnknown);
         return;
      }

      if(outputTmp.length < 3)
      {
         /* Find minimum symbol size for projected length */
         sizeIdx = FindSymbolSize(stream->output->length + outputTmp.length, sizeIdxRequest); CHKSIZE;

         /* Find remaining capacity over current length */
         symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx); CHKERR;

         if(symbolRemaining < 3 && outputTmp.length <= symbolRemaining)
         {
            EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchImplicit); CHKERR;

            for(i = 0; i < outputTmp.length; i++)
            {
               AppendValueAscii(stream, outputTmp.b[i]); CHKERR;
            }

            /* Register progress since encoding happened outside normal path */
            stream->inputNext = stream->input->length;

            /* Pad remaining if necessary */
            PadRemainingInAscii(stream, sizeIdx); CHKERR;
            StreamMarkComplete(stream, sizeIdx);
            return;
         }
      }
   }

   if(!StreamInputHasNext(stream))
   {
      sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE;
      symbolRemaining = GetRemainingSymbolCapacity(stream->output->length, sizeIdx); CHKERR;

      /* Explicit unlatch required unless on clean boundary and full symbol */
      if(cleanBoundary == DmtxFalse || symbolRemaining > 0)
      {
         EncodeChangeScheme(stream, DmtxSchemeAscii, DmtxUnlatchExplicit); CHKERR;
         sizeIdx = FindSymbolSize(stream->output->length, sizeIdxRequest); CHKSIZE;
         PadRemainingInAscii(stream, sizeIdx); CHKERR;
      }

      StreamMarkComplete(stream, sizeIdx);
   }
}
Added jni/libdmtx/dmtxencodeoptimize.c.






























































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2011 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxencodeoptimize.c
 * \brief Logic for optimized (multiple scheme) encoding
 */

enum SchemeState {
   AsciiFull,
   AsciiCompactOffset0, /* 0 offset from first regular input value */
   AsciiCompactOffset1,
   C40Offset0,          /* 0 offset from first expanded C40 value */
   C40Offset1,
   C40Offset2,
   TextOffset0,         /* 0 offset from first expanded Text value */
   TextOffset1,
   TextOffset2,
   X12Offset0,          /* 0 offset from first expanded X12 value */
   X12Offset1,
   X12Offset2,
   EdifactOffset0,      /* 0 offset from first regular input value */
   EdifactOffset1,
   EdifactOffset2,
   EdifactOffset3,
   Base256,
   SchemeStateCount
};

/** temporary
static void DumpStreams(DmtxEncodeStream *streamBest)
{
   enum SchemeState state;
   char prefix[32];

   fprintf(stdout, "----------------------------------------\n");
   for(state = 0; state < SchemeStateCount; state++)
   {
      if(streamBest[state].status == DmtxStatusEncoding ||
            streamBest[state].status == DmtxStatusComplete)
         fprintf(stdout, "\"%c\" ", streamBest[state].input->b[streamBest[state].inputNext-1]);
      else
         fprintf(stdout, "    ");

      switch(streamBest[state].status) {
         case DmtxStatusEncoding:
            snprintf(prefix, sizeof(prefix), "%2d (%s): ", state, " encode ");
            break;
         case DmtxStatusComplete:
            snprintf(prefix, sizeof(prefix), "%2d (%s): ", state, "complete");
            break;
         case DmtxStatusInvalid:
            snprintf(prefix, sizeof(prefix), "%2d (%s): ", state, "invalid ");
            break;
         case DmtxStatusFatal:
            snprintf(prefix, sizeof(prefix), "%2d (%s): ", state, " fatal  ");
            break;
      }
      dmtxByteListPrint(streamBest[state].output, prefix);
   }
}
*/

/**
 *
 *
 */
static int
EncodeOptimizeBest(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest)
{
   enum SchemeState state;
   int inputNext, c40ValueCount, textValueCount, x12ValueCount;
   int sizeIdx;
   DmtxEncodeStream *winner;
   DmtxPassFail passFail;
   DmtxEncodeStream streamsBest[SchemeStateCount];
   DmtxEncodeStream streamsTemp[SchemeStateCount];
   DmtxByte outputsBestStorage[SchemeStateCount][4096];
   DmtxByte outputsTempStorage[SchemeStateCount][4096];
   DmtxByte ctxTempStorage[4];
   DmtxByteList outputsBest[SchemeStateCount];
   DmtxByteList outputsTemp[SchemeStateCount];
   DmtxByteList ctxTemp = dmtxByteListBuild(ctxTempStorage, sizeof(ctxTempStorage));

   /* Initialize all streams with their own output storage */
   for(state = 0; state < SchemeStateCount; state++)
   {
      outputsBest[state] = dmtxByteListBuild(outputsBestStorage[state], sizeof(outputsBestStorage[state]));
      outputsTemp[state] = dmtxByteListBuild(outputsTempStorage[state], sizeof(outputsTempStorage[state]));
      streamsBest[state] = StreamInit(input, &(outputsBest[state]));
      streamsTemp[state] = StreamInit(input, &(outputsTemp[state]));
   }

   c40ValueCount = textValueCount = x12ValueCount = 0;

   for(inputNext = 0; inputNext < input->length; inputNext++)
   {
      StreamAdvanceFromBest(streamsTemp, streamsBest, AsciiFull, sizeIdxRequest);

      AdvanceAsciiCompact(streamsTemp, streamsBest, AsciiCompactOffset0, inputNext, sizeIdxRequest);
      AdvanceAsciiCompact(streamsTemp, streamsBest, AsciiCompactOffset1, inputNext, sizeIdxRequest);

      AdvanceCTX(streamsTemp, streamsBest, C40Offset0, inputNext, c40ValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, C40Offset1, inputNext, c40ValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, C40Offset2, inputNext, c40ValueCount, sizeIdxRequest);

      AdvanceCTX(streamsTemp, streamsBest, TextOffset0, inputNext, textValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, TextOffset1, inputNext, textValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, TextOffset2, inputNext, textValueCount, sizeIdxRequest);

      AdvanceCTX(streamsTemp, streamsBest, X12Offset0, inputNext, x12ValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, X12Offset1, inputNext, x12ValueCount, sizeIdxRequest);
      AdvanceCTX(streamsTemp, streamsBest, X12Offset2, inputNext, x12ValueCount, sizeIdxRequest);

      AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset0, inputNext, sizeIdxRequest);
      AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset1, inputNext, sizeIdxRequest);
      AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset2, inputNext, sizeIdxRequest);
      AdvanceEdifact(streamsTemp, streamsBest, EdifactOffset3, inputNext, sizeIdxRequest);

      StreamAdvanceFromBest(streamsTemp, streamsBest, Base256, sizeIdxRequest);

      /* Overwrite best streams with new results */
      for(state = 0; state < SchemeStateCount; state++)
      {
         if(streamsBest[state].status != DmtxStatusComplete)
            StreamCopy(&(streamsBest[state]), &(streamsTemp[state]));
      }

      dmtxByteListClear(&ctxTemp);
      PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeC40, &passFail);
      c40ValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);

      dmtxByteListClear(&ctxTemp);
      PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeText, &passFail);
      textValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);

      dmtxByteListClear(&ctxTemp);
      PushCTXValues(&ctxTemp, input->b[inputNext], DmtxSchemeX12, &passFail);
      x12ValueCount += ((passFail == DmtxPass) ? ctxTemp.length : 1);

/*    DumpStreams(streamsBest); */
   }

   /* Choose the overall winner */
   winner = NULL;
   for(state = 0; state < SchemeStateCount; state++)
   {
      if(streamsBest[state].status == DmtxStatusComplete)
      {
         if(winner == NULL || streamsBest[state].output->length < winner->output->length)
            winner = &(streamsBest[state]);
      }
   }

   /* Copy winner to output */
   if(winner == NULL)
   {
      sizeIdx = DmtxUndefined;
   }
   else
   {
      dmtxByteListCopy(output, winner->output, &passFail);
      sizeIdx = (passFail == DmtxPass) ? winner->sizeIdx : DmtxUndefined;
   }

   return sizeIdx;
}

/**
 * It's safe to compare output length because all targetState combinations
 * start on same input and encodes same number of inputs. Only difference
 * is the number of latches/unlatches that are also encoded
 */
static void
StreamAdvanceFromBest(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest,
     int targetState, int sizeIdxRequest)
{
   enum SchemeState fromState;
   DmtxScheme targetScheme;
   DmtxEncodeOption encodeOption;
   DmtxByte outputTempStorage[4096];
   DmtxByteList outputTemp = dmtxByteListBuild(outputTempStorage, sizeof(outputTempStorage));
   DmtxEncodeStream streamTemp;
   DmtxEncodeStream *targetStream = &(streamsNext[targetState]);

   streamTemp.output = &outputTemp; /* Set directly instead of calling StreamInit() */
   targetScheme = GetScheme(targetState);

   if(targetState == AsciiFull)
      encodeOption = DmtxEncodeFull;
   else if(targetState == AsciiCompactOffset0 || targetState == AsciiCompactOffset1)
      encodeOption = DmtxEncodeCompact;
   else
      encodeOption = DmtxEncodeNormal;

   for(fromState = 0; fromState < SchemeStateCount; fromState++)
   {
      if(streamsBest[fromState].status != DmtxStatusEncoding ||
            ValidStateSwitch(fromState, targetState) == DmtxFalse)
      {
         continue;
      }

      StreamCopy(&streamTemp, &(streamsBest[fromState]));
      EncodeNextChunk(&streamTemp, targetScheme, encodeOption, sizeIdxRequest);

      if(fromState == 0 || (streamTemp.status != DmtxStatusInvalid &&
            streamTemp.output->length < targetStream->output->length))
      {
         StreamCopy(targetStream, &streamTemp);
      }
   }
}

/**
 *
 */
static void
AdvanceAsciiCompact(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest,
      int targetState, int inputNext, int sizeIdxRequest)
{
   DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
   DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
   DmtxBoolean isStartState;

   switch(targetState)
   {
      case AsciiCompactOffset0:
         isStartState = (inputNext % 2 == 0) ? DmtxTrue : DmtxFalse;
         break;

      case AsciiCompactOffset1:
         isStartState = (inputNext % 2 == 1) ? DmtxTrue : DmtxFalse;
         break;

      default:
         StreamMarkFatal(targetStream, DmtxErrorIllegalParameterValue);
         return;
   }

   if(inputNext < currentStream->inputNext)
   {
      StreamCopy(targetStream, currentStream);
   }
   else if(isStartState == DmtxTrue)
   {
      StreamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
   }
   else
   {
      StreamCopy(targetStream, currentStream);
      StreamMarkInvalid(targetStream, DmtxErrorUnknown);
   }
}

/**
 *
 */
static void
AdvanceCTX(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest,
      int targetState, int inputNext, int ctxValueCount, int sizeIdxRequest)
{
   DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
   DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
   DmtxBoolean isStartState;

   /* we won't actually use inputNext here */
   switch(targetState)
   {
      case C40Offset0:
      case TextOffset0:
      case X12Offset0:
         isStartState = (ctxValueCount % 3 == 0) ? DmtxTrue : DmtxFalse;
         break;

      case C40Offset1:
      case TextOffset1:
      case X12Offset1:
         isStartState = (ctxValueCount % 3 == 1) ? DmtxTrue : DmtxFalse;
         break;

      case C40Offset2:
      case TextOffset2:
      case X12Offset2:
         isStartState = (ctxValueCount % 3 == 2) ? DmtxTrue : DmtxFalse;
         break;

      default:
         StreamMarkFatal(targetStream, DmtxErrorIllegalParameterValue);
         return;
   }

   if(inputNext < currentStream->inputNext)
   {
      StreamCopy(targetStream, currentStream);
   }
   else if(isStartState == DmtxTrue)
   {
      StreamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
   }
   else
   {
      StreamCopy(targetStream, currentStream);
      StreamMarkInvalid(targetStream, DmtxErrorUnknown);
   }
}

/**
 *
 */
static void
AdvanceEdifact(DmtxEncodeStream *streamsNext, DmtxEncodeStream *streamsBest,
      int targetState, int inputNext, int sizeIdxRequest)
{
   DmtxEncodeStream *currentStream = &(streamsBest[targetState]);
   DmtxEncodeStream *targetStream = &(streamsNext[targetState]);
   DmtxBoolean isStartState;

   switch(targetState)
   {
      case EdifactOffset0:
         isStartState = (inputNext % 4 == 0) ? DmtxTrue : DmtxFalse;
         break;

      case EdifactOffset1:
         isStartState = (inputNext % 4 == 1) ? DmtxTrue : DmtxFalse;
         break;

      case EdifactOffset2:
         isStartState = (inputNext % 4 == 2) ? DmtxTrue : DmtxFalse;
         break;

      case EdifactOffset3:
         isStartState = (inputNext % 4 == 3) ? DmtxTrue : DmtxFalse;
         break;

      default:
         StreamMarkFatal(targetStream, DmtxErrorIllegalParameterValue);
         return;
   }

   if(isStartState == DmtxTrue)
   {
      StreamAdvanceFromBest(streamsNext, streamsBest, targetState, sizeIdxRequest);
   }
   else
   {
      StreamCopy(targetStream, currentStream);
      if(currentStream->status == DmtxStatusEncoding && currentStream->currentScheme == DmtxSchemeEdifact)
         EncodeNextChunk(targetStream, DmtxSchemeEdifact, DmtxEncodeNormal, sizeIdxRequest);
      else
         StreamMarkInvalid(targetStream, DmtxErrorUnknown);
   }
}

/**
 *
 *
 */
static int
GetScheme(int state)
{
   DmtxScheme scheme;

   switch(state)
   {
      case AsciiFull:
      case AsciiCompactOffset0:
      case AsciiCompactOffset1:
         scheme = DmtxSchemeAscii;
         break;
      case C40Offset0:
      case C40Offset1:
      case C40Offset2:
         scheme = DmtxSchemeC40;
         break;
      case TextOffset0:
      case TextOffset1:
      case TextOffset2:
         scheme = DmtxSchemeText;
         break;
      case X12Offset0:
      case X12Offset1:
      case X12Offset2:
         scheme = DmtxSchemeX12;
         break;
      case EdifactOffset0:
      case EdifactOffset1:
      case EdifactOffset2:
      case EdifactOffset3:
         scheme = DmtxSchemeEdifact;
         break;
      case Base256:
         scheme = DmtxSchemeBase256;
         break;
      default:
         scheme = DmtxUndefined;
         break;
   }

   return scheme;
}

/**
 *
 *
 */
static DmtxBoolean
ValidStateSwitch(int fromState, int targetState)
{
   DmtxBoolean validStateSwitch;
   DmtxScheme fromScheme = GetScheme(fromState);
   DmtxScheme toScheme = GetScheme(targetState);

   if(fromScheme == toScheme && fromState != targetState &&
         fromState != AsciiFull && targetState != AsciiFull)
   {
      validStateSwitch = DmtxFalse;
   }
   else
   {
      validStateSwitch = DmtxTrue;
   }

   return validStateSwitch;
}
Added jni/libdmtx/dmtxencodescheme.c.


















































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2011 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxencodescheme.c
 * \brief Logic for encoding in single scheme
 */

/**
 * In this file:
 *
 * A "word" refers to a full codeword byte to be appended to the encoded output.
 *
 * A "value" refers to any scheme value being appended to the output stream,
 * regardless of how many bytes are used to represent it. Examples:
 *
 *   ASCII:                   1 value  in  1 codeword
 *   ASCII (digits):          2 values in  1 codeword
 *   C40/Text/X12:            3 values in  2 codewords
 *   C40/Text/X12 (unlatch):  1 values in  1 codeword
 *   EDIFACT:                 4 values in  3 codewords
 *   Base 256:                1 value  in  1 codeword
 *
 *   * Shifts count as values, so outputChainValueCount will reflect these.
 *
 *   * Latches and unlatches are also counted as values, but always in the
 *     scheme being exited.
 *
 *   * Base256 header bytes are not included as values.
 *
 * A "chunk" refers to the minimum grouping of values in a schema that must be
 * encoded together.
 *
 *   ASCII:                   1 value  (1 codeword)  in 1 chunk
 *   ASCII (digits):          2 values (1 codeword)  in 1 chunk (optional)
 *   C40/Text/X12:            3 values (2 codewords) in 1 chunk
 *   C40/Text/X12 (unlatch):  1 value  (1 codeword)  in 1 chunk
 *   EDIFACT:                 1 value  (1 codeword*) in 1 chunk
 *   Base 256:                1 value  (1 codeword)  in 1 chunk
 *
 *   * EDIFACT writes 6 bits at a time, but progress is tracked to the next byte
 *     boundary. If unlatch value finishes mid-byte, the remaining bits before
 *     the next boundary are set to zero.
 *
 * Each scheme implements 3 equivalent functions:
 *   * EncodeNextChunk[Scheme]
 *   * AppendValue[Scheme]
 *   * CompleteIfDone[Scheme]
 *
 * The function EncodeNextChunk() (no Scheme in the name) knows which scheme-
 * specific implementations to call based on the stream's current encodation
 * scheme.
 *
 * It's important that EncodeNextChunk[Scheme] not call CompleteIfDone[Scheme]
 * directly because some parts of the logic might want to encode a stream
 * without allowing the padding and other extra logic that can occur when an
 * end-of-symbol condition is triggered.
 */

/* Verify stream is using expected scheme */
#define CHKSCHEME(s) { \
   if(stream->currentScheme != (s)) { StreamMarkFatal(stream, DmtxErrorUnexpectedScheme); return; } \
}

/* CHKERR should follow any call that might alter stream status */
#define CHKERR { \
   if(stream->status != DmtxStatusEncoding) { return; } \
}

/* CHKSIZE should follows typical calls to FindSymbolSize()  */
#define CHKSIZE { \
   if(sizeIdx == DmtxUndefined) { StreamMarkInvalid(stream, DmtxErrorUnknown); return; } \
}

/**
 *
 *
 */
static int
EncodeSingleScheme(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest, DmtxScheme scheme)
{
   DmtxEncodeStream stream;

   stream = StreamInit(input, output);

   /* Continue encoding until complete */
   while(stream.status == DmtxStatusEncoding)
      EncodeNextChunk(&stream, scheme, DmtxEncodeNormal, sizeIdxRequest);

   /* Verify encoding completed and all inputs were consumed */
   if(stream.status != DmtxStatusComplete || StreamInputHasNext(&stream))
      return DmtxUndefined;

   return stream.sizeIdx;
}

/**
 * This function distributes work to the equivalent scheme-specific
 * implementation.
 *
 * Each of these functions will encode the next symbol input word, and in some
 * cases this requires additional input words to be encoded as well.
 */
static void
EncodeNextChunk(DmtxEncodeStream *stream, int scheme, int option, int sizeIdxRequest)
{
   /* Special case: Prevent X12 from entering state with no way to unlatch */
   if(stream->currentScheme != DmtxSchemeX12 && scheme == DmtxSchemeX12)
   {
      if(PartialX12ChunkRemains(stream))
         scheme = DmtxSchemeAscii;
   }

   /* Change to target scheme if necessary */
   if(stream->currentScheme != scheme)
   {
      EncodeChangeScheme(stream, scheme, DmtxUnlatchExplicit); CHKERR;
      CHKSCHEME(scheme);
   }

   /* Special case: Edifact may be done before writing first word */
   if(scheme == DmtxSchemeEdifact)
      CompleteIfDoneEdifact(stream, sizeIdxRequest); CHKERR;

   switch(stream->currentScheme)
   {
      case DmtxSchemeAscii:
         EncodeNextChunkAscii(stream, option); CHKERR;
         CompleteIfDoneAscii(stream, sizeIdxRequest); CHKERR;
         break;
      case DmtxSchemeC40:
      case DmtxSchemeText:
      case DmtxSchemeX12:
         EncodeNextChunkCTX(stream, sizeIdxRequest); CHKERR;
         CompleteIfDoneCTX(stream, sizeIdxRequest); CHKERR;
         break;
      case DmtxSchemeEdifact:
         EncodeNextChunkEdifact(stream); CHKERR;
         CompleteIfDoneEdifact(stream, sizeIdxRequest); CHKERR;
         break;
      case DmtxSchemeBase256:
         EncodeNextChunkBase256(stream); CHKERR;
         CompleteIfDoneBase256(stream, sizeIdxRequest); CHKERR;
         break;
      default:
         StreamMarkFatal(stream, DmtxErrorUnknown);
         break;
   }
}

/**
 *
 *
 */
static void
EncodeChangeScheme(DmtxEncodeStream *stream, DmtxScheme targetScheme, int unlatchType)
{
   /* Nothing to do */
   if(stream->currentScheme == targetScheme)
      return;

   /* Every latch must go through ASCII */
   switch(stream->currentScheme)
   {
      case DmtxSchemeC40:
      case DmtxSchemeText:
      case DmtxSchemeX12:
         if(unlatchType == DmtxUnlatchExplicit)
         {
            AppendUnlatchCTX(stream); CHKERR;
         }
         break;
      case DmtxSchemeEdifact:
         if(unlatchType == DmtxUnlatchExplicit)
         {
            AppendValueEdifact(stream, DmtxValueEdifactUnlatch); CHKERR;
         }
         break;
      default:
         /* Nothing to do for ASCII or Base 256 */
         assert(stream->currentScheme == DmtxSchemeAscii ||
               stream->currentScheme == DmtxSchemeBase256);
         break;
   }
   stream->currentScheme = DmtxSchemeAscii;

   /* Anything other than ASCII (the default) requires a latch */
   switch(targetScheme)
   {
      case DmtxSchemeC40:
         AppendValueAscii(stream, DmtxValueC40Latch); CHKERR;
         break;
      case DmtxSchemeText:
         AppendValueAscii(stream, DmtxValueTextLatch); CHKERR;
         break;
      case DmtxSchemeX12:
         AppendValueAscii(stream, DmtxValueX12Latch); CHKERR;
         break;
      case DmtxSchemeEdifact:
         AppendValueAscii(stream, DmtxValueEdifactLatch); CHKERR;
         break;
      case DmtxSchemeBase256:
         AppendValueAscii(stream, DmtxValueBase256Latch); CHKERR;
         break;
      default:
         /* Nothing to do for ASCII */
         CHKSCHEME(DmtxSchemeAscii);
         break;
   }
   stream->currentScheme = targetScheme;

   /* Reset new chain length to zero */
   stream->outputChainWordCount = 0;
   stream->outputChainValueCount = 0;

   /* Insert header byte if just latched to Base256 */
   if(targetScheme == DmtxSchemeBase256)
   {
      UpdateBase256ChainHeader(stream, DmtxUndefined); CHKERR;
   }
}

/**
 *
 *
 */
static int
GetRemainingSymbolCapacity(int outputLength, int sizeIdx)
{
   int capacity;
   int remaining;

   if(sizeIdx == DmtxUndefined)
   {
      remaining = DmtxUndefined;
   }
   else
   {
      capacity = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
      remaining = capacity - outputLength;
   }

   return remaining;
}
Added jni/libdmtx/dmtxencodestream.c.
































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2011 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxencodestream.c
 * \brief DmtxEncodeStream implementation
 */

/**
 *
 *
 */
static DmtxEncodeStream
StreamInit(DmtxByteList *input, DmtxByteList *output)
{
   DmtxEncodeStream stream;

   stream.input = input;
   stream.output = output;

   stream.currentScheme = DmtxSchemeAscii;
   stream.inputNext = 0;
   stream.outputChainValueCount = 0;
   stream.outputChainWordCount = 0;
   stream.reason = NULL;
   stream.sizeIdx = DmtxUndefined;
   stream.status = DmtxStatusEncoding;

   return stream;
}

/**
 *
 *
 */
static void
StreamCopy(DmtxEncodeStream *dst, DmtxEncodeStream *src)
{
   DmtxPassFail passFail;

   dst->currentScheme = src->currentScheme;
   dst->inputNext = src->inputNext;
   dst->outputChainValueCount = src->outputChainValueCount;
   dst->outputChainWordCount = src->outputChainWordCount;
   dst->reason = src->reason;
   dst->sizeIdx = src->sizeIdx;
   dst->status = src->status;
   dst->input = src->input;

   dmtxByteListCopy(dst->output, src->output, &passFail);
}

/**
 *
 *
 */
static void
StreamMarkComplete(DmtxEncodeStream *stream, int sizeIdx)
{
   if(stream->status == DmtxStatusEncoding)
   {
      stream->sizeIdx = sizeIdx;
      stream->status = DmtxStatusComplete;
      assert(stream->reason == NULL);
   }
}

/**
 *
 *
 */
static void
StreamMarkInvalid(DmtxEncodeStream *stream, int reasonIdx)
{
   stream->status = DmtxStatusInvalid;
   stream->reason = dmtxErrorMessage[reasonIdx];
}

/**
 *
 *
 */
static void
StreamMarkFatal(DmtxEncodeStream *stream, int reasonIdx)
{
   stream->status = DmtxStatusFatal;
   stream->reason = dmtxErrorMessage[reasonIdx];
}

/**
 * push on newest/last append
 * used for encoding each output cw
 */
static void
StreamOutputChainAppend(DmtxEncodeStream *stream, DmtxByte value)
{
   DmtxPassFail passFail;

   dmtxByteListPush(stream->output, value, &passFail);

   if(passFail == DmtxPass)
      stream->outputChainWordCount++;
   else
      StreamMarkFatal(stream, DmtxErrorOutOfBounds);
}

/**
 * pop off newest/last
 * used for edifact
 */
static DmtxByte
StreamOutputChainRemoveLast(DmtxEncodeStream *stream)
{
   DmtxByte value;
   DmtxPassFail passFail;

   if(stream->outputChainWordCount > 0)
   {
      value = dmtxByteListPop(stream->output, &passFail);
      stream->outputChainWordCount--;
   }
   else
   {
      value = 0;
      StreamMarkFatal(stream, DmtxErrorEmptyList);
   }

   return value;
}

/**
 * overwrite arbitrary element
 * used for binary length changes
 */
static void
StreamOutputSet(DmtxEncodeStream *stream, int index, DmtxByte value)
{
   if(index < 0 || index >= stream->output->length)
      StreamMarkFatal(stream, DmtxErrorOutOfBounds);
   else
      stream->output->b[index] = value;
}

/**
 *
 *
 */
static DmtxBoolean
StreamInputHasNext(DmtxEncodeStream *stream)
{
   return (stream->inputNext < stream->input->length) ? DmtxTrue : DmtxFalse;
}

/**
 * peek at first/oldest
 * used for ascii double digit
 */
static DmtxByte
StreamInputPeekNext(DmtxEncodeStream *stream)
{
   DmtxByte value = 0;

   if(StreamInputHasNext(stream))
      value = stream->input->b[stream->inputNext];
   else
      StreamMarkFatal(stream, DmtxErrorOutOfBounds);

   return value;
}

/**
 * used as each input cw is processed
 *
 * \param value Value to populate, can be null (for blind dequeues)
 * \param stream
 */
static DmtxByte
StreamInputAdvanceNext(DmtxEncodeStream *stream)
{
   DmtxByte value;

   value = StreamInputPeekNext(stream);

   if(stream->status == DmtxStatusEncoding)
      stream->inputNext++; /* XXX is this what we really mean here? */

   return value;
}

/**
 * used as each input cw is processed
 *
 * \param value Value to populate, can be null (for blind dequeues)
 * \param stream
 */
static void
StreamInputAdvancePrev(DmtxEncodeStream *stream)
{
   if(stream->inputNext > 0)
      stream->inputNext--;
   else
      StreamMarkFatal(stream, DmtxErrorOutOfBounds);
}
Added jni/libdmtx/dmtximage.c.


























































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtximage.c
 * \brief Image handling
 */

/**
 * libdmtx stores image data as a large one-dimensional array of packed pixels,
 * reading from the array when scanning barcodes and writing to it when creating
 * a barcode. Beyond this interaction the calling program is responsible for
 * populating and dispatching pixels between the image array and the outside
 * world, whether that means loading an image from a file, acquiring camera
 * input, displaying output to a screen, saving to disk, etc...
 *
 * By default, libdmtx treats the first pixel of an image array as the top-left
 * corner of the physical image, with the final pixel landing at the bottom-
 * right. However, if mapping a pixel buffer this way produces an inverted
 * image the calling program can specify DmtxFlipY at image creation time to
 * remove the inversion. This has a negligible effect on performance since it
 * only modifies the pixel mapping math, and does not alter any pixel data.
 *
 * Regardless of how an image is stored internally, all libdmtx functions
 * consider coordinate (0,0) to mathematically represent the bottom-left pixel
 * location of an image using a right-handed coordinate system.
 *
 *                (0,HEIGHT-1)        (WIDTH-1,HEIGHT-1)
 *
 *          array pos = 0,1,2,3,...-----------+
 *                      |                     |
 *                      |                     |
 *                      |       libdmtx       |
 *                      |        image        |
 *                      |     coordinates     |
 *                      |                     |
 *                      |                     |
 *                      +---------...,N-2,N-1,N = array pos
 *
 *                    (0,0)              (WIDTH-1,0)
 *
 * Notes:
 *   - OpenGL pixel arrays obtained with glReadPixels() are stored
 *     bottom-to-top; use DmtxFlipY
 *   - Many popular image formats (e.g., PNG, GIF) store rows
 *     top-to-bottom; use DmtxFlipNone
 */

/**
 * \brief  XXX
 * \param  XXX
 * \return XXX
 */
extern DmtxImage *
dmtxImageCreate(unsigned char *pxl, int width, int height, int pack)
{
   DmtxPassFail err;
   DmtxImage *img;

   if(pxl == NULL || width < 1 || height < 1)
      return NULL;

   img = (DmtxImage *)calloc(1, sizeof(DmtxImage));
   if(img == NULL)
      return NULL;

   img->pxl = pxl;
   img->width = width;
   img->height = height;
   img->pixelPacking = pack;
   img->bitsPerPixel = GetBitsPerPixel(pack);
   img->bytesPerPixel = img->bitsPerPixel/8;
   img->rowPadBytes = 0;
   img->rowSizeBytes = img->width * img->bytesPerPixel + img->rowPadBytes;
   img->imageFlip = DmtxFlipNone;

   /* Leave channelStart[] and bitsPerChannel[] with zeros from calloc */
   img->channelCount = 0;

   switch(pack) {
      case DmtxPackCustom:
         break;
      case DmtxPack1bppK:
         err = dmtxImageSetChannel(img, 0, 1);
         return NULL; /* unsupported packing order */
/*       break; */
      case DmtxPack8bppK:
         err = dmtxImageSetChannel(img, 0, 8);
         break;
      case DmtxPack16bppRGB:
      case DmtxPack16bppBGR:
      case DmtxPack16bppYCbCr:
         err = dmtxImageSetChannel(img,  0, 5);
         err = dmtxImageSetChannel(img,  5, 5);
         err = dmtxImageSetChannel(img, 10, 5);
         break;
      case DmtxPack24bppRGB:
      case DmtxPack24bppBGR:
      case DmtxPack24bppYCbCr:
      case DmtxPack32bppRGBX:
      case DmtxPack32bppBGRX:
         err = dmtxImageSetChannel(img,  0, 8);
         err = dmtxImageSetChannel(img,  8, 8);
         err = dmtxImageSetChannel(img, 16, 8);
         break;
      case DmtxPack16bppRGBX:
      case DmtxPack16bppBGRX:
         err = dmtxImageSetChannel(img,  0, 5);
         err = dmtxImageSetChannel(img,  5, 5);
         err = dmtxImageSetChannel(img, 10, 5);
         break;
      case DmtxPack16bppXRGB:
      case DmtxPack16bppXBGR:
         err = dmtxImageSetChannel(img,  1, 5);
         err = dmtxImageSetChannel(img,  6, 5);
         err = dmtxImageSetChannel(img, 11, 5);
         break;
      case DmtxPack32bppXRGB:
      case DmtxPack32bppXBGR:
         err = dmtxImageSetChannel(img,  8, 8);
         err = dmtxImageSetChannel(img, 16, 8);
         err = dmtxImageSetChannel(img, 24, 8);
         break;
      case DmtxPack32bppCMYK:
         err = dmtxImageSetChannel(img,  0, 8);
         err = dmtxImageSetChannel(img,  8, 8);
         err = dmtxImageSetChannel(img, 16, 8);
         err = dmtxImageSetChannel(img, 24, 8);
         break;
      default:
         return NULL;
   }

   return img;
}

/**
 * \brief  Free libdmtx image memory
 * \param  img pointer to img location
 * \return DmtxFail | DmtxPass
 */
extern DmtxPassFail
dmtxImageDestroy(DmtxImage **img)
{
   if(img == NULL || *img == NULL)
      return DmtxFail;

   free(*img);

   *img = NULL;

   return DmtxPass;
}

/**
 *
 *
 */
extern DmtxPassFail
dmtxImageSetChannel(DmtxImage *img, int channelStart, int bitsPerChannel)
{
   if(img->channelCount >= 4) /* IMAGE_MAX_CHANNEL */
      return DmtxFail;

   /* New channel extends beyond pixel data */
/* if(channelStart + bitsPerChannel > img->bitsPerPixel)
      return DmtxFail; */

   img->bitsPerChannel[img->channelCount] = bitsPerChannel;
   img->channelStart[img->channelCount] = channelStart;
   (img->channelCount)++;

   return DmtxPass;
}

/**
 * \brief  Set image property
 * \param  img pointer to image
 * \return image width
 */
extern DmtxPassFail
dmtxImageSetProp(DmtxImage *img, int prop, int value)
{
   if(img == NULL)
      return DmtxFail;

   switch(prop) {
      case DmtxPropRowPadBytes:
         img->rowPadBytes = value;
         img->rowSizeBytes = img->width * (img->bitsPerPixel/8) + img->rowPadBytes;
         break;
      case DmtxPropImageFlip:
         img->imageFlip = value;
         break;
      default:
         break;
   }

   return DmtxPass;
}

/**
 * \brief  Get image width
 * \param  img pointer to image
 * \return image width
 */
extern int
dmtxImageGetProp(DmtxImage *img, int prop)
{
   if(img == NULL)
      return DmtxUndefined;

   switch(prop) {
      case DmtxPropWidth:
         return img->width;
      case DmtxPropHeight:
         return img->height;
      case DmtxPropPixelPacking:
         return img->pixelPacking;
      case DmtxPropBitsPerPixel:
         return img->bitsPerPixel;
      case DmtxPropBytesPerPixel:
         return img->bytesPerPixel;
      case DmtxPropRowPadBytes:
         return img->rowPadBytes;
      case DmtxPropRowSizeBytes:
         return img->rowSizeBytes;
      case DmtxPropImageFlip:
         return img->imageFlip;
      case DmtxPropChannelCount:
         return img->channelCount;
      default:
         break;
   }

   return DmtxUndefined;
}

/**
 * \brief  Returns pixel offset for image
 * \param  img
 * \param  x coordinate
 * \param  y coordinate
 * \return pixel byte offset
 */
extern int
dmtxImageGetByteOffset(DmtxImage *img, int x, int y)
{
   assert(img != NULL);
   assert(!(img->imageFlip & DmtxFlipX)); /* DmtxFlipX is not an option */

   if(dmtxImageContainsInt(img, 0, x, y) == DmtxFalse)
      return DmtxUndefined;

   if(img->imageFlip & DmtxFlipY)
      return (y * img->rowSizeBytes + x * img->bytesPerPixel);

   return ((img->height - y - 1) * img->rowSizeBytes + x * img->bytesPerPixel);
}

/**
 *
 *
 */
extern DmtxPassFail
dmtxImageGetPixelValue(DmtxImage *img, int x, int y, int channel, int *value)
{
   int offset;
/* unsigned char *pixelPtr;
   int pixelValue;
   int mask;
   int bitShift; */

   assert(img != NULL);
   assert(channel < img->channelCount);

   offset = dmtxImageGetByteOffset(img, x, y);
   if(offset == DmtxUndefined)
      return DmtxFail;

   switch(img->bitsPerChannel[channel]) {
      case 1:
/*       assert(img->bitsPerPixel == 1);
         mask = 0x01 << (7 - offset%8);
         *value = (img->pxl[offset/8] & mask) ? 255 : 0; */
         break;
      case 5:
         /* XXX might be expensive if we want to scale perfect 0-255 range */
/*       assert(img->bitsPerPixel == 16);
         pixelPtr = img->pxl + (offset * (img->bitsPerPixel/8));
         pixelValue = (*pixelPtr << 8) | (*(pixelPtr+1));
         bitShift = img->bitsPerPixel - 5 - img->channelStart[channel];
         mask = 0x1f << bitShift;
         *value = (((pixelValue & mask) >> bitShift) << 3); */
         break;
      case 8:
         assert(img->channelStart[channel] % 8 == 0);
         assert(img->bitsPerPixel % 8 == 0);
         *value = img->pxl[offset + channel];
         break;
   }

   return DmtxPass;
}

/**
 *
 *
 */
extern DmtxPassFail
dmtxImageSetPixelValue(DmtxImage *img, int x, int y, int channel, int value)
{
   int offset;
/* unsigned char *pixelPtr; */
/* int pixelValue; */
/* int mask; */
/* int bitShift; */

   assert(img != NULL);
   assert(channel < img->channelCount);

   offset = dmtxImageGetByteOffset(img, x, y);
   if(offset == DmtxUndefined)
      return DmtxFail;

   switch(img->bitsPerChannel[channel]) {
      case 1:
/*       assert(img->bitsPerPixel == 1);
         mask = 0x01 << (7 - offset%8);
         *value = (img->pxl[offset/8] & mask) ? 255 : 0; */
         break;
      case 5:
         /* XXX might be expensive if we want to scale perfect 0-255 range */
/*       assert(img->bitsPerPixel == 16);
         pixelPtr = img->pxl + (offset * (img->bitsPerPixel/8));
         pixelValue = (*pixelPtr << 8) | (*(pixelPtr+1));
         bitShift = img->bitsPerPixel - 5 - img->channelStart[channel];
         mask = 0x1f << bitShift;
         *value = (((pixelValue & mask) >> bitShift) << 3); */
         break;
      case 8:
         assert(img->channelStart[channel] % 8 == 0);
         assert(img->bitsPerPixel % 8 == 0);
         img->pxl[offset + channel] = value;
         break;
   }

   return DmtxPass;
}

/**
 * \brief  Test whether image contains a coordinate expressed in integers
 * \param  img
 * \param  margin width
 * \param  x coordinate
 * \param  y coordinate
 * \return DmtxTrue | DmtxFalse
 */
extern DmtxBoolean
dmtxImageContainsInt(DmtxImage *img, int margin, int x, int y)
{
   assert(img != NULL);

   if(x - margin >= 0 && x + margin < img->width &&
         y - margin >= 0 && y + margin < img->height)
      return DmtxTrue;

   return DmtxFalse;
}

/**
 * \brief  Test whether image contains a coordinate expressed in floating points
 * \param  img
 * \param  x coordinate
 * \param  y coordinate
 * \return DmtxTrue | DmtxFalse
 */
extern DmtxBoolean
dmtxImageContainsFloat(DmtxImage *img, double x, double y)
{
   assert(img != NULL);

   if(x >= 0.0 && x < (double)img->width && y >= 0.0 && y < (double)img->height)
      return DmtxTrue;

   return DmtxFalse;
}

/**
 *
 *
 */
static int
GetBitsPerPixel(int pack)
{
   switch(pack) {
      case DmtxPack1bppK:
         return 1;
      case DmtxPack8bppK:
         return 8;
      case DmtxPack16bppRGB:
      case DmtxPack16bppRGBX:
      case DmtxPack16bppXRGB:
      case DmtxPack16bppBGR:
      case DmtxPack16bppBGRX:
      case DmtxPack16bppXBGR:
      case DmtxPack16bppYCbCr:
         return 16;
      case DmtxPack24bppRGB:
      case DmtxPack24bppBGR:
      case DmtxPack24bppYCbCr:
         return  24;
      case DmtxPack32bppRGBX:
      case DmtxPack32bppXRGB:
      case DmtxPack32bppBGRX:
      case DmtxPack32bppXBGR:
      case DmtxPack32bppCMYK:
         return  32;
      default:
         break;
   }

   return DmtxUndefined;
}
Added jni/libdmtx/dmtxmatrix3.c.
































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxmatrix3.c
 * \brief 2D Matrix (3x3) math
 */

/**
 * \brief  Copy matrix contents
 * \param  m0 Copy target
 * \param  m1 Copy source
 * \return void
 */
extern void
dmtxMatrix3Copy(DmtxMatrix3 m0, DmtxMatrix3 m1)
{
   memcpy(m0, m1, sizeof(DmtxMatrix3));
}

/**
 * \brief  Generate identity transformation matrix
 * \param  m Generated matrix
 * \return void
 *
 *      | 1  0  0 |
 *  m = | 0  1  0 |
 *      | 0  0  1 |
 *
 *                  Transform "m"
 *            (doesn't change anything)
 *                       |\
 *  (0,1)  x----o     +--+ \    (0,1)  x----o
 *         |    |     |     \          |    |
 *         |    |     |     /          |    |
 *         +----*     +--+ /           +----*
 *  (0,0)     (1,0)      |/     (0,0)     (1,0)
 *
 */
extern void
dmtxMatrix3Identity(DmtxMatrix3 m)
{
   static DmtxMatrix3 tmp = { {1, 0, 0},
                              {0, 1, 0},
                              {0, 0, 1} };
   dmtxMatrix3Copy(m, tmp);
}

/**
 * \brief  Generate translate transformation matrix
 * \param  m Generated matrix
 * \param  tx
 * \param  ty
 * \return void
 *
 *      | 1  0  0 |
 *  m = | 0  1  0 |
 *      | tx ty 1 |
 *
 *                  Transform "m"
 *                      _____    (tx,1+ty)  x----o  (1+tx,1+ty)
 *                      \   |               |    |
 *  (0,1)  x----o       /   |      (0,1)  +-|--+ |
 *         |    |      /  /\|             | +----*  (1+tx,ty)
 *         |    |      \ /                |    |
 *         +----*       `                 +----+
 *  (0,0)     (1,0)                (0,0)     (1,0)
 *
 */
void dmtxMatrix3Translate(DmtxMatrix3 m, double tx, double ty)
{
   dmtxMatrix3Identity(m);
   m[2][0] = tx;
   m[2][1] = ty;
}

/**
 * \brief  Generate rotate transformation
 * \param  m Generated matrix
 * \param  angle
 * \return void
 *
 *     |  cos(a)  sin(a)  0 |
 * m = | -sin(a)  cos(a)  0 |
 *     |  0       0       1 |
 *                                       o
 *                  Transform "m"      /   `
 *                       ___         /       `
 *  (0,1)  x----o      |/   \       x          *  (cos(a),sin(a))
 *         |    |      '--   |       `        /
 *         |    |        ___/          `    /  a
 *         +----*                        `+  - - - - - -
 *  (0,0)     (1,0)                     (0,0)
 *
 */
extern void
dmtxMatrix3Rotate(DmtxMatrix3 m, double angle)
{
   double sinAngle, cosAngle;

   sinAngle = sin(angle);
   cosAngle = cos(angle);

   dmtxMatrix3Identity(m);
   m[0][0] = cosAngle;
   m[0][1] = sinAngle;
   m[1][0] = -sinAngle;
   m[1][1] = cosAngle;
}

/**
 * \brief  Generate scale transformation matrix
 * \param  m Generated matrix
 * \param  sx
 * \param  sy
 * \return void
 *
 *     | sx 0  0 |
 * m = | 0  sy 0 |
 *     | 0  0  1 |
 *
 *                  Transform "m"
 *                      _____     (0,sy)  x-------o (sx,sy)
 *                      \   |             |       |
 *  (0,1)  x----o       /   |      (0,1)  +----+  |
 *         |    |      /  /\|             |    |  |
 *         |    |      \ /                |    |  |
 *         +----*       `                 +----+--*
 *  (0,0)     (1,0)                (0,0)            (sx,0)
 *
 */
extern void
dmtxMatrix3Scale(DmtxMatrix3 m, double sx, double sy)
{
   dmtxMatrix3Identity(m);
   m[0][0] = sx;
   m[1][1] = sy;
}

/**
 * \brief  Generate shear transformation matrix
 * \param  m Generated matrix
 * \param  shx
 * \param  shy
 * \return void
 *
 *     | 0    shy  0 |
 * m = | shx  0    0 |
 *     | 0    0    1 |
 */
extern void
dmtxMatrix3Shear(DmtxMatrix3 m, double shx, double shy)
{
   dmtxMatrix3Identity(m);
   m[1][0] = shx;
   m[0][1] = shy;
}

/**
 * \brief  Generate top line skew transformation
 * \param  m
 * \param  b0
 * \param  b1
 * \param  sz
 * \return void
 *
 *     | b1/b0    0    (b1-b0)/(sz*b0) |
 * m = |   0    sz/b0         0        |
 *     |   0      0           1        |
 *
 *     (sz,b1)  o
 *             /|    Transform "m"
 *            / |
 *           /  |        +--+
 *          /   |        |  |
 * (0,b0)  x    |        |  |
 *         |    |      +-+  +-+
 * (0,sz)  +----+       \    /    (0,sz)  x----o
 *         |    |        \  /             |    |
 *         |    |         \/              |    |
 *         +----+                         +----+
 *  (0,0)    (sz,0)                (0,0)    (sz,0)
 *
 */
extern void
dmtxMatrix3LineSkewTop(DmtxMatrix3 m, double b0, double b1, double sz)
{
   assert(b0 >= DmtxAlmostZero);

   dmtxMatrix3Identity(m);
   m[0][0] = b1/b0;
   m[1][1] = sz/b0;
   m[0][2] = (b1 - b0)/(sz*b0);
}

/**
 * \brief  Generate top line skew transformation (inverse)
 * \param  m
 * \param  b0
 * \param  b1
 * \param  sz
 * \return void
 */
extern void
dmtxMatrix3LineSkewTopInv(DmtxMatrix3 m, double b0, double b1, double sz)
{
   assert(b1 >= DmtxAlmostZero);

   dmtxMatrix3Identity(m);
   m[0][0] = b0/b1;
   m[1][1] = b0/sz;
   m[0][2] = (b0 - b1)/(sz*b1);
}

/**
 * \brief  Generate side line skew transformation
 * \param  m
 * \param  b0
 * \param  b1
 * \param  sz
 * \return void
 */
extern void
dmtxMatrix3LineSkewSide(DmtxMatrix3 m, double b0, double b1, double sz)
{
   assert(b0 >= DmtxAlmostZero);

   dmtxMatrix3Identity(m);
   m[0][0] = sz/b0;
   m[1][1] = b1/b0;
   m[1][2] = (b1 - b0)/(sz*b0);
}

/**
 * \brief  Generate side line skew transformation (inverse)
 * \param  m
 * \param  b0
 * \param  b1
 * \param  sz
 * \return void
 */
extern void
dmtxMatrix3LineSkewSideInv(DmtxMatrix3 m, double b0, double b1, double sz)
{
   assert(b1 >= DmtxAlmostZero);

   dmtxMatrix3Identity(m);
   m[0][0] = b0/sz;
   m[1][1] = b0/b1;
   m[1][2] = (b0 - b1)/(sz*b1);
}

/**
 * \brief  Multiply two matrices to create a third
 * \param  mOut
 * \param  m0
 * \param  m1
 * \return void
 */
extern void
dmtxMatrix3Multiply(DmtxMatrix3 mOut, DmtxMatrix3 m0, DmtxMatrix3 m1)
{
   int i, j, k;
   double val;

   for(i = 0; i < 3; i++) {
      for(j = 0; j < 3; j++) {
         val = 0.0;
         for(k = 0; k < 3; k++) {
            val += m0[i][k] * m1[k][j];
         }
         mOut[i][j] = val;
      }
   }
}

/**
 * \brief  Multiply two matrices in place
 * \param  m0
 * \param  m1
 * \return void
 */
extern void
dmtxMatrix3MultiplyBy(DmtxMatrix3 m0, DmtxMatrix3 m1)
{
   DmtxMatrix3 mTmp;

   dmtxMatrix3Copy(mTmp, m0);
   dmtxMatrix3Multiply(m0, mTmp, m1);
}

/**
 * \brief  Multiply vector and matrix
 * \param  vOut Vector (output)
 * \param  vIn Vector (input)
 * \param  m Matrix to be multiplied
 * \return DmtxPass | DmtxFail
 */
extern int
dmtxMatrix3VMultiply(DmtxVector2 *vOut, DmtxVector2 *vIn, DmtxMatrix3 m)
{
   double w;

   w = vIn->X*m[0][2] + vIn->Y*m[1][2] + m[2][2];
   if(fabs(w) <= DmtxAlmostZero) {
      vOut->X = FLT_MAX;
      vOut->Y = FLT_MAX;
      return DmtxFail;
   }

   vOut->X = (vIn->X*m[0][0] + vIn->Y*m[1][0] + m[2][0])/w;
   vOut->Y = (vIn->X*m[0][1] + vIn->Y*m[1][1] + m[2][1])/w;

   return DmtxPass;
}

/**
 * \brief  Multiply vector and matrix in place
 * \param  v Vector (input and output)
 * \param  m Matrix to be multiplied
 * \return DmtxPass | DmtxFail
 */
extern int
dmtxMatrix3VMultiplyBy(DmtxVector2 *v, DmtxMatrix3 m)
{
   int success;
   DmtxVector2 vOut;

   success = dmtxMatrix3VMultiply(&vOut, v, m);
   *v = vOut;

   return success;
}

/**
 * \brief  Print matrix contents to STDOUT
 * \param  m
 * \return void
 */
extern void
dmtxMatrix3Print(DmtxMatrix3 m)
{
   fprintf(stdout, "%8.8f\t%8.8f\t%8.8f\n", m[0][0], m[0][1], m[0][2]);
   fprintf(stdout, "%8.8f\t%8.8f\t%8.8f\n", m[1][0], m[1][1], m[1][2]);
   fprintf(stdout, "%8.8f\t%8.8f\t%8.8f\n", m[2][0], m[2][1], m[2][2]);
   fprintf(stdout, "\n");
}
Added jni/libdmtx/dmtxmessage.c.


































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxmessage.c
 * \brief Data message handling
 */

/**
 * \brief  Allocate memory for message
 * \param  sizeIdx
 * \param  symbolFormat DmtxFormatMatrix | DmtxFormatMosaic
 * \return Address of allocated memory
 */
extern DmtxMessage *
dmtxMessageCreate(int sizeIdx, int symbolFormat)
{
   DmtxMessage *message;
   int mappingRows, mappingCols;

   assert(symbolFormat == DmtxFormatMatrix || symbolFormat == DmtxFormatMosaic);

   mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx);
   mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx);

   message = (DmtxMessage *)calloc(1, sizeof(DmtxMessage));
   if(message == NULL)
      return NULL;

   message->arraySize = sizeof(unsigned char) * mappingRows * mappingCols;

   message->array = (unsigned char *)calloc(1, message->arraySize);
   if(message->array == NULL) {
      perror("Calloc failed");
      dmtxMessageDestroy(&message);
      return NULL;
   }

   message->codeSize = sizeof(unsigned char) *
         dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx) +
         dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx);

   if(symbolFormat == DmtxFormatMosaic)
      message->codeSize *= 3;

   message->code = (unsigned char *)calloc(message->codeSize, sizeof(unsigned char));
   if(message->code == NULL) {
      perror("Calloc failed");
      dmtxMessageDestroy(&message);
      return NULL;
   }

   /* XXX not sure if this is the right place or even the right approach.
      Trying to allocate memory for the decoded data stream and will
      initially assume that decoded data will not be larger than 2x encoded data */
   message->outputSize = sizeof(unsigned char) * message->codeSize * 10;
   message->output = (unsigned char *)calloc(message->outputSize, sizeof(unsigned char));
   if(message->output == NULL) {
      perror("Calloc failed");
      dmtxMessageDestroy(&message);
      return NULL;
   }

   return message;
}

/**
 * \brief  Free memory previously allocated for message
 * \param  message
 * \return void
 */
extern DmtxPassFail
dmtxMessageDestroy(DmtxMessage **msg)
{
   if(msg == NULL || *msg == NULL)
      return DmtxFail;

   if((*msg)->array != NULL)
      free((*msg)->array);

   if((*msg)->code != NULL)
      free((*msg)->code);

   if((*msg)->output != NULL)
      free((*msg)->output);

   free(*msg);

   *msg = NULL;

   return DmtxPass;
}
Added jni/libdmtx/dmtxplacemod.c.














































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxplacemod.c
 * \brief Data Matrix module placement
 */

/**
 * receives symbol row and col and returns status
 * DmtxModuleOn / !DmtxModuleOn (DmtxModuleOff)
 * DmtxModuleAssigned
 * DmtxModuleVisited
 * DmtxModuleData / !DmtxModuleData (DmtxModuleAlignment)
 * row and col are expressed in symbol coordinates, so (0,0) is the intersection of the "L"
 */
int
dmtxSymbolModuleStatus(DmtxMessage *message, int sizeIdx, int symbolRow, int symbolCol)
{
   int symbolRowReverse;
   int mappingRow, mappingCol;
   int dataRegionRows, dataRegionCols;
   int symbolRows, mappingCols;

   dataRegionRows = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionRows, sizeIdx);
   dataRegionCols = dmtxGetSymbolAttribute(DmtxSymAttribDataRegionCols, sizeIdx);
   symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
   mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx);

   symbolRowReverse = symbolRows - symbolRow - 1;
   mappingRow = symbolRowReverse - 1 - 2 * (symbolRowReverse / (dataRegionRows+2));
   mappingCol = symbolCol - 1 - 2 * (symbolCol / (dataRegionCols+2));

   /* Solid portion of alignment patterns */
   if(symbolRow % (dataRegionRows+2) == 0 ||
         symbolCol % (dataRegionCols+2) == 0)
      return (DmtxModuleOnRGB | (!DmtxModuleData));

   /* Horinzontal calibration bars */
   if((symbolRow+1) % (dataRegionRows+2) == 0)
      return (((symbolCol & 0x01) ? 0 : DmtxModuleOnRGB) | (!DmtxModuleData));

   /* Vertical calibration bars */
   if((symbolCol+1) % (dataRegionCols+2) == 0)
      return (((symbolRow & 0x01) ? 0 : DmtxModuleOnRGB) | (!DmtxModuleData));

   /* Data modules */
   return (message->array[mappingRow * mappingCols + mappingCol] | DmtxModuleData);
}

/**
 * \brief  Logical relationship between bit and module locations
 * \param  modules
 * \param  codewords
 * \param  sizeIdx
 * \param  moduleOnColor
 * \return Number of codewords read
 */
static int
ModulePlacementEcc200(unsigned char *modules, unsigned char *codewords, int sizeIdx, int moduleOnColor)
{
   int row, col, chr;
   int mappingRows, mappingCols;

   assert(moduleOnColor & (DmtxModuleOnRed | DmtxModuleOnGreen | DmtxModuleOnBlue));

   mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, sizeIdx);
   mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, sizeIdx);

   /* Start in the nominal location for the 8th bit of the first character */
   chr = 0;
   row = 4;
   col = 0;

   do {
      /* Repeatedly first check for one of the special corner cases */
      if((row == mappingRows) && (col == 0))
         PatternShapeSpecial1(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor);
      else if((row == mappingRows-2) && (col == 0) && (mappingCols%4 != 0))
         PatternShapeSpecial2(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor);
      else if((row == mappingRows-2) && (col == 0) && (mappingCols%8 == 4))
         PatternShapeSpecial3(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor);
      else if((row == mappingRows+4) && (col == 2) && (mappingCols%8 == 0))
         PatternShapeSpecial4(modules, mappingRows, mappingCols, &(codewords[chr++]), moduleOnColor);

      /* Sweep upward diagonally, inserting successive characters */
      do {
         if((row < mappingRows) && (col >= 0) &&
               !(modules[row*mappingCols+col] & DmtxModuleVisited))
            PatternShapeStandard(modules, mappingRows, mappingCols, row, col, &(codewords[chr++]), moduleOnColor);
         row -= 2;
         col += 2;
      } while ((row >= 0) && (col < mappingCols));
      row += 1;
      col += 3;

      /* Sweep downward diagonally, inserting successive characters */
      do {
         if((row >= 0) && (col < mappingCols) &&
               !(modules[row*mappingCols+col] & DmtxModuleVisited))
            PatternShapeStandard(modules, mappingRows, mappingCols, row, col, &(codewords[chr++]), moduleOnColor);
         row += 2;
         col -= 2;
      } while ((row < mappingRows) && (col >= 0));
      row += 3;
      col += 1;
      /* ... until the entire modules array is scanned */
   } while ((row < mappingRows) || (col < mappingCols));

   /* If lower righthand corner is untouched then fill in the fixed pattern */
   if(!(modules[mappingRows * mappingCols - 1] &
         DmtxModuleVisited)) {

      modules[mappingRows * mappingCols - 1] |= moduleOnColor;
      modules[(mappingRows * mappingCols) - mappingCols - 2] |= moduleOnColor;
   } /* XXX should this fixed pattern also be used in reading somehow? */

   /* XXX compare that chr == region->dataSize here */
   return chr; /* XXX number of codewords read off */
}

/**
 * \brief  XXX
 * \param  modules
 * \param  mappingRows
 * \param  mappingCols
 * \param  row
 * \param  col
 * \param  codeword
 * \param  moduleOnColor
 * \return void
 */
static void
PatternShapeStandard(unsigned char *modules, int mappingRows, int mappingCols, int row, int col, unsigned char *codeword, int moduleOnColor)
{
   PlaceModule(modules, mappingRows, mappingCols, row-2, col-2, codeword, DmtxMaskBit1, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, row-2, col-1, codeword, DmtxMaskBit2, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, row-1, col-2, codeword, DmtxMaskBit3, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, row-1, col-1, codeword, DmtxMaskBit4, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, row-1, col,   codeword, DmtxMaskBit5, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, row,   col-2, codeword, DmtxMaskBit6, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, row,   col-1, codeword, DmtxMaskBit7, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, row,   col,   codeword, DmtxMaskBit8, moduleOnColor);
}

/**
 * \brief  XXX
 * \param  modules
 * \param  mappingRows
 * \param  mappingCols
 * \param  codeword
 * \param  moduleOnColor
 * \return void
 */
static void
PatternShapeSpecial1(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor)
{
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 0, codeword, DmtxMaskBit1, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 1, codeword, DmtxMaskBit2, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 2, codeword, DmtxMaskBit3, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-2, codeword, DmtxMaskBit4, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-1, codeword, DmtxMaskBit5, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-1, codeword, DmtxMaskBit6, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 2, mappingCols-1, codeword, DmtxMaskBit7, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 3, mappingCols-1, codeword, DmtxMaskBit8, moduleOnColor);
}

/**
 * \brief  XXX
 * \param  modules
 * \param  mappingRows
 * \param  mappingCols
 * \param  codeword
 * \param  moduleOnColor
 * \return void
 */
static void
PatternShapeSpecial2(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor)
{
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-3, 0, codeword, DmtxMaskBit1, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-2, 0, codeword, DmtxMaskBit2, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 0, codeword, DmtxMaskBit3, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-4, codeword, DmtxMaskBit4, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-3, codeword, DmtxMaskBit5, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-2, codeword, DmtxMaskBit6, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-1, codeword, DmtxMaskBit7, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-1, codeword, DmtxMaskBit8, moduleOnColor);
}

/**
 * \brief  XXX
 * \param  modules
 * \param  mappingRows
 * \param  mappingCols
 * \param  codeword
 * \param  moduleOnColor
 * \return void
 */
static void
PatternShapeSpecial3(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor)
{
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-3, 0, codeword, DmtxMaskBit1, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-2, 0, codeword, DmtxMaskBit2, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 0, codeword, DmtxMaskBit3, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-2, codeword, DmtxMaskBit4, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-1, codeword, DmtxMaskBit5, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-1, codeword, DmtxMaskBit6, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 2, mappingCols-1, codeword, DmtxMaskBit7, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 3, mappingCols-1, codeword, DmtxMaskBit8, moduleOnColor);
}

/**
 * \brief  XXX
 * \param  modules
 * \param  mappingRows
 * \param  mappingCols
 * \param  codeword
 * \param  moduleOnColor
 * \return void
 */
static void
PatternShapeSpecial4(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor)
{
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, 0, codeword, DmtxMaskBit1, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, mappingRows-1, mappingCols-1, codeword, DmtxMaskBit2, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-3, codeword, DmtxMaskBit3, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-2, codeword, DmtxMaskBit4, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 0, mappingCols-1, codeword, DmtxMaskBit5, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-3, codeword, DmtxMaskBit6, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-2, codeword, DmtxMaskBit7, moduleOnColor);
   PlaceModule(modules, mappingRows, mappingCols, 1, mappingCols-1, codeword, DmtxMaskBit8, moduleOnColor);
}

/**
 * \brief  XXX
 * \param  modules
 * \param  mappingRows
 * \param  mappingCols
 * \param  row
 * \param  col
 * \param  codeword
 * \param  mask
 * \param  moduleOnColor
 * \return void
 */
static void
PlaceModule(unsigned char *modules, int mappingRows, int mappingCols, int row, int col, unsigned char *codeword, int mask, int moduleOnColor)
{
   if(row < 0) {
      row += mappingRows;
      col += 4 - ((mappingRows+4)%8);
   }
   if(col < 0) {
      col += mappingCols;
      row += 4 - ((mappingCols+4)%8);
   }

   /* If module has already been assigned then we are decoding the pattern into codewords */
   if((modules[row*mappingCols+col] & DmtxModuleAssigned) != 0) {
      if((modules[row*mappingCols+col] & moduleOnColor) != 0)
         *codeword |= mask;
      else
         *codeword &= (0xff ^ mask);
   }
   /* Otherwise we are encoding the codewords into a pattern */
   else {
      if((*codeword & mask) != 0x00)
         modules[row*mappingCols+col] |= moduleOnColor;

      modules[row*mappingCols+col] |= DmtxModuleAssigned;
   }

   modules[row*mappingCols+col] |= DmtxModuleVisited;
}
Added jni/libdmtx/dmtxreedsol.c.






























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2011 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * ---------------------------------------------------------
 * Portions of this file were derived from the Reed-Solomon
 * encoder/decoder released by Simon Rockliff in June 1991.
 * ---------------------------------------------------------
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxreedsol.c
 */

/**
 * TODO:
 *   o try doxygen using using the JavaDoc style and JAVADOC_AUTOBRIEF = YES
 *   o switch doxygen to simplified syntax, and using "\file" instead of "@file"
 */

#define NN                      255
#define MAX_ERROR_WORD_COUNT     68

/* GF add (a + b) */
#define GfAdd(a,b) \
   ((a) ^ (b))

/* GF multiply (a * b) */
#define GfMult(a,b) \
   (((a) == 0 || (b) == 0) ? 0 : antilog301[(log301[(a)] + log301[(b)]) % NN])

/* GF multiply by antilog (a * alpha**b) */
#define GfMultAntilog(a,b) \
   (((a) == 0) ? 0 : antilog301[(log301[(a)] + (b)) % NN])

/* GF(256) log values using primitive polynomial 301 */
static DmtxByte log301[] =
   { 255,   0,   1, 240,   2, 225, 241,  53,   3,  38, 226, 133, 242,  43,  54, 210,
       4, 195,  39, 114, 227, 106, 134,  28, 243, 140,  44,  23,  55, 118, 211, 234,
       5, 219, 196,  96,  40, 222, 115, 103, 228,  78, 107, 125, 135,   8,  29, 162,
     244, 186, 141, 180,  45,  99,  24,  49,  56,  13, 119, 153, 212, 199, 235,  91,
       6,  76, 220, 217, 197,  11,  97, 184,  41,  36, 223, 253, 116, 138, 104, 193,
     229,  86,  79, 171, 108, 165, 126, 145, 136,  34,   9,  74,  30,  32, 163,  84,
     245, 173, 187, 204, 142,  81, 181, 190,  46,  88, 100, 159,  25, 231,  50, 207,
      57, 147,  14,  67, 120, 128, 154, 248, 213, 167, 200,  63, 236, 110,  92, 176,
       7, 161,  77, 124, 221, 102, 218,  95, 198,  90,  12, 152,  98,  48, 185, 179,
      42, 209,  37, 132, 224,  52, 254, 239, 117, 233, 139,  22, 105,  27, 194, 113,
     230, 206,  87, 158,  80, 189, 172, 203, 109, 175, 166,  62, 127, 247, 146,  66,
     137, 192,  35, 252,  10, 183,  75, 216,  31,  83,  33,  73, 164, 144,  85, 170,
     246,  65, 174,  61, 188, 202, 205, 157, 143, 169,  82,  72, 182, 215, 191, 251,
      47, 178,  89, 151, 101,  94, 160, 123,  26, 112, 232,  21,  51, 238, 208, 131,
      58,  69, 148,  18,  15,  16,  68,  17, 121, 149, 129,  19, 155,  59, 249,  70,
     214, 250, 168,  71, 201, 156,  64,  60, 237, 130, 111,  20,  93, 122, 177, 150 };

/* GF(256) antilog values using primitive polynomial 301 */
static DmtxByte antilog301[] =
   {   1,   2,   4,   8,  16,  32,  64, 128,  45,  90, 180,  69, 138,  57, 114, 228,
     229, 231, 227, 235, 251, 219, 155,  27,  54, 108, 216, 157,  23,  46,  92, 184,
      93, 186,  89, 178,  73, 146,   9,  18,  36,  72, 144,  13,  26,  52, 104, 208,
     141,  55, 110, 220, 149,   7,  14,  28,  56, 112, 224, 237, 247, 195, 171, 123,
     246, 193, 175, 115, 230, 225, 239, 243, 203, 187,  91, 182,  65, 130,  41,  82,
     164, 101, 202, 185,  95, 190,  81, 162, 105, 210, 137,  63, 126, 252, 213, 135,
      35,  70, 140,  53, 106, 212, 133,  39,  78, 156,  21,  42,  84, 168, 125, 250,
     217, 159,  19,  38,  76, 152,  29,  58, 116, 232, 253, 215, 131,  43,  86, 172,
     117, 234, 249, 223, 147,  11,  22,  44,  88, 176,  77, 154,  25,  50, 100, 200,
     189,  87, 174, 113, 226, 233, 255, 211, 139,  59, 118, 236, 245, 199, 163, 107,
     214, 129,  47,  94, 188,  85, 170, 121, 242, 201, 191,  83, 166,  97, 194, 169,
     127, 254, 209, 143,  51, 102, 204, 181,  71, 142,  49,  98, 196, 165, 103, 206,
     177,  79, 158,  17,  34,  68, 136,  61, 122, 244, 197, 167,  99, 198, 161, 111,
     222, 145,  15,  30,  60, 120, 240, 205, 183,  67, 134,  33,  66, 132,  37,  74,
     148,   5,  10,  20,  40,  80, 160, 109, 218, 153,  31,  62, 124, 248, 221, 151,
       3,   6,  12,  24,  48,  96, 192, 173, 119, 238, 241, 207, 179,  75, 150,   0 };

/**
 * Encode xyz.
 * More detailed description.
 * \param message
 * \param sizeIdx
 * \return Function success (DmtxPass|DmtxFail)
 */
#undef CHKPASS
#define CHKPASS { if(passFail == DmtxFail) return DmtxFail; }
static DmtxPassFail
RsEncode(DmtxMessage *message, int sizeIdx)
{
   int i, j;
   int blockStride, blockIdx;
   int blockErrorWords, symbolDataWords, symbolErrorWords, symbolTotalWords;
   DmtxPassFail passFail;
   DmtxByte val, *eccPtr;
   DmtxByte genStorage[MAX_ERROR_WORD_COUNT];
   DmtxByte eccStorage[MAX_ERROR_WORD_COUNT];
   DmtxByteList gen = dmtxByteListBuild(genStorage, sizeof(genStorage));
   DmtxByteList ecc = dmtxByteListBuild(eccStorage, sizeof(eccStorage));

   blockStride = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx);
   blockErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockErrorWords, sizeIdx);
   symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
   symbolErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx);
   symbolTotalWords = symbolDataWords + symbolErrorWords;

   /* Populate generator polynomial */
   RsGenPoly(&gen, blockErrorWords);

   /* For each interleaved block... */
   for(blockIdx = 0; blockIdx < blockStride; blockIdx++)
   {
      /* Generate error codewords */
      dmtxByteListInit(&ecc, blockErrorWords, 0, &passFail); CHKPASS;
      for(i = blockIdx; i < symbolDataWords; i += blockStride)
      {
         val = GfAdd(ecc.b[blockErrorWords-1], message->code[i]);

         for(j = blockErrorWords - 1; j > 0; j--)
         {
            DMTX_CHECK_BOUNDS(&ecc, j); DMTX_CHECK_BOUNDS(&ecc, j-1); DMTX_CHECK_BOUNDS(&gen, j);
            ecc.b[j] = GfAdd(ecc.b[j-1], GfMult(gen.b[j], val));
         }

         ecc.b[0] = GfMult(gen.b[0], val);
      }

      /* Copy to output message */
      eccPtr = ecc.b + blockErrorWords;
      for(i = symbolDataWords + blockIdx; i < symbolTotalWords; i += blockStride)
         message->code[i] = *(--eccPtr);

      assert(ecc.b == eccPtr);
   }

   return DmtxPass;
}

/**
 * Decode xyz.
 * More detailed description.
 * \param code
 * \param sizeIdx
 * \param fix
 * \return Function success (DmtxPass|DmtxFail)
 */
#undef CHKPASS
#define CHKPASS { if(passFail == DmtxFail) return DmtxFail; }
static DmtxPassFail
RsDecode(unsigned char *code, int sizeIdx, int fix)
{
   int i;
   int blockStride, blockIdx;
   int blockDataWords, blockErrorWords, blockTotalWords, blockMaxCorrectable;
   int symbolDataWords, symbolErrorWords, symbolTotalWords;
   DmtxBoolean error, repairable;
   DmtxPassFail passFail;
   unsigned char *word;
   DmtxByte elpStorage[MAX_ERROR_WORD_COUNT];
   DmtxByte synStorage[MAX_ERROR_WORD_COUNT+1];
   DmtxByte recStorage[NN];
   DmtxByte locStorage[NN];
   DmtxByteList elp = dmtxByteListBuild(elpStorage, sizeof(elpStorage));
   DmtxByteList syn = dmtxByteListBuild(synStorage, sizeof(synStorage));
   DmtxByteList rec = dmtxByteListBuild(recStorage, sizeof(recStorage));
   DmtxByteList loc = dmtxByteListBuild(locStorage, sizeof(locStorage));

   blockStride = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx);
   blockErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribBlockErrorWords, sizeIdx);
   blockMaxCorrectable = dmtxGetSymbolAttribute(DmtxSymAttribBlockMaxCorrectable, sizeIdx);
   symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
   symbolErrorWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolErrorWords, sizeIdx);
   symbolTotalWords = symbolDataWords + symbolErrorWords;

   /* For each interleaved block */
   for(blockIdx = 0; blockIdx < blockStride; blockIdx++)
   {
      /* Data word count depends on blockIdx due to special case at 144x144 */
      blockDataWords = dmtxGetBlockDataSize(sizeIdx, blockIdx);
      blockTotalWords = blockErrorWords + blockDataWords;

      /* Populate received list (rec) with data and error codewords */
      dmtxByteListInit(&rec, 0, 0, &passFail); CHKPASS;

      /* Start with final error word and work backward */
      word = code + symbolTotalWords + blockIdx - blockStride;
      for(i = 0; i < blockErrorWords; i++)
      {
         dmtxByteListPush(&rec, *word, &passFail); CHKPASS;
         word -= blockStride;
      }

      /* Start with final data word and work backward */
      word = code + blockIdx + (blockStride * (blockDataWords - 1));
      for(i = 0; i < blockDataWords; i++)
      {
         dmtxByteListPush(&rec, *word, &passFail); CHKPASS;
         word -= blockStride;
      }

      /* Compute syndromes (syn) */
      error = RsComputeSyndromes(&syn, &rec, blockErrorWords);

      /* Error(s) detected: Attempt repair */
      if(error)
      {
         /* Find error locator polynomial (elp) */
         repairable = RsFindErrorLocatorPoly(&elp, &syn, blockErrorWords, blockMaxCorrectable);
         if(!repairable)
            return DmtxFail;

         /* Find error positions (loc) */
         repairable = RsFindErrorLocations(&loc, &elp);
         if(!repairable)
            return DmtxFail;

         /* Find error values and repair */
         RsRepairErrors(&rec, &loc, &elp, &syn);
      }

      /*
       * Overwrite output with correct/corrected values
       */

      /* Start with first data word and work forward */
      word = code + blockIdx;
      for(i = 0; i < blockDataWords; i++)
      {
         *word = dmtxByteListPop(&rec, &passFail); CHKPASS;
         word += blockStride;
      }

      /* Start with first error word and work forward */
      word = code + symbolDataWords + blockIdx;
      for(i = 0; i < blockErrorWords; i++)
      {
         *word = dmtxByteListPop(&rec, &passFail); CHKPASS;
         word += blockStride;
      }
   }

   return DmtxPass;
}

/**
 * Populate generator polynomial.
 * More detailed description.
 * \param gen
 * \param errorWordCount
 * \return Function success (DmtxPass|DmtxFail)
 */
#undef CHKPASS
#define CHKPASS { if(passFail == DmtxFail) return DmtxFail; }
static DmtxPassFail
RsGenPoly(DmtxByteList *gen, int errorWordCount)
{
   int i, j;
   DmtxPassFail passFail;

   /* Initialize all coefficients to 1 */
   dmtxByteListInit(gen, errorWordCount, 1, &passFail); CHKPASS;

   /* Generate polynomial */
   for(i = 0; i < gen->length; i++)
   {
      for(j = i; j >= 0; j--)
      {
         gen->b[j] = GfMultAntilog(gen->b[j], i+1);
         if(j > 0)
            gen->b[j] = GfAdd(gen->b[j], gen->b[j-1]);
      }
   }

   return DmtxPass;
}

/**
 * Populate generator polynomial.
 * Assume we have received bits grouped into mm-bit symbols in rec[i],
 * i=0..(nn-1),  and rec[i] is index form (ie as powers of alpha). We first
 * compute the 2*tt syndromes by substituting alpha**i into rec(X) and
 * evaluating, storing the syndromes in syn[i], i=1..2tt (leave syn[0] zero).
 * \param syn
 * \param rec
 * \param blockErrorWords
 * \return Are error(s) present? (DmtxPass|DmtxFail)
 */
/* XXX this CHKPASS isn't doing what we want ... really need a error reporting strategy */
#undef CHKPASS
#define CHKPASS { if(passFail == DmtxFail) return DmtxTrue; }
static DmtxBoolean
RsComputeSyndromes(DmtxByteList *syn, const DmtxByteList *rec, int blockErrorWords)
{
   int i, j;
   DmtxPassFail passFail;
   DmtxBoolean error = DmtxFalse;

   /* Initialize all coefficients to 0 */
   dmtxByteListInit(syn, blockErrorWords + 1, 0, &passFail); CHKPASS;

   for(i = 1; i < syn->length; i++)
   {
      /* Calculate syndrome at i */
      for(j = 0; j < rec->length; j++) /* alternatively: j < blockTotalWords */
         syn->b[i] = GfAdd(syn->b[i], GfMultAntilog(rec->b[j], i*j));

      /* Non-zero syndrome indicates presence of error(s) */
      if(syn->b[i] != 0)
         error = DmtxTrue;
   }

   return error;
}

/**
 * Find the error location polynomial using Berlekamp-Massey.
 * More detailed description.
 * \param elpOut
 * \param syn
 * \param errorWordCount
 * \param maxCorrectable
 * \return Is block repairable? (DmtxTrue|DmtxFalse)
 */
/* XXX this CHKPASS isn't doing what we want ... really need a error reporting strategy */
#undef CHKPASS
#define CHKPASS { if(passFail == DmtxFail) return DmtxFalse; }
static DmtxBoolean
RsFindErrorLocatorPoly(DmtxByteList *elpOut, const DmtxByteList *syn, int errorWordCount, int maxCorrectable)
{
   int i, iNext, j;
   int m, mCmp, lambda;
   DmtxByte disTmp, disStorage[MAX_ERROR_WORD_COUNT+1];
   DmtxByte elpStorage[MAX_ERROR_WORD_COUNT+2][MAX_ERROR_WORD_COUNT];
   DmtxByteList dis, elp[MAX_ERROR_WORD_COUNT+2];
   DmtxPassFail passFail;

   dis = dmtxByteListBuild(disStorage, sizeof(disStorage));
   dmtxByteListInit(&dis, 0, 0, &passFail); CHKPASS;

   for(i = 0; i < MAX_ERROR_WORD_COUNT + 2; i++)
   {
      elp[i] = dmtxByteListBuild(elpStorage[i], sizeof(elpStorage[i]));
      dmtxByteListInit(&elp[i], 0, 0, &passFail); CHKPASS;
   }

   /* iNext = 0 */
   dmtxByteListPush(&elp[0], 1, &passFail); CHKPASS;
   dmtxByteListPush(&dis, 1, &passFail); CHKPASS;

   /* iNext = 1 */
   dmtxByteListPush(&elp[1], 1, &passFail); CHKPASS;
   dmtxByteListPush(&dis, syn->b[1], &passFail); CHKPASS;

   for(iNext = 2, i = 1; /* explicit break */; i = iNext++)
   {
      if(dis.b[i] == 0)
      {
         /* Simple case: Copy directly from previous iteration */
         dmtxByteListCopy(&elp[iNext], &elp[i], &passFail); CHKPASS;
      }
      else
      {
         /* Find earlier iteration (m) that provides maximal (m - lambda) */
         for(m = 0, mCmp = 1; mCmp < i; mCmp++)
            if(dis.b[mCmp] != 0 && (mCmp - elp[mCmp].length) >= (m - elp[m].length))
               m = mCmp;

         /* Calculate error location polynomial elp[i] (set 1st term) */
         for(lambda = elp[m].length - 1, j = 0; j <= lambda; j++)
            elp[iNext].b[j+i-m] = antilog301[(NN - log301[dis.b[m]] +
                  log301[dis.b[i]] + log301[elp[m].b[j]]) % NN];

         /* Calculate error location polynomial elp[i] (add 2nd term) */
         for(lambda = elp[i].length - 1, j = 0; j <= lambda; j++)
            elp[iNext].b[j] = GfAdd(elp[iNext].b[j], elp[i].b[j]);

         elp[iNext].length = max(elp[i].length, elp[m].length + i - m);
      }

      lambda = elp[iNext].length - 1;
      if(i == errorWordCount || i >= lambda + maxCorrectable)
         break;

      /* Calculate discrepancy dis.b[i] */
      for(disTmp = syn->b[iNext], j = 1; j <= lambda; j++)
         disTmp = GfAdd(disTmp, GfMult(syn->b[iNext-j], elp[iNext].b[j]));

      assert(dis.length == iNext);
      dmtxByteListPush(&dis, disTmp, &passFail); CHKPASS;
   }

   dmtxByteListCopy(elpOut, &elp[iNext], &passFail); CHKPASS;

   return (lambda <= maxCorrectable) ? DmtxTrue : DmtxFalse;
}

/**
 * Find roots of the error locator polynomial (Chien Search).
 * If the degree of elp is <= tt, we substitute alpha**i, i=1..n into the elp
 * to get the roots, hence the inverse roots, the error location numbers.
 * If the number of errors located does not equal the degree of the elp, we
 * have more than tt errors and cannot correct them.
 * \param loc
 * \param elp
 * \return Is block repairable? (DmtxTrue|DmtxFalse)
 */
#undef CHKPASS
#define CHKPASS { if(passFail == DmtxFail) return DmtxFalse; }
static DmtxBoolean
RsFindErrorLocations(DmtxByteList *loc, const DmtxByteList *elp)
{
   int i, j;
   int lambda = elp->length - 1;
   DmtxPassFail passFail;
   DmtxByte q, regStorage[MAX_ERROR_WORD_COUNT];
   DmtxByteList reg = dmtxByteListBuild(regStorage, sizeof(regStorage));

   dmtxByteListCopy(&reg, elp, &passFail); CHKPASS;
   dmtxByteListInit(loc, 0, 0, &passFail); CHKPASS;

   for(i = 1; i <= NN; i++)
   {
      for(q = 1, j = 1; j <= lambda; j++)
      {
         reg.b[j] = GfMultAntilog(reg.b[j], j);
         q = GfAdd(q, reg.b[j]);
      }

      if(q == 0)
      {
         dmtxByteListPush(loc, NN - i, &passFail); CHKPASS;
      }
   }

   return (loc->length == lambda) ? DmtxTrue : DmtxFalse;
}

/**
 * Find the error values and repair.
 * Solve for the error value at the error location and correct the error. The
 * procedure is that found in Lin and Costello.
 * For the cases where the number of errors is known to be too large to
 * correct, the information symbols as received are output (the advantage of
 * systematic encoding is that hopefully some of the information symbols will
 * be okay and that if we are in luck, the errors are in the parity part of
 * the transmitted codeword).
 * \param rec
 * \param loc
 * \param elp
 * \param syn
 */
#undef CHKPASS
#define CHKPASS { if(passFail == DmtxFail) return DmtxFail; }
static DmtxPassFail
RsRepairErrors(DmtxByteList *rec, const DmtxByteList *loc, const DmtxByteList *elp, const DmtxByteList *syn)
{
   int i, j, q;
   int lambda = elp->length - 1;
   DmtxPassFail passFail;
   DmtxByte zVal, root, err;
   DmtxByte zStorage[MAX_ERROR_WORD_COUNT+1];
   DmtxByteList z = dmtxByteListBuild(zStorage, sizeof(zStorage));

   /* Form polynomial z(x) */
   dmtxByteListPush(&z, 1, &passFail); CHKPASS;
   for(i = 1; i <= lambda; i++)
   {
      for(zVal = GfAdd(syn->b[i], elp->b[i]), j = 1; j < i; j++)
         zVal= GfAdd(zVal, GfMult(elp->b[i-j], syn->b[j]));
      dmtxByteListPush(&z, zVal, &passFail); CHKPASS;
   }

   for(i = 0; i < lambda; i++)
   {
      /* Calculate numerator of error term */
      root = NN - loc->b[i];

      for(err = 1, j = 1; j <= lambda; j++)
         err = GfAdd(err, GfMultAntilog(z.b[j], j * root));

      if(err == 0)
         continue;

      /* Calculate denominator of error term */
      for(q = 0, j = 0; j < lambda; j++)
      {
         if(j != i)
            q += log301[1 ^ antilog301[(loc->b[j] + root) % NN]];
      }
      q %= NN;

      err = GfMultAntilog(err, NN - q);
      rec->b[loc->b[i]] = GfAdd(rec->b[loc->b[i]], err);
   }

   return DmtxPass;
}
Added jni/libdmtx/dmtxregion.c.










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxregion.c
 * \brief Detect barcode regions
 */

#define DMTX_HOUGH_RES 180

/**
 * \brief  Create copy of existing region struct
 * \param  None
 * \return Initialized DmtxRegion struct
 */
extern DmtxRegion *
dmtxRegionCreate(DmtxRegion *reg)
{
   DmtxRegion *regCopy;

   regCopy = (DmtxRegion *)malloc(sizeof(DmtxRegion));
   if(regCopy == NULL)
      return NULL;

   memcpy(regCopy, reg, sizeof(DmtxRegion));

   return regCopy;
}

/**
 * \brief  Destroy region struct
 * \param  reg
 * \return void
 */
extern DmtxPassFail
dmtxRegionDestroy(DmtxRegion **reg)
{
   if(reg == NULL || *reg == NULL)
      return DmtxFail;

   free(*reg);

   *reg = NULL;

   return DmtxPass;
}

/**
 * \brief  Find next barcode region
 * \param  dec Pointer to DmtxDecode information struct
 * \param  timeout Pointer to timeout time (NULL if none)
 * \return Detected region (if found)
 */
extern DmtxRegion *
dmtxRegionFindNext(DmtxDecode *dec, DmtxTime *timeout)
{
   int locStatus;
   DmtxPixelLoc loc;
   DmtxRegion   *reg;

   /* Continue until we find a region or run out of chances */
   for(;;) {
      locStatus = PopGridLocation(&(dec->grid), &loc);
      if(locStatus == DmtxRangeEnd)
         break;

      /* Scan location for presence of valid barcode region */
      reg = dmtxRegionScanPixel(dec, loc.X, loc.Y);
      if(reg != NULL)
         return reg;

      /* Ran out of time? */
      if(timeout != NULL && dmtxTimeExceeded(*timeout))
         break;
   }

   return NULL;
}

/**
 * \brief  Scan individual pixel for presence of barcode edge
 * \param  dec Pointer to DmtxDecode information struct
 * \param  loc Pixel location
 * \return Detected region (if any)
 */
extern DmtxRegion *
dmtxRegionScanPixel(DmtxDecode *dec, int x, int y)
{
   unsigned char *cache;
   DmtxRegion reg;
   DmtxPointFlow flowBegin;
   DmtxPixelLoc loc;

   loc.X = x;
   loc.Y = y;

   cache = dmtxDecodeGetCache(dec, loc.X, loc.Y);
   if(cache == NULL)
      return NULL;

   if((int)(*cache & 0x80) != 0x00)
      return NULL;

   /* Test for presence of any reasonable edge at this location */
   flowBegin = MatrixRegionSeekEdge(dec, loc);
   if(flowBegin.mag < (int)(dec->edgeThresh * 7.65 + 0.5))
      return NULL;

   memset(&reg, 0x00, sizeof(DmtxRegion));

   /* Determine barcode orientation */
   if(MatrixRegionOrientation(dec, &reg, flowBegin) == DmtxFail)
      return NULL;
   if(dmtxRegionUpdateXfrms(dec, &reg) == DmtxFail)
      return NULL;

   /* Define top edge */
   if(MatrixRegionAlignCalibEdge(dec, &reg, DmtxEdgeTop) == DmtxFail)
      return NULL;
   if(dmtxRegionUpdateXfrms(dec, &reg) == DmtxFail)
      return NULL;

   /* Define right edge */
   if(MatrixRegionAlignCalibEdge(dec, &reg, DmtxEdgeRight) == DmtxFail)
      return NULL;
   if(dmtxRegionUpdateXfrms(dec, &reg) == DmtxFail)
      return NULL;

   CALLBACK_MATRIX(&reg);

   /* Calculate the best fitting symbol size */
   if(MatrixRegionFindSize(dec, &reg) == DmtxFail)
      return NULL;

   /* Found a valid matrix region */
   return dmtxRegionCreate(&reg);
}

/**
 *
 *
 */
static DmtxPointFlow
MatrixRegionSeekEdge(DmtxDecode *dec, DmtxPixelLoc loc)
{
   int i;
   int strongIdx;
   int channelCount;
   DmtxPointFlow flow, flowPlane[3];
   DmtxPointFlow flowPos, flowPosBack;
   DmtxPointFlow flowNeg, flowNegBack;

   channelCount = dec->image->channelCount;

   /* Find whether red, green, or blue shows the strongest edge */
   strongIdx = 0;
   for(i = 0; i < channelCount; i++) {
      flowPlane[i] = GetPointFlow(dec, i, loc, dmtxNeighborNone);
      if(i > 0 && flowPlane[i].mag > flowPlane[strongIdx].mag)
         strongIdx = i;
   }

   if(flowPlane[strongIdx].mag < 10)
      return dmtxBlankEdge;

   flow = flowPlane[strongIdx];

   flowPos = FindStrongestNeighbor(dec, flow, +1);
   flowNeg = FindStrongestNeighbor(dec, flow, -1);
   if(flowPos.mag != 0 && flowNeg.mag != 0) {
      flowPosBack = FindStrongestNeighbor(dec, flowPos, -1);
      flowNegBack = FindStrongestNeighbor(dec, flowNeg, +1);
      if(flowPos.arrive == (flowPosBack.arrive+4)%8 &&
            flowNeg.arrive == (flowNegBack.arrive+4)%8) {
         flow.arrive = dmtxNeighborNone;
         CALLBACK_POINT_PLOT(flow.loc, 1, 1, 1);
         return flow;
      }
   }

   return dmtxBlankEdge;
}

/**
 *
 *
 */
static DmtxPassFail
MatrixRegionOrientation(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow begin)
{
   int cross;
   int minArea;
   int scale;
   int symbolShape;
   int maxDiagonal;
   DmtxPassFail err;
   DmtxBestLine line1x, line2x;
   DmtxBestLine line2n, line2p;
   DmtxFollow fTmp;

   if(dec->sizeIdxExpected == DmtxSymbolSquareAuto ||
         (dec->sizeIdxExpected >= DmtxSymbol10x10 &&
         dec->sizeIdxExpected <= DmtxSymbol144x144))
      symbolShape = DmtxSymbolSquareAuto;
   else if(dec->sizeIdxExpected == DmtxSymbolRectAuto ||
         (dec->sizeIdxExpected >= DmtxSymbol8x18 &&
         dec->sizeIdxExpected <= DmtxSymbol16x48))
      symbolShape = DmtxSymbolRectAuto;
   else
      symbolShape = DmtxSymbolShapeAuto;

   if(dec->edgeMax != DmtxUndefined) {
      if(symbolShape == DmtxSymbolRectAuto)
         maxDiagonal = (int)(1.23 * dec->edgeMax + 0.5); /* sqrt(5/4) + 10% */
      else
         maxDiagonal = (int)(1.56 * dec->edgeMax + 0.5); /* sqrt(2) + 10% */
   }
   else {
      maxDiagonal = DmtxUndefined;
   }

   /* Follow to end in both directions */
   err = TrailBlazeContinuous(dec, reg, begin, maxDiagonal);
   if(err == DmtxFail || reg->stepsTotal < 40) {
      TrailClear(dec, reg, 0x40);
      return DmtxFail;
   }

   /* Filter out region candidates that are smaller than expected */
   if(dec->edgeMin != DmtxUndefined) {
      scale = dmtxDecodeGetProp(dec, DmtxPropScale);

      if(symbolShape == DmtxSymbolSquareAuto)
         minArea = (dec->edgeMin * dec->edgeMin)/(scale * scale);
      else
         minArea = (2 * dec->edgeMin * dec->edgeMin)/(scale * scale);

      if((reg->boundMax.X - reg->boundMin.X) * (reg->boundMax.Y - reg->boundMin.Y) < minArea) {
         TrailClear(dec, reg, 0x40);
         return DmtxFail;
      }
   }

   line1x = FindBestSolidLine(dec, reg, 0, 0, +1, DmtxUndefined);
   if(line1x.mag < 5) {
      TrailClear(dec, reg, 0x40);
      return DmtxFail;
   }

   err = FindTravelLimits(dec, reg, &line1x);
   if(line1x.distSq < 100 || line1x.devn * 10 >= sqrt((double)line1x.distSq)) {
      TrailClear(dec, reg, 0x40);
      return DmtxFail;
   }
   assert(line1x.stepPos >= line1x.stepNeg);

   fTmp = FollowSeek(dec, reg, line1x.stepPos + 5);
   line2p = FindBestSolidLine(dec, reg, fTmp.step, line1x.stepNeg, +1, line1x.angle);

   fTmp = FollowSeek(dec, reg, line1x.stepNeg - 5);
   line2n = FindBestSolidLine(dec, reg, fTmp.step, line1x.stepPos, -1, line1x.angle);
   if(max(line2p.mag, line2n.mag) < 5)
      return DmtxFail;

   if(line2p.mag > line2n.mag) {
      line2x = line2p;
      err = FindTravelLimits(dec, reg, &line2x);
      if(line2x.distSq < 100 || line2x.devn * 10 >= sqrt((double)line2x.distSq))
         return DmtxFail;

      cross = ((line1x.locPos.X - line1x.locNeg.X) * (line2x.locPos.Y - line2x.locNeg.Y)) -
            ((line1x.locPos.Y - line1x.locNeg.Y) * (line2x.locPos.X - line2x.locNeg.X));
      if(cross > 0) {
         /* Condition 2 */
         reg->polarity = +1;
         reg->locR = line2x.locPos;
         reg->stepR = line2x.stepPos;
         reg->locT = line1x.locNeg;
         reg->stepT = line1x.stepNeg;
         reg->leftLoc = line1x.locBeg;
         reg->leftAngle = line1x.angle;
         reg->bottomLoc = line2x.locBeg;
         reg->bottomAngle = line2x.angle;
         reg->leftLine = line1x;
         reg->bottomLine = line2x;
      }
      else {
         /* Condition 3 */
         reg->polarity = -1;
         reg->locR = line1x.locNeg;
         reg->stepR = line1x.stepNeg;
         reg->locT = line2x.locPos;
         reg->stepT = line2x.stepPos;
         reg->leftLoc = line2x.locBeg;
         reg->leftAngle = line2x.angle;
         reg->bottomLoc = line1x.locBeg;
         reg->bottomAngle = line1x.angle;
         reg->leftLine = line2x;
         reg->bottomLine = line1x;
      }
   }
   else {
      line2x = line2n;
      err = FindTravelLimits(dec, reg, &line2x);
      if(line2x.distSq < 100 || line2x.devn / sqrt((double)line2x.distSq) >= 0.1)
         return DmtxFail;

      cross = ((line1x.locNeg.X - line1x.locPos.X) * (line2x.locNeg.Y - line2x.locPos.Y)) -
            ((line1x.locNeg.Y - line1x.locPos.Y) * (line2x.locNeg.X - line2x.locPos.X));
      if(cross > 0) {
         /* Condition 1 */
         reg->polarity = -1;
         reg->locR = line2x.locNeg;
         reg->stepR = line2x.stepNeg;
         reg->locT = line1x.locPos;
         reg->stepT = line1x.stepPos;
         reg->leftLoc = line1x.locBeg;
         reg->leftAngle = line1x.angle;
         reg->bottomLoc = line2x.locBeg;
         reg->bottomAngle = line2x.angle;
         reg->leftLine = line1x;
         reg->bottomLine = line2x;
      }
      else {
         /* Condition 4 */
         reg->polarity = +1;
         reg->locR = line1x.locPos;
         reg->stepR = line1x.stepPos;
         reg->locT = line2x.locNeg;
         reg->stepT = line2x.stepNeg;
         reg->leftLoc = line2x.locBeg;
         reg->leftAngle = line2x.angle;
         reg->bottomLoc = line1x.locBeg;
         reg->bottomAngle = line1x.angle;
         reg->leftLine = line2x;
         reg->bottomLine = line1x;
      }
   }
/* CALLBACK_POINT_PLOT(reg->locR, 2, 1, 1);
   CALLBACK_POINT_PLOT(reg->locT, 2, 1, 1); */

   reg->leftKnown = reg->bottomKnown = 1;

   return DmtxPass;
}

/**
 *
 *
 */
static long
DistanceSquared(DmtxPixelLoc a, DmtxPixelLoc b)
{
   long xDelta, yDelta;

   xDelta = a.X - b.X;
   yDelta = a.Y - b.Y;

   return (xDelta * xDelta) + (yDelta * yDelta);
}

/**
 *
 *
 */
extern DmtxPassFail
dmtxRegionUpdateCorners(DmtxDecode *dec, DmtxRegion *reg, DmtxVector2 p00,
      DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01)
{
   double xMax, yMax;
   double tx, ty, phi, shx, scx, scy, skx, sky;
   double dimOT, dimOR, dimTX, dimRX, ratio;
   DmtxVector2 vOT, vOR, vTX, vRX, vTmp;
   DmtxMatrix3 m, mtxy, mphi, mshx, mscx, mscy, mscxy, msky, mskx;

   xMax = (double)(dmtxDecodeGetProp(dec, DmtxPropWidth) - 1);
   yMax = (double)(dmtxDecodeGetProp(dec, DmtxPropHeight) - 1);

   if(p00.X < 0.0 || p00.Y < 0.0 || p00.X > xMax || p00.Y > yMax ||
         p01.X < 0.0 || p01.Y < 0.0 || p01.X > xMax || p01.Y > yMax ||
         p10.X < 0.0 || p10.Y < 0.0 || p10.X > xMax || p10.Y > yMax)
      return DmtxFail;

   dimOT = dmtxVector2Mag(dmtxVector2Sub(&vOT, &p01, &p00)); /* XXX could use MagSquared() */
   dimOR = dmtxVector2Mag(dmtxVector2Sub(&vOR, &p10, &p00));
   dimTX = dmtxVector2Mag(dmtxVector2Sub(&vTX, &p11, &p01));
   dimRX = dmtxVector2Mag(dmtxVector2Sub(&vRX, &p11, &p10));

   /* Verify that sides are reasonably long */
   if(dimOT <= 8.0 || dimOR <= 8.0 || dimTX <= 8.0 || dimRX <= 8.0)
      return DmtxFail;

   /* Verify that the 4 corners define a reasonably fat quadrilateral */
   ratio = dimOT / dimRX;
   if(ratio <= 0.5 || ratio >= 2.0)
      return DmtxFail;

   ratio = dimOR / dimTX;
   if(ratio <= 0.5 || ratio >= 2.0)
      return DmtxFail;

   /* Verify this is not a bowtie shape */
   if(dmtxVector2Cross(&vOR, &vRX) <= 0.0 ||
         dmtxVector2Cross(&vOT, &vTX) >= 0.0)
      return DmtxFail;

   if(RightAngleTrueness(p00, p10, p11, M_PI_2) <= dec->squareDevn)
      return DmtxFail;
   if(RightAngleTrueness(p10, p11, p01, M_PI_2) <= dec->squareDevn)
      return DmtxFail;

   /* Calculate values needed for transformations */
   tx = -1 * p00.X;
   ty = -1 * p00.Y;
   dmtxMatrix3Translate(mtxy, tx, ty);

   phi = atan2(vOT.X, vOT.Y);
   dmtxMatrix3Rotate(mphi, phi);
   dmtxMatrix3Multiply(m, mtxy, mphi);

   dmtxMatrix3VMultiply(&vTmp, &p10, m);
   shx = -vTmp.Y / vTmp.X;
   dmtxMatrix3Shear(mshx, 0.0, shx);
   dmtxMatrix3MultiplyBy(m, mshx);

   scx = 1.0/vTmp.X;
   dmtxMatrix3Scale(mscx, scx, 1.0);
   dmtxMatrix3MultiplyBy(m, mscx);

   dmtxMatrix3VMultiply(&vTmp, &p11, m);
   scy = 1.0/vTmp.Y;
   dmtxMatrix3Scale(mscy, 1.0, scy);
   dmtxMatrix3MultiplyBy(m, mscy);

   dmtxMatrix3VMultiply(&vTmp, &p11, m);
   skx = vTmp.X;
   dmtxMatrix3LineSkewSide(mskx, 1.0, skx, 1.0);
   dmtxMatrix3MultiplyBy(m, mskx);

   dmtxMatrix3VMultiply(&vTmp, &p01, m);
   sky = vTmp.Y;
   dmtxMatrix3LineSkewTop(msky, sky, 1.0, 1.0);
   dmtxMatrix3Multiply(reg->raw2fit, m, msky);

   /* Create inverse matrix by reverse (avoid straight matrix inversion) */
   dmtxMatrix3LineSkewTopInv(msky, sky, 1.0, 1.0);
   dmtxMatrix3LineSkewSideInv(mskx, 1.0, skx, 1.0);
   dmtxMatrix3Multiply(m, msky, mskx);

   dmtxMatrix3Scale(mscxy, 1.0/scx, 1.0/scy);
   dmtxMatrix3MultiplyBy(m, mscxy);

   dmtxMatrix3Shear(mshx, 0.0, -shx);
   dmtxMatrix3MultiplyBy(m, mshx);

   dmtxMatrix3Rotate(mphi, -phi);
   dmtxMatrix3MultiplyBy(m, mphi);

   dmtxMatrix3Translate(mtxy, -tx, -ty);
   dmtxMatrix3Multiply(reg->fit2raw, m, mtxy);

   return DmtxPass;
}

/**
 *
 *
 */
extern DmtxPassFail
dmtxRegionUpdateXfrms(DmtxDecode *dec, DmtxRegion *reg)
{
   double radians;
   DmtxRay2 rLeft, rBottom, rTop, rRight;
   DmtxVector2 p00, p10, p11, p01;

   assert(reg->leftKnown != 0 && reg->bottomKnown != 0);

   /* Build ray representing left edge */
   rLeft.p.X = (double)reg->leftLoc.X;
   rLeft.p.Y = (double)reg->leftLoc.Y;
   radians = reg->leftAngle * (M_PI/DMTX_HOUGH_RES);
   rLeft.v.X = cos(radians);
   rLeft.v.Y = sin(radians);
   rLeft.tMin = 0.0;
   rLeft.tMax = dmtxVector2Norm(&rLeft.v);

   /* Build ray representing bottom edge */
   rBottom.p.X = (double)reg->bottomLoc.X;
   rBottom.p.Y = (double)reg->bottomLoc.Y;
   radians = reg->bottomAngle * (M_PI/DMTX_HOUGH_RES);
   rBottom.v.X = cos(radians);
   rBottom.v.Y = sin(radians);
   rBottom.tMin = 0.0;
   rBottom.tMax = dmtxVector2Norm(&rBottom.v);

   /* Build ray representing top edge */
   if(reg->topKnown != 0) {
      rTop.p.X = (double)reg->topLoc.X;
      rTop.p.Y = (double)reg->topLoc.Y;
      radians = reg->topAngle * (M_PI/DMTX_HOUGH_RES);
      rTop.v.X = cos(radians);
      rTop.v.Y = sin(radians);
      rTop.tMin = 0.0;
      rTop.tMax = dmtxVector2Norm(&rTop.v);
   }
   else {
      rTop.p.X = (double)reg->locT.X;
      rTop.p.Y = (double)reg->locT.Y;
      radians = reg->bottomAngle * (M_PI/DMTX_HOUGH_RES);
      rTop.v.X = cos(radians);
      rTop.v.Y = sin(radians);
      rTop.tMin = 0.0;
      rTop.tMax = rBottom.tMax;
   }

   /* Build ray representing right edge */
   if(reg->rightKnown != 0) {
      rRight.p.X = (double)reg->rightLoc.X;
      rRight.p.Y = (double)reg->rightLoc.Y;
      radians = reg->rightAngle * (M_PI/DMTX_HOUGH_RES);
      rRight.v.X = cos(radians);
      rRight.v.Y = sin(radians);
      rRight.tMin = 0.0;
      rRight.tMax = dmtxVector2Norm(&rRight.v);
   }
   else {
      rRight.p.X = (double)reg->locR.X;
      rRight.p.Y = (double)reg->locR.Y;
      radians = reg->leftAngle * (M_PI/DMTX_HOUGH_RES);
      rRight.v.X = cos(radians);
      rRight.v.Y = sin(radians);
      rRight.tMin = 0.0;
      rRight.tMax = rLeft.tMax;
   }

   /* Calculate 4 corners, real or imagined */
   if(dmtxRay2Intersect(&p00, &rLeft, &rBottom) == DmtxFail)
      return DmtxFail;

   if(dmtxRay2Intersect(&p10, &rBottom, &rRight) == DmtxFail)
      return DmtxFail;

   if(dmtxRay2Intersect(&p11, &rRight, &rTop) == DmtxFail)
      return DmtxFail;

   if(dmtxRay2Intersect(&p01, &rTop, &rLeft) == DmtxFail)
      return DmtxFail;

   if(dmtxRegionUpdateCorners(dec, reg, p00, p10, p11, p01) != DmtxPass)
      return DmtxFail;

   return DmtxPass;
}

/**
 *
 *
 */
static double
RightAngleTrueness(DmtxVector2 c0, DmtxVector2 c1, DmtxVector2 c2, double angle)
{
   DmtxVector2 vA, vB;
   DmtxMatrix3 m;

   dmtxVector2Norm(dmtxVector2Sub(&vA, &c0, &c1));
   dmtxVector2Norm(dmtxVector2Sub(&vB, &c2, &c1));

   dmtxMatrix3Rotate(m, angle);
   dmtxMatrix3VMultiplyBy(&vB, m);

   return dmtxVector2Dot(&vA, &vB);
}

/**
 * \brief  Read color of Data Matrix module location
 * \param  dec
 * \param  reg
 * \param  symbolRow
 * \param  symbolCol
 * \param  sizeIdx
 * \return Averaged module color
 */
static int
ReadModuleColor(DmtxDecode *dec, DmtxRegion *reg, int symbolRow, int symbolCol,
      int sizeIdx, int colorPlane)
{
   int err;
   int i;
   int symbolRows, symbolCols;
   int color, colorTmp;
   double sampleX[] = { 0.5, 0.4, 0.5, 0.6, 0.5 };
   double sampleY[] = { 0.5, 0.5, 0.4, 0.5, 0.6 };
   DmtxVector2 p;

   symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
   symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx);

   color = 0;
   for(i = 0; i < 5; i++) {

      p.X = (1.0/symbolCols) * (symbolCol + sampleX[i]);
      p.Y = (1.0/symbolRows) * (symbolRow + sampleY[i]);

      dmtxMatrix3VMultiplyBy(&p, reg->fit2raw);

      err = dmtxDecodeGetPixelValue(dec, (int)(p.X + 0.5), (int)(p.Y + 0.5),
            colorPlane, &colorTmp);
      color += colorTmp;
   }

   return color/5;
}

/**
 * \brief  Determine barcode size, expressed in modules
 * \param  image
 * \param  reg
 * \return DmtxPass | DmtxFail
 */
static DmtxPassFail
MatrixRegionFindSize(DmtxDecode *dec, DmtxRegion *reg)
{
   int row, col;
   int sizeIdxBeg, sizeIdxEnd;
   int sizeIdx, bestSizeIdx;
   int symbolRows, symbolCols;
   int jumpCount, errors;
   int color;
   int colorOnAvg, bestColorOnAvg;
   int colorOffAvg, bestColorOffAvg;
   int contrast, bestContrast;
   DmtxImage *img;

   img = dec->image;
   bestSizeIdx = DmtxUndefined;
   bestContrast = 0;
   bestColorOnAvg = bestColorOffAvg = 0;

   if(dec->sizeIdxExpected == DmtxSymbolShapeAuto) {
      sizeIdxBeg = 0;
      sizeIdxEnd = DmtxSymbolSquareCount + DmtxSymbolRectCount;
   }
   else if(dec->sizeIdxExpected == DmtxSymbolSquareAuto) {
      sizeIdxBeg = 0;
      sizeIdxEnd = DmtxSymbolSquareCount;
   }
   else if(dec->sizeIdxExpected == DmtxSymbolRectAuto) {
      sizeIdxBeg = DmtxSymbolSquareCount;
      sizeIdxEnd = DmtxSymbolSquareCount + DmtxSymbolRectCount;
   }
   else {
      sizeIdxBeg = dec->sizeIdxExpected;
      sizeIdxEnd = dec->sizeIdxExpected + 1;
   }

   /* Test each barcode size to find best contrast in calibration modules */
   for(sizeIdx = sizeIdxBeg; sizeIdx < sizeIdxEnd; sizeIdx++) {

      symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, sizeIdx);
      symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, sizeIdx);
      colorOnAvg = colorOffAvg = 0;

      /* Sum module colors along horizontal calibration bar */
      row = symbolRows - 1;
      for(col = 0; col < symbolCols; col++) {
         color = ReadModuleColor(dec, reg, row, col, sizeIdx, reg->flowBegin.plane);
         if((col & 0x01) != 0x00)
            colorOffAvg += color;
         else
            colorOnAvg += color;
      }

      /* Sum module colors along vertical calibration bar */
      col = symbolCols - 1;
      for(row = 0; row < symbolRows; row++) {
         color = ReadModuleColor(dec, reg, row, col, sizeIdx, reg->flowBegin.plane);
         if((row & 0x01) != 0x00)
            colorOffAvg += color;
         else
            colorOnAvg += color;
      }

      colorOnAvg = (colorOnAvg * 2)/(symbolRows + symbolCols);
      colorOffAvg = (colorOffAvg * 2)/(symbolRows + symbolCols);

      contrast = abs(colorOnAvg - colorOffAvg);
      if(contrast < 20)
         continue;

      if(contrast > bestContrast) {
         bestContrast = contrast;
         bestSizeIdx = sizeIdx;
         bestColorOnAvg = colorOnAvg;
         bestColorOffAvg = colorOffAvg;
      }
   }

   /* If no sizes produced acceptable contrast then call it quits */
   if(bestSizeIdx == DmtxUndefined || bestContrast < 20)
      return DmtxFail;

   reg->sizeIdx = bestSizeIdx;
   reg->onColor = bestColorOnAvg;
   reg->offColor = bestColorOffAvg;

   reg->symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, reg->sizeIdx);
   reg->symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, reg->sizeIdx);
   reg->mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, reg->sizeIdx);
   reg->mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, reg->sizeIdx);

   /* Tally jumps on horizontal calibration bar to verify sizeIdx */
   jumpCount = CountJumpTally(dec, reg, 0, reg->symbolRows - 1, DmtxDirRight);
   errors = abs(1 + jumpCount - reg->symbolCols);
   if(jumpCount < 0 || errors > 2)
      return DmtxFail;

   /* Tally jumps on vertical calibration bar to verify sizeIdx */
   jumpCount = CountJumpTally(dec, reg, reg->symbolCols - 1, 0, DmtxDirUp);
   errors = abs(1 + jumpCount - reg->symbolRows);
   if(jumpCount < 0 || errors > 2)
      return DmtxFail;

   /* Tally jumps on horizontal finder bar to verify sizeIdx */
   errors = CountJumpTally(dec, reg, 0, 0, DmtxDirRight);
   if(jumpCount < 0 || errors > 2)
      return DmtxFail;

   /* Tally jumps on vertical finder bar to verify sizeIdx */
   errors = CountJumpTally(dec, reg, 0, 0, DmtxDirUp);
   if(errors < 0 || errors > 2)
      return DmtxFail;

   /* Tally jumps on surrounding whitespace, else fail */
   errors = CountJumpTally(dec, reg, 0, -1, DmtxDirRight);
   if(errors < 0 || errors > 2)
      return DmtxFail;

   errors = CountJumpTally(dec, reg, -1, 0, DmtxDirUp);
   if(errors < 0 || errors > 2)
      return DmtxFail;

   errors = CountJumpTally(dec, reg, 0, reg->symbolRows, DmtxDirRight);
   if(errors < 0 || errors > 2)
      return DmtxFail;

   errors = CountJumpTally(dec, reg, reg->symbolCols, 0, DmtxDirUp);
   if(errors < 0 || errors > 2)
      return DmtxFail;

   return DmtxPass;
}

/**
 * \brief  Count the number of number of transitions between light and dark
 * \param  img
 * \param  reg
 * \param  xStart
 * \param  yStart
 * \param  dir
 * \return Jump count
 */
static int
CountJumpTally(DmtxDecode *dec, DmtxRegion *reg, int xStart, int yStart, DmtxDirection dir)
{
   int x, xInc = 0;
   int y, yInc = 0;
   int state = DmtxModuleOn;
   int jumpCount = 0;
   int jumpThreshold;
   int tModule, tPrev;
   int darkOnLight;
   int color;

   assert(xStart == 0 || yStart == 0);
   assert(dir == DmtxDirRight || dir == DmtxDirUp);

   if(dir == DmtxDirRight)
      xInc = 1;
   else
      yInc = 1;

   if(xStart == -1 || xStart == reg->symbolCols ||
         yStart == -1 || yStart == reg->symbolRows)
      state = DmtxModuleOff;

   darkOnLight = (int)(reg->offColor > reg->onColor);
   jumpThreshold = abs((int)(0.4 * (reg->onColor - reg->offColor) + 0.5));
   color = ReadModuleColor(dec, reg, yStart, xStart, reg->sizeIdx, reg->flowBegin.plane);
   tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor;

   for(x = xStart + xInc, y = yStart + yInc;
         (dir == DmtxDirRight && x < reg->symbolCols) ||
         (dir == DmtxDirUp && y < reg->symbolRows);
         x += xInc, y += yInc) {

      tPrev = tModule;
      color = ReadModuleColor(dec, reg, y, x, reg->sizeIdx, reg->flowBegin.plane);
      tModule = (darkOnLight) ? reg->offColor - color : color - reg->offColor;

      if(state == DmtxModuleOff) {
         if(tModule > tPrev + jumpThreshold) {
            jumpCount++;
            state = DmtxModuleOn;
         }
      }
      else {
         if(tModule < tPrev - jumpThreshold) {
            jumpCount++;
            state = DmtxModuleOff;
         }
      }
   }

   return jumpCount;
}

/**
 *
 *
 */
static DmtxPointFlow
GetPointFlow(DmtxDecode *dec, int colorPlane, DmtxPixelLoc loc, int arrive)
{
   static const int coefficient[] = {  0,  1,  2,  1,  0, -1, -2, -1 };
   int err;
   int patternIdx, coefficientIdx;
   int compass, compassMax;
   int mag[4] = { 0 };
   int xAdjust, yAdjust;
   int color, colorPattern[8];
   DmtxPointFlow flow;

   for(patternIdx = 0; patternIdx < 8; patternIdx++) {
      xAdjust = loc.X + dmtxPatternX[patternIdx];
      yAdjust = loc.Y + dmtxPatternY[patternIdx];
      err = dmtxDecodeGetPixelValue(dec, xAdjust, yAdjust, colorPlane,
            &colorPattern[patternIdx]);
      if(err == DmtxFail)
         return dmtxBlankEdge;
   }

   /* Calculate this pixel's flow intensity for each direction (-45, 0, 45, 90) */
   compassMax = 0;
   for(compass = 0; compass < 4; compass++) {

      /* Add portion from each position in the convolution matrix pattern */
      for(patternIdx = 0; patternIdx < 8; patternIdx++) {

         coefficientIdx = (patternIdx - compass + 8) % 8;
         if(coefficient[coefficientIdx] == 0)
            continue;

         color = colorPattern[patternIdx];

         switch(coefficient[coefficientIdx]) {
            case 2:
               mag[compass] += color;
               /* Fall through */
            case 1:
               mag[compass] += color;
               break;
            case -2:
               mag[compass] -= color;
               /* Fall through */
            case -1:
               mag[compass] -= color;
               break;
         }
      }

      /* Identify strongest compass flow */
      if(compass != 0 && abs(mag[compass]) > abs(mag[compassMax]))
         compassMax = compass;
   }

   /* Convert signed compass direction into unique flow directions (0-7) */
   flow.plane = colorPlane;
   flow.arrive = arrive;
   flow.depart = (mag[compassMax] > 0) ? compassMax + 4 : compassMax;
   flow.mag = abs(mag[compassMax]);
   flow.loc = loc;

   return flow;
}

/**
 *
 *
 */
static DmtxPointFlow
FindStrongestNeighbor(DmtxDecode *dec, DmtxPointFlow center, int sign)
{
   int i;
   int strongIdx;
   int attempt, attemptDiff;
   int occupied;
   unsigned char *cache;
   DmtxPixelLoc loc;
   DmtxPointFlow flow[8];

   attempt = (sign < 0) ? center.depart : (center.depart+4)%8;

   occupied = 0;
   strongIdx = DmtxUndefined;
   for(i = 0; i < 8; i++) {

      loc.X = center.loc.X + dmtxPatternX[i];
      loc.Y = center.loc.Y + dmtxPatternY[i];

      cache = dmtxDecodeGetCache(dec, loc.X, loc.Y);
      if(cache == NULL)
         continue;

      if((int)(*cache & 0x80) != 0x00) {
         if(++occupied > 2)
            return dmtxBlankEdge;
         else
            continue;
      }

      attemptDiff = abs(attempt - i);
      if(attemptDiff > 4)
         attemptDiff = 8 - attemptDiff;
      if(attemptDiff > 1)
         continue;

      flow[i] = GetPointFlow(dec, center.plane, loc, i);

      if(strongIdx == DmtxUndefined || flow[i].mag > flow[strongIdx].mag ||
            (flow[i].mag == flow[strongIdx].mag && ((i & 0x01) != 0))) {
         strongIdx = i;
      }
   }

   return (strongIdx == DmtxUndefined) ? dmtxBlankEdge : flow[strongIdx];
}

/**
 *
 *
 */
static DmtxFollow
FollowSeek(DmtxDecode *dec, DmtxRegion *reg, int seek)
{
   int i;
   int sign;
   DmtxFollow follow;

   follow.loc = reg->flowBegin.loc;
   follow.step = 0;
   follow.ptr = dmtxDecodeGetCache(dec, follow.loc.X, follow.loc.Y);
   assert(follow.ptr != NULL);
   follow.neighbor = *follow.ptr;

   sign = (seek > 0) ? +1 : -1;
   for(i = 0; i != seek; i += sign) {
      follow = FollowStep(dec, reg, follow, sign);
      assert(follow.ptr != NULL);
      assert(abs(follow.step) <= reg->stepsTotal);
   }

   return follow;
}

/**
 *
 *
 */
static DmtxFollow
FollowSeekLoc(DmtxDecode *dec, DmtxPixelLoc loc)
{
   DmtxFollow follow;

   follow.loc = loc;
   follow.step = 0;
   follow.ptr = dmtxDecodeGetCache(dec, follow.loc.X, follow.loc.Y);
   assert(follow.ptr != NULL);
   follow.neighbor = *follow.ptr;

   return follow;
}


/**
 *
 *
 */
static DmtxFollow
FollowStep(DmtxDecode *dec, DmtxRegion *reg, DmtxFollow followBeg, int sign)
{
   int patternIdx;
   int stepMod;
   int factor;
   DmtxFollow follow;

   assert(abs(sign) == 1);
   assert((int)(followBeg.neighbor & 0x40) != 0x00);

   factor = reg->stepsTotal + 1;
   if(sign > 0)
      stepMod = (factor + (followBeg.step % factor)) % factor;
   else
      stepMod = (factor - (followBeg.step % factor)) % factor;

   /* End of positive trail -- magic jump */
   if(sign > 0 && stepMod == reg->jumpToNeg) {
      follow.loc = reg->finalNeg;
   }
   /* End of negative trail -- magic jump */
   else if(sign < 0 && stepMod == reg->jumpToPos) {
      follow.loc = reg->finalPos;
   }
   /* Trail in progress -- normal jump */
   else {
      patternIdx = (sign < 0) ? followBeg.neighbor & 0x07 : ((followBeg.neighbor & 0x38) >> 3);
      follow.loc.X = followBeg.loc.X + dmtxPatternX[patternIdx];
      follow.loc.Y = followBeg.loc.Y + dmtxPatternY[patternIdx];
   }

   follow.step = followBeg.step + sign;
   follow.ptr = dmtxDecodeGetCache(dec, follow.loc.X, follow.loc.Y);
   assert(follow.ptr != NULL);
   follow.neighbor = *follow.ptr;

   return follow;
}

/**
 *
 *
 */
static DmtxFollow
FollowStep2(DmtxDecode *dec, DmtxFollow followBeg, int sign)
{
   int patternIdx;
   DmtxFollow follow;

   assert(abs(sign) == 1);
   assert((int)(followBeg.neighbor & 0x40) != 0x00);

   patternIdx = (sign < 0) ? followBeg.neighbor & 0x07 : ((followBeg.neighbor & 0x38) >> 3);
   follow.loc.X = followBeg.loc.X + dmtxPatternX[patternIdx];
   follow.loc.Y = followBeg.loc.Y + dmtxPatternY[patternIdx];

   follow.step = followBeg.step + sign;
   follow.ptr = dmtxDecodeGetCache(dec, follow.loc.X, follow.loc.Y);
   assert(follow.ptr != NULL);
   follow.neighbor = *follow.ptr;

   return follow;
}

/**
 * vaiiiooo
 * --------
 * 0x80 v = visited bit
 * 0x40 a = assigned bit
 * 0x38 u = 3 bits points upstream 0-7
 * 0x07 d = 3 bits points downstream 0-7
 */
static DmtxPassFail
TrailBlazeContinuous(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow flowBegin, int maxDiagonal)
{
   int posAssigns, negAssigns, clears;
   int sign;
   int steps;
   unsigned char *cache, *cacheNext, *cacheBeg;
   DmtxPointFlow flow, flowNext;
   DmtxPixelLoc boundMin, boundMax;

   boundMin = boundMax = flowBegin.loc;
   cacheBeg = dmtxDecodeGetCache(dec, flowBegin.loc.X, flowBegin.loc.Y);
   if(cacheBeg == NULL)
      return DmtxFail;
   *cacheBeg = (0x80 | 0x40); /* Mark location as visited and assigned */

   reg->flowBegin = flowBegin;

   posAssigns = negAssigns = 0;
   for(sign = 1; sign >= -1; sign -= 2) {

      flow = flowBegin;
      cache = cacheBeg;

      for(steps = 0; ; steps++) {

         if(maxDiagonal != DmtxUndefined && (boundMax.X - boundMin.X > maxDiagonal ||
               boundMax.Y - boundMin.Y > maxDiagonal))
            break;

         /* Find the strongest eligible neighbor */
         flowNext = FindStrongestNeighbor(dec, flow, sign);
         if(flowNext.mag < 50)
            break;

         /* Get the neighbor's cache location */
         cacheNext = dmtxDecodeGetCache(dec, flowNext.loc.X, flowNext.loc.Y);
         if(cacheNext == NULL)
            break;
         assert(!(*cacheNext & 0x80));

         /* Mark departure from current location. If flowing downstream
          * (sign < 0) then departure vector here is the arrival vector
          * of the next location. Upstream flow uses the opposite rule. */
         *cache |= (sign < 0) ? flowNext.arrive : flowNext.arrive << 3;

         /* Mark known direction for next location */
         /* If testing downstream (sign < 0) then next upstream is opposite of next arrival */
         /* If testing upstream (sign > 0) then next downstream is opposite of next arrival */
         *cacheNext = (sign < 0) ? (((flowNext.arrive + 4)%8) << 3) : ((flowNext.arrive + 4)%8);
         *cacheNext |= (0x80 | 0x40); /* Mark location as visited and assigned */
         if(sign > 0)
            posAssigns++;
         else
            negAssigns++;
         cache = cacheNext;
         flow = flowNext;

         if(flow.loc.X > boundMax.X)
            boundMax.X = flow.loc.X;
         else if(flow.loc.X < boundMin.X)
            boundMin.X = flow.loc.X;
         if(flow.loc.Y > boundMax.Y)
            boundMax.Y = flow.loc.Y;
         else if(flow.loc.Y < boundMin.Y)
            boundMin.Y = flow.loc.Y;

/*       CALLBACK_POINT_PLOT(flow.loc, (sign > 0) ? 2 : 3, 1, 2); */
      }

      if(sign > 0) {
         reg->finalPos = flow.loc;
         reg->jumpToNeg = steps;
      }
      else {
         reg->finalNeg = flow.loc;
         reg->jumpToPos = steps;
      }
   }
   reg->stepsTotal = reg->jumpToPos + reg->jumpToNeg;
   reg->boundMin = boundMin;
   reg->boundMax = boundMax;

   /* Clear "visited" bit from trail */
   clears = TrailClear(dec, reg, 0x80);
   assert(posAssigns + negAssigns == clears - 1);

   /* XXX clean this up ... redundant test above */
   if(maxDiagonal != DmtxUndefined && (boundMax.X - boundMin.X > maxDiagonal ||
         boundMax.Y - boundMin.Y > maxDiagonal))
      return DmtxFail;

   return DmtxPass;
}

/**
 * recives bresline, and follows strongest neighbor unless it involves
 * ratcheting bresline inward or backward (although back + outward is allowed).
 *
 */
static int
TrailBlazeGapped(DmtxDecode *dec, DmtxRegion *reg, DmtxBresLine line, int streamDir)
{
   unsigned char *beforeCache, *afterCache;
   DmtxBoolean onEdge;
   int distSq, distSqMax;
   int travel, outward;
   int xDiff, yDiff;
   int steps;
   int stepDir, dirMap[] = { 0, 1, 2, 7, 8, 3, 6, 5, 4 };
   DmtxPassFail err;
   DmtxPixelLoc beforeStep, afterStep;
   DmtxPointFlow flow, flowNext;
   DmtxPixelLoc loc0;
   int xStep, yStep;

   loc0 = line.loc;
   flow = GetPointFlow(dec, reg->flowBegin.plane, loc0, dmtxNeighborNone);
   distSqMax = (line.xDelta * line.xDelta) + (line.yDelta * line.yDelta);
   steps = 0;
   onEdge = DmtxTrue;

   beforeStep = loc0;
   beforeCache = dmtxDecodeGetCache(dec, loc0.X, loc0.Y);
   if(beforeCache == NULL)
      return DmtxFail;
   else
      *beforeCache = 0x00; /* probably should just overwrite one direction */

   do {
      if(onEdge == DmtxTrue) {
         flowNext = FindStrongestNeighbor(dec, flow, streamDir);
         if(flowNext.mag == DmtxUndefined)
            break;

         err = BresLineGetStep(line, flowNext.loc, &travel, &outward);
         if(flowNext.mag < 50 || outward < 0 || (outward == 0 && travel < 0)) {
            onEdge = DmtxFalse;
         }
         else {
            BresLineStep(&line, travel, outward);
            flow = flowNext;
         }
      }

      if(onEdge == DmtxFalse) {
         BresLineStep(&line, 1, 0);
         flow = GetPointFlow(dec, reg->flowBegin.plane, line.loc, dmtxNeighborNone);
         if(flow.mag > 50)
            onEdge = DmtxTrue;
      }

      afterStep = line.loc;
      afterCache = dmtxDecodeGetCache(dec, afterStep.X, afterStep.Y);
      if(afterCache == NULL)
         break;

      /* Determine step direction using pure magic */
      xStep = afterStep.X - beforeStep.X;
      yStep = afterStep.Y - beforeStep.Y;
      assert(abs(xStep) <= 1 && abs(yStep) <= 1);
      stepDir = dirMap[3 * yStep + xStep + 4];
      assert(stepDir != 8);

      if(streamDir < 0) {
         *beforeCache |= (0x40 | stepDir);
         *afterCache = (((stepDir + 4)%8) << 3);
      }
      else {
         *beforeCache |= (0x40 | (stepDir << 3));
         *afterCache = ((stepDir + 4)%8);
      }

      /* Guaranteed to have taken one step since top of loop */
      xDiff = line.loc.X - loc0.X;
      yDiff = line.loc.Y - loc0.Y;
      distSq = (xDiff * xDiff) + (yDiff * yDiff);

      beforeStep = line.loc;
      beforeCache = afterCache;
      steps++;

   } while(distSq < distSqMax);

   return steps;
}

/**
 *
 *
 */
static int
TrailClear(DmtxDecode *dec, DmtxRegion *reg, int clearMask)
{
   int clears;
   DmtxFollow follow;

   assert((clearMask | 0xff) == 0xff);

   /* Clear "visited" bit from trail */
   clears = 0;
   follow = FollowSeek(dec, reg, 0);
   while(abs(follow.step) <= reg->stepsTotal) {
      assert((int)(*follow.ptr & clearMask) != 0x00);
      *follow.ptr &= (clearMask ^ 0xff);
      follow = FollowStep(dec, reg, follow, +1);
      clears++;
   }

   return clears;
}

/**
 *
 *
 */
static DmtxBestLine
FindBestSolidLine(DmtxDecode *dec, DmtxRegion *reg, int step0, int step1, int streamDir, int houghAvoid)
{
   int hough[3][DMTX_HOUGH_RES] = { { 0 } };
   int houghMin, houghMax;
   char houghTest[DMTX_HOUGH_RES];
   int i;
   int step;
   int sign;
   int tripSteps;
   int angleBest;
   int hOffset, hOffsetBest;
   int xDiff, yDiff;
   int dH;
   DmtxRay2 rH;
   DmtxFollow follow;
   DmtxBestLine line;
   DmtxPixelLoc rHp;

   memset(&line, 0x00, sizeof(DmtxBestLine));
   memset(&rH, 0x00, sizeof(DmtxRay2));
   angleBest = 0;
   hOffset = hOffsetBest = 0;

   /* Always follow path flowing away from the trail start */
   if(step0 != 0) {
      if(step0 > 0) {
         sign = +1;
         tripSteps = (step1 - step0 + reg->stepsTotal) % reg->stepsTotal;
      }
      else {
         sign = -1;
         tripSteps = (step0 - step1 + reg->stepsTotal) % reg->stepsTotal;
      }
      if(tripSteps == 0)
         tripSteps = reg->stepsTotal;
   }
   else if(step1 != 0) {
      sign = (step1 > 0) ? +1 : -1;
      tripSteps = abs(step1);
   }
   else if(step1 == 0) {
      sign = +1;
      tripSteps = reg->stepsTotal;
   }
   assert(sign == streamDir);

   follow = FollowSeek(dec, reg, step0);
   rHp = follow.loc;

   line.stepBeg = line.stepPos = line.stepNeg = step0;
   line.locBeg = follow.loc;
   line.locPos = follow.loc;
   line.locNeg = follow.loc;

   /* Predetermine which angles to test */
   for(i = 0; i < DMTX_HOUGH_RES; i++) {
      if(houghAvoid == DmtxUndefined) {
         houghTest[i] = 1;
      }
      else {
         houghMin = (houghAvoid + DMTX_HOUGH_RES/6) % DMTX_HOUGH_RES;
         houghMax = (houghAvoid - DMTX_HOUGH_RES/6 + DMTX_HOUGH_RES) % DMTX_HOUGH_RES;
         if(houghMin > houghMax)
            houghTest[i] = (i > houghMin || i < houghMax) ? 1 : 0;
         else
            houghTest[i] = (i > houghMin && i < houghMax) ? 1 : 0;
      }
   }

   /* Test each angle for steps along path */
   for(step = 0; step < tripSteps; step++) {

      xDiff = follow.loc.X - rHp.X;
      yDiff = follow.loc.Y - rHp.Y;

      /* Increment Hough accumulator */
      for(i = 0; i < DMTX_HOUGH_RES; i++) {

         if((int)houghTest[i] == 0)
            continue;

         dH = (rHvX[i] * yDiff) - (rHvY[i] * xDiff);
         if(dH >= -384 && dH <= 384) {

            if(dH > 128)
               hOffset = 2;
            else if(dH >= -128)
               hOffset = 1;
            else
               hOffset = 0;

            hough[hOffset][i]++;

            /* New angle takes over lead */
            if(hough[hOffset][i] > hough[hOffsetBest][angleBest]) {
               angleBest = i;
               hOffsetBest = hOffset;
            }
         }
      }

/*    CALLBACK_POINT_PLOT(follow.loc, (sign > 1) ? 4 : 3, 1, 2); */

      follow = FollowStep(dec, reg, follow, sign);
   }

   line.angle = angleBest;
   line.hOffset = hOffsetBest;
   line.mag = hough[hOffsetBest][angleBest];

   return line;
}

/**
 *
 *
 */
static DmtxBestLine
FindBestSolidLine2(DmtxDecode *dec, DmtxPixelLoc loc0, int tripSteps, int sign, int houghAvoid)
{
   int hough[3][DMTX_HOUGH_RES] = { { 0 } };
   int houghMin, houghMax;
   char houghTest[DMTX_HOUGH_RES];
   int i;
   int step;
   int angleBest;
   int hOffset, hOffsetBest;
   int xDiff, yDiff;
   int dH;
   DmtxRay2 rH;
   DmtxBestLine line;
   DmtxPixelLoc rHp;
   DmtxFollow follow;

   memset(&line, 0x00, sizeof(DmtxBestLine));
   memset(&rH, 0x00, sizeof(DmtxRay2));
   angleBest = 0;
   hOffset = hOffsetBest = 0;

   follow = FollowSeekLoc(dec, loc0);
   rHp = line.locBeg = line.locPos = line.locNeg = follow.loc;
   line.stepBeg = line.stepPos = line.stepNeg = 0;

   /* Predetermine which angles to test */
   for(i = 0; i < DMTX_HOUGH_RES; i++) {
      if(houghAvoid == DmtxUndefined) {
         houghTest[i] = 1;
      }
      else {
         houghMin = (houghAvoid + DMTX_HOUGH_RES/6) % DMTX_HOUGH_RES;
         houghMax = (houghAvoid - DMTX_HOUGH_RES/6 + DMTX_HOUGH_RES) % DMTX_HOUGH_RES;
         if(houghMin > houghMax)
            houghTest[i] = (i > houghMin || i < houghMax) ? 1 : 0;
         else
            houghTest[i] = (i > houghMin && i < houghMax) ? 1 : 0;
      }
   }

   /* Test each angle for steps along path */
   for(step = 0; step < tripSteps; step++) {

      xDiff = follow.loc.X - rHp.X;
      yDiff = follow.loc.Y - rHp.Y;

      /* Increment Hough accumulator */
      for(i = 0; i < DMTX_HOUGH_RES; i++) {

         if((int)houghTest[i] == 0)
            continue;

         dH = (rHvX[i] * yDiff) - (rHvY[i] * xDiff);
         if(dH >= -384 && dH <= 384) {
            if(dH > 128)
               hOffset = 2;
            else if(dH >= -128)
               hOffset = 1;
            else
               hOffset = 0;

            hough[hOffset][i]++;

            /* New angle takes over lead */
            if(hough[hOffset][i] > hough[hOffsetBest][angleBest]) {
               angleBest = i;
               hOffsetBest = hOffset;
            }
         }
      }

/*    CALLBACK_POINT_PLOT(follow.loc, (sign > 1) ? 4 : 3, 1, 2); */

      follow = FollowStep2(dec, follow, sign);
   }

   line.angle = angleBest;
   line.hOffset = hOffsetBest;
   line.mag = hough[hOffsetBest][angleBest];

   return line;
}

/**
 *
 *
 */
static DmtxPassFail
FindTravelLimits(DmtxDecode *dec, DmtxRegion *reg, DmtxBestLine *line)
{
   int i;
   int distSq, distSqMax;
   int xDiff, yDiff;
   int posRunning, negRunning;
   int posTravel, negTravel;
   int posWander, posWanderMin, posWanderMax, posWanderMinLock, posWanderMaxLock;
   int negWander, negWanderMin, negWanderMax, negWanderMinLock, negWanderMaxLock;
   int cosAngle, sinAngle;
   DmtxFollow followPos, followNeg;
   DmtxPixelLoc loc0, posMax, negMax;

   /* line->stepBeg is already known to sit on the best Hough line */
   followPos = followNeg = FollowSeek(dec, reg, line->stepBeg);
   loc0 = followPos.loc;

   cosAngle = rHvX[line->angle];
   sinAngle = rHvY[line->angle];

   distSqMax = 0;
   posMax = negMax = followPos.loc;

   posTravel = negTravel = 0;
   posWander = posWanderMin = posWanderMax = posWanderMinLock = posWanderMaxLock = 0;
   negWander = negWanderMin = negWanderMax = negWanderMinLock = negWanderMaxLock = 0;

   for(i = 0; i < reg->stepsTotal/2; i++) {

      posRunning = (int)(i < 10 || abs(posWander) < abs(posTravel));
      negRunning = (int)(i < 10 || abs(negWander) < abs(negTravel));

      if(posRunning != 0) {
         xDiff = followPos.loc.X - loc0.X;
         yDiff = followPos.loc.Y - loc0.Y;
         posTravel = (cosAngle * xDiff) + (sinAngle * yDiff);
         posWander = (cosAngle * yDiff) - (sinAngle * xDiff);

         if(posWander >= -3*256 && posWander <= 3*256) {
            distSq = DistanceSquared(followPos.loc, negMax);
            if(distSq > distSqMax) {
               posMax = followPos.loc;
               distSqMax = distSq;
               line->stepPos = followPos.step;
               line->locPos = followPos.loc;
               posWanderMinLock = posWanderMin;
               posWanderMaxLock = posWanderMax;
            }
         }
         else {
            posWanderMin = min(posWanderMin, posWander);
            posWanderMax = max(posWanderMax, posWander);
         }
      }
      else if(!negRunning) {
         break;
      }

      if(negRunning != 0) {
         xDiff = followNeg.loc.X - loc0.X;
         yDiff = followNeg.loc.Y - loc0.Y;
         negTravel = (cosAngle * xDiff) + (sinAngle * yDiff);
         negWander = (cosAngle * yDiff) - (sinAngle * xDiff);

         if(negWander >= -3*256 && negWander < 3*256) {
            distSq = DistanceSquared(followNeg.loc, posMax);
            if(distSq > distSqMax) {
               negMax = followNeg.loc;
               distSqMax = distSq;
               line->stepNeg = followNeg.step;
               line->locNeg = followNeg.loc;
               negWanderMinLock = negWanderMin;
               negWanderMaxLock = negWanderMax;
            }
         }
         else {
            negWanderMin = min(negWanderMin, negWander);
            negWanderMax = max(negWanderMax, negWander);
         }
      }
      else if(!posRunning) {
         break;
      }

/*  CALLBACK_POINT_PLOT(followPos.loc, 2, 1, 2);
    CALLBACK_POINT_PLOT(followNeg.loc, 4, 1, 2); */

      followPos = FollowStep(dec, reg, followPos, +1);
      followNeg = FollowStep(dec, reg, followNeg, -1);
   }
   line->devn = max(posWanderMaxLock - posWanderMinLock, negWanderMaxLock - negWanderMinLock)/256;
   line->distSq = distSqMax;

/* CALLBACK_POINT_PLOT(posMax, 2, 1, 1);
   CALLBACK_POINT_PLOT(negMax, 2, 1, 1); */

   return DmtxPass;
}

/**
 *
 *
 */
static DmtxPassFail
MatrixRegionAlignCalibEdge(DmtxDecode *dec, DmtxRegion *reg, int edgeLoc)
{
   int streamDir;
   int steps;
   int avoidAngle;
   int symbolShape;
   DmtxVector2 pTmp;
   DmtxPixelLoc loc0, loc1, locOrigin;
   DmtxBresLine line;
   DmtxFollow follow;
   DmtxBestLine bestLine;

   /* Determine pixel coordinates of origin */
   pTmp.X = 0.0;
   pTmp.Y = 0.0;
   dmtxMatrix3VMultiplyBy(&pTmp, reg->fit2raw);
   locOrigin.X = (int)(pTmp.X + 0.5);
   locOrigin.Y = (int)(pTmp.Y + 0.5);

   if(dec->sizeIdxExpected == DmtxSymbolSquareAuto ||
         (dec->sizeIdxExpected >= DmtxSymbol10x10 &&
         dec->sizeIdxExpected <= DmtxSymbol144x144))
      symbolShape = DmtxSymbolSquareAuto;
   else if(dec->sizeIdxExpected == DmtxSymbolRectAuto ||
         (dec->sizeIdxExpected >= DmtxSymbol8x18 &&
         dec->sizeIdxExpected <= DmtxSymbol16x48))
      symbolShape = DmtxSymbolRectAuto;
   else
      symbolShape = DmtxSymbolShapeAuto;

   /* Determine end locations of test line */
   if(edgeLoc == DmtxEdgeTop) {
      streamDir = reg->polarity * -1;
      avoidAngle = reg->leftLine.angle;
      follow = FollowSeekLoc(dec, reg->locT);
      pTmp.X = 0.8;
      pTmp.Y = (symbolShape == DmtxSymbolRectAuto) ? 0.2 : 0.6;
   }
   else {
      assert(edgeLoc == DmtxEdgeRight);
      streamDir = reg->polarity;
      avoidAngle = reg->bottomLine.angle;
      follow = FollowSeekLoc(dec, reg->locR);
      pTmp.X = (symbolShape == DmtxSymbolSquareAuto) ? 0.7 : 0.9;
      pTmp.Y = 0.8;
   }

   dmtxMatrix3VMultiplyBy(&pTmp, reg->fit2raw);
   loc1.X = (int)(pTmp.X + 0.5);
   loc1.Y = (int)(pTmp.Y + 0.5);

   loc0 = follow.loc;
   line = BresLineInit(loc0, loc1, locOrigin);
   steps = TrailBlazeGapped(dec, reg, line, streamDir);

   bestLine = FindBestSolidLine2(dec, loc0, steps, streamDir, avoidAngle);
   if(bestLine.mag < 5) {
      ;
   }

   if(edgeLoc == DmtxEdgeTop) {
      reg->topKnown = 1;
      reg->topAngle = bestLine.angle;
      reg->topLoc = bestLine.locBeg;
   }
   else {
      reg->rightKnown = 1;
      reg->rightAngle = bestLine.angle;
      reg->rightLoc = bestLine.locBeg;
   }

   return DmtxPass;
}

/**
 *
 *
 */
static DmtxBresLine
BresLineInit(DmtxPixelLoc loc0, DmtxPixelLoc loc1, DmtxPixelLoc locInside)
{
   int cp;
   DmtxBresLine line;
   DmtxPixelLoc *locBeg, *locEnd;

   /* XXX Verify that loc0 and loc1 are inbounds */

   /* Values that stay the same after initialization */
   line.loc0 = loc0;
   line.loc1 = loc1;
   line.xStep = (loc0.X < loc1.X) ? +1 : -1;
   line.yStep = (loc0.Y < loc1.Y) ? +1 : -1;
   line.xDelta = abs(loc1.X - loc0.X);
   line.yDelta = abs(loc1.Y - loc0.Y);
   line.steep = (int)(line.yDelta > line.xDelta);

   /* Take cross product to determine outward step */
   if(line.steep != 0) {
      /* Point first vector up to get correct sign */
      if(loc0.Y < loc1.Y) {
         locBeg = &loc0;
         locEnd = &loc1;
      }
      else {
         locBeg = &loc1;
         locEnd = &loc0;
      }
      cp = (((locEnd->X - locBeg->X) * (locInside.Y - locEnd->Y)) -
            ((locEnd->Y - locBeg->Y) * (locInside.X - locEnd->X)));

      line.xOut = (cp > 0) ? +1 : -1;
      line.yOut = 0;
   }
   else {
      /* Point first vector left to get correct sign */
      if(loc0.X > loc1.X) {
         locBeg = &loc0;
         locEnd = &loc1;
      }
      else {
         locBeg = &loc1;
         locEnd = &loc0;
      }
      cp = (((locEnd->X - locBeg->X) * (locInside.Y - locEnd->Y)) -
            ((locEnd->Y - locBeg->Y) * (locInside.X - locEnd->X)));

      line.xOut = 0;
      line.yOut = (cp > 0) ? +1 : -1;
   }

   /* Values that change while stepping through line */
   line.loc = loc0;
   line.travel = 0;
   line.outward = 0;
   line.error = (line.steep) ? line.yDelta/2 : line.xDelta/2;

/* CALLBACK_POINT_PLOT(loc0, 3, 1, 1);
   CALLBACK_POINT_PLOT(loc1, 3, 1, 1); */

   return line;
}

/**
 *
 *
 */
static DmtxPassFail
BresLineGetStep(DmtxBresLine line, DmtxPixelLoc target, int *travel, int *outward)
{
   /* Determine necessary step along and outward from Bresenham line */
   if(line.steep != 0) {
      *travel = (line.yStep > 0) ? target.Y - line.loc.Y : line.loc.Y - target.Y;
      BresLineStep(&line, *travel, 0);
      *outward = (line.xOut > 0) ? target.X - line.loc.X : line.loc.X - target.X;
      assert(line.yOut == 0);
   }
   else {
      *travel = (line.xStep > 0) ? target.X - line.loc.X : line.loc.X - target.X;
      BresLineStep(&line, *travel, 0);
      *outward = (line.yOut > 0) ? target.Y - line.loc.Y : line.loc.Y - target.Y;
      assert(line.xOut == 0);
   }

   return DmtxPass;
}

/**
 *
 *
 */
static DmtxPassFail
BresLineStep(DmtxBresLine *line, int travel, int outward)
{
   int i;
   DmtxBresLine lineNew;

   lineNew = *line;

   assert(abs(travel) < 2);
   assert(abs(outward) >= 0);

   /* Perform forward step */
   if(travel > 0) {
      lineNew.travel++;
      if(lineNew.steep != 0) {
         lineNew.loc.Y += lineNew.yStep;
         lineNew.error -= lineNew.xDelta;
         if(lineNew.error < 0) {
            lineNew.loc.X += lineNew.xStep;
            lineNew.error += lineNew.yDelta;
         }
      }
      else {
         lineNew.loc.X += lineNew.xStep;
         lineNew.error -= lineNew.yDelta;
         if(lineNew.error < 0) {
            lineNew.loc.Y += lineNew.yStep;
            lineNew.error += lineNew.xDelta;
         }
      }
   }
   else if(travel < 0) {
      lineNew.travel--;
      if(lineNew.steep != 0) {
         lineNew.loc.Y -= lineNew.yStep;
         lineNew.error += lineNew.xDelta;
         if(lineNew.error >= lineNew.yDelta) {
            lineNew.loc.X -= lineNew.xStep;
            lineNew.error -= lineNew.yDelta;
         }
      }
      else {
         lineNew.loc.X -= lineNew.xStep;
         lineNew.error += lineNew.yDelta;
         if(lineNew.error >= lineNew.xDelta) {
            lineNew.loc.Y -= lineNew.yStep;
            lineNew.error -= lineNew.xDelta;
         }
      }
   }

   for(i = 0; i < outward; i++) {
      /* Outward steps */
      lineNew.outward++;
      lineNew.loc.X += lineNew.xOut;
      lineNew.loc.Y += lineNew.yOut;
   }

   *line = lineNew;

   return DmtxPass;
}

/**
 *
 *
 */
#ifdef NOTDEFINED
static void
WriteDiagnosticImage(DmtxDecode *dec, DmtxRegion *reg, char *imagePath)
{
   int row, col;
   int width, height;
   unsigned char *cache;
   int rgb[3];
   FILE *fp;
   DmtxVector2 p;
   DmtxImage *img;

   assert(reg != NULL);

   fp = fopen(imagePath, "wb");
   if(fp == NULL) {
      exit(3);
   }

   width = dmtxDecodeGetProp(dec, DmtxPropWidth);
   height = dmtxDecodeGetProp(dec->image, DmtxPropHeight);

   img = dmtxImageCreate(NULL, width, height, DmtxPack24bppRGB);

   /* Populate image */
   for(row = 0; row < height; row++) {
      for(col = 0; col < width; col++) {

         cache = dmtxDecodeGetCache(dec, col, row);
         if(cache == NULL) {
            rgb[0] = 0;
            rgb[1] = 0;
            rgb[2] = 128;
         }
         else {
            dmtxDecodeGetPixelValue(dec, col, row, 0, &rgb[0]);
            dmtxDecodeGetPixelValue(dec, col, row, 1, &rgb[1]);
            dmtxDecodeGetPixelValue(dec, col, row, 2, &rgb[2]);

            p.X = col;
            p.Y = row;
            dmtxMatrix3VMultiplyBy(&p, reg->raw2fit);

            if(p.X < 0.0 || p.X > 1.0 || p.Y < 0.0 || p.Y > 1.0) {
               rgb[0] = 0;
               rgb[1] = 0;
               rgb[2] = 128;
            }
            else if(p.X + p.Y > 1.0) {
               rgb[0] += (0.4 * (255 - rgb[0]));
               rgb[1] += (0.4 * (255 - rgb[1]));
               rgb[2] += (0.4 * (255 - rgb[2]));
            }
         }

         dmtxImageSetRgb(img, col, row, rgb);
      }
   }

   /* Write additional markers */
   rgb[0] = 255;
   rgb[1] = 0;
   rgb[2] = 0;
   dmtxImageSetRgb(img, reg->topLoc.X, reg->topLoc.Y, rgb);
   dmtxImageSetRgb(img, reg->rightLoc.X, reg->rightLoc.Y, rgb);

   /* Write image to PNM file */
   fprintf(fp, "P6\n%d %d\n255\n", width, height);
   for(row = height - 1; row >= 0; row--) {
      for(col = 0; col < width; col++) {
         dmtxImageGetRgb(img, col, row, rgb);
         fwrite(rgb, sizeof(char), 3, fp);
      }
   }

   dmtxImageDestroy(&img);

   fclose(fp);
}
#endif
Added jni/libdmtx/dmtxscangrid.c.






























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxscangrid.c
 * \brief Scan grid tracking
 */

/**
 * \brief  Initialize scan grid pattern
 * \param  dec
 * \return Initialized grid
 */
static DmtxScanGrid
InitScanGrid(DmtxDecode *dec)
{
   int scale, smallestFeature;
   int xExtent, yExtent, maxExtent;
   int extent;
   DmtxScanGrid grid;

   memset(&grid, 0x00, sizeof(DmtxScanGrid));

   scale = dmtxDecodeGetProp(dec, DmtxPropScale);
   smallestFeature = dmtxDecodeGetProp(dec, DmtxPropScanGap) / scale;

   grid.xMin = dmtxDecodeGetProp(dec, DmtxPropXmin);
   grid.xMax = dmtxDecodeGetProp(dec, DmtxPropXmax);
   grid.yMin = dmtxDecodeGetProp(dec, DmtxPropYmin);
   grid.yMax = dmtxDecodeGetProp(dec, DmtxPropYmax);

   /* Values that get set once */
   xExtent = grid.xMax - grid.xMin;
   yExtent = grid.yMax - grid.yMin;
   maxExtent = (xExtent > yExtent) ? xExtent : yExtent;

   assert(maxExtent > 1);

   for(extent = 1; extent < maxExtent; extent = ((extent + 1) * 2) - 1)
      if(extent <= smallestFeature)
         grid.minExtent = extent;

   grid.maxExtent = extent;

   grid.xOffset = (grid.xMin + grid.xMax - grid.maxExtent) / 2;
   grid.yOffset = (grid.yMin + grid.yMax - grid.maxExtent) / 2;

   /* Values that get reset for every level */
   grid.total = 1;
   grid.extent = grid.maxExtent;

   SetDerivedFields(&grid);

   return grid;
}

/**
 * \brief  Return the next good location (which may be the current location),
 *         and advance grid progress one position beyond that. If no good
 *         locations remain then return DmtxRangeEnd.
 * \param  grid
 * \return void
 */
static int
PopGridLocation(DmtxScanGrid *grid, DmtxPixelLoc *locPtr)
{
   int locStatus;

   do {
      locStatus = GetGridCoordinates(grid, locPtr);

      /* Always leave grid pointing at next available location */
      grid->pixelCount++;

   } while(locStatus == DmtxRangeBad);

   return locStatus;
}

/**
 * \brief  Extract current grid position in pixel coordinates and return
 *         whether location is good, bad, or end
 * \param  grid
 * \return Pixel location
 */
static int
GetGridCoordinates(DmtxScanGrid *grid, DmtxPixelLoc *locPtr)
{
   int count, half, quarter;
   DmtxPixelLoc loc;

   /* Initially pixelCount may fall beyond acceptable limits. Update grid
    * state before testing coordinates */

   /* Jump to next cross pattern horizontally if current column is done */
   if(grid->pixelCount >= grid->pixelTotal) {
      grid->pixelCount = 0;
      grid->xCenter += grid->jumpSize;
   }

   /* Jump to next cross pattern vertically if current row is done */
   if(grid->xCenter > grid->maxExtent) {
      grid->xCenter = grid->startPos;
      grid->yCenter += grid->jumpSize;
   }

   /* Increment level when vertical step goes too far */
   if(grid->yCenter > grid->maxExtent) {
      grid->total *= 4;
      grid->extent /= 2;
      SetDerivedFields(grid);
   }

   if(grid->extent == 0 || grid->extent < grid->minExtent) {
      locPtr->X = locPtr->Y = -1;
      return DmtxRangeEnd;
   }

   count = grid->pixelCount;

   assert(count < grid->pixelTotal);

   if(count == grid->pixelTotal - 1) {
      /* center pixel */
      loc.X = grid->xCenter;
      loc.Y = grid->yCenter;
   }
   else {
      half = grid->pixelTotal / 2;
      quarter = half / 2;

      /* horizontal portion */
      if(count < half) {
         loc.X = grid->xCenter + ((count < quarter) ? (count - quarter) : (half - count));
         loc.Y = grid->yCenter;
      }
      /* vertical portion */
      else {
         count -= half;
         loc.X = grid->xCenter;
         loc.Y = grid->yCenter + ((count < quarter) ? (count - quarter) : (half - count));
      }
   }

   loc.X += grid->xOffset;
   loc.Y += grid->yOffset;

   *locPtr = loc;

   if(loc.X < grid->xMin || loc.X > grid->xMax ||
         loc.Y < grid->yMin || loc.Y > grid->yMax)
      return DmtxRangeBad;

   return DmtxRangeGood;
}

/**
 * \brief  Update derived fields based on current state
 * \param  grid
 * \return void
 */
static void
SetDerivedFields(DmtxScanGrid *grid)
{
   grid->jumpSize = grid->extent + 1;
   grid->pixelTotal = 2 * grid->extent - 1;
   grid->startPos = grid->extent / 2;
   grid->pixelCount = 0;
   grid->xCenter = grid->yCenter = grid->startPos;
}
Added jni/libdmtx/dmtxstatic.h.




























































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxstatic.h
 * \brief Static header
 */

#ifndef __DMTXSTATIC_H__
#define __DMTXSTATIC_H__

#define DmtxAlmostZero          0.000001
#define DmtxAlmostInfinity            -1

#define DmtxValueC40Latch            230
#define DmtxValueTextLatch           239
#define DmtxValueX12Latch            238
#define DmtxValueEdifactLatch        240
#define DmtxValueBase256Latch        231

#define DmtxValueCTXUnlatch   254
#define DmtxValueEdifactUnlatch       31

#define DmtxValueAsciiPad            129
#define DmtxValueAsciiUpperShift     235
#define DmtxValueCTXShift1      0
#define DmtxValueCTXShift2      1
#define DmtxValueCTXShift3      2
#define DmtxValueFNC1                232
#define DmtxValueStructuredAppend    233
#define DmtxValue05Macro             236
#define DmtxValue06Macro             237
#define DmtxValueECI                 241

#define DmtxC40TextBasicSet            0
#define DmtxC40TextShift1              1
#define DmtxC40TextShift2              2
#define DmtxC40TextShift3              3

#define DmtxUnlatchExplicit            0
#define DmtxUnlatchImplicit            1

#define DmtxChannelValid            0x00
#define DmtxChannelUnsupportedChar  0x01 << 0
#define DmtxChannelCannotUnlatch    0x01 << 1

#undef min
#define min(X,Y) (((X) < (Y)) ? (X) : (Y))

#undef max
#define max(X,Y) (((X) > (Y)) ? (X) : (Y))

typedef enum {
   DmtxEncodeNormal,  /* Use normal scheme behavior (e.g., ASCII auto) */
   DmtxEncodeCompact, /* Use only compact format within scheme */
   DmtxEncodeFull     /* Use only fully expanded format within scheme */
} DmtxEncodeOption;

typedef enum {
   DmtxRangeGood,
   DmtxRangeBad,
   DmtxRangeEnd
} DmtxRange;

typedef enum {
   DmtxEdgeTop               = 0x01 << 0,
   DmtxEdgeBottom            = 0x01 << 1,
   DmtxEdgeLeft              = 0x01 << 2,
   DmtxEdgeRight             = 0x01 << 3
} DmtxEdge;

typedef enum {
   DmtxMaskBit8              = 0x01 << 0,
   DmtxMaskBit7              = 0x01 << 1,
   DmtxMaskBit6              = 0x01 << 2,
   DmtxMaskBit5              = 0x01 << 3,
   DmtxMaskBit4              = 0x01 << 4,
   DmtxMaskBit3              = 0x01 << 5,
   DmtxMaskBit2              = 0x01 << 6,
   DmtxMaskBit1              = 0x01 << 7
} DmtxMaskBit;

/**
 * @struct DmtxFollow
 * @brief DmtxFollow
 */
typedef struct DmtxFollow_struct {
   unsigned char  *ptr;
   unsigned char   neighbor;
   int             step;
   DmtxPixelLoc    loc;
} DmtxFollow;

/**
 * @struct DmtxBresLine
 * @brief DmtxBresLine
 */
typedef struct DmtxBresLine_struct {
   int             xStep;
   int             yStep;
   int             xDelta;
   int             yDelta;
   int             steep;
   int             xOut;
   int             yOut;
   int             travel;
   int             outward;
   int             error;
   DmtxPixelLoc    loc;
   DmtxPixelLoc    loc0;
   DmtxPixelLoc    loc1;
} DmtxBresLine;

typedef struct C40TextState_struct {
   int             shift;
   DmtxBoolean     upperShift;
} C40TextState;

/* dmtxregion.c */
static double RightAngleTrueness(DmtxVector2 c0, DmtxVector2 c1, DmtxVector2 c2, double angle);
static DmtxPointFlow MatrixRegionSeekEdge(DmtxDecode *dec, DmtxPixelLoc loc0);
static DmtxPassFail MatrixRegionOrientation(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow flowBegin);
static long DistanceSquared(DmtxPixelLoc a, DmtxPixelLoc b);
static int ReadModuleColor(DmtxDecode *dec, DmtxRegion *reg, int symbolRow, int symbolCol, int sizeIdx, int colorPlane);

static DmtxPassFail MatrixRegionFindSize(DmtxDecode *dec, DmtxRegion *reg);
static int CountJumpTally(DmtxDecode *dec, DmtxRegion *reg, int xStart, int yStart, DmtxDirection dir);
static DmtxPointFlow GetPointFlow(DmtxDecode *dec, int colorPlane, DmtxPixelLoc loc, int arrive);
static DmtxPointFlow FindStrongestNeighbor(DmtxDecode *dec, DmtxPointFlow center, int sign);
static DmtxFollow FollowSeek(DmtxDecode *dec, DmtxRegion *reg, int seek);
static DmtxFollow FollowSeekLoc(DmtxDecode *dec, DmtxPixelLoc loc);
static DmtxFollow FollowStep(DmtxDecode *dec, DmtxRegion *reg, DmtxFollow followBeg, int sign);
static DmtxFollow FollowStep2(DmtxDecode *dec, DmtxFollow followBeg, int sign);
static DmtxPassFail TrailBlazeContinuous(DmtxDecode *dec, DmtxRegion *reg, DmtxPointFlow flowBegin, int maxDiagonal);
static int TrailBlazeGapped(DmtxDecode *dec, DmtxRegion *reg, DmtxBresLine line, int streamDir);
static int TrailClear(DmtxDecode *dec, DmtxRegion *reg, int clearMask);
static DmtxBestLine FindBestSolidLine(DmtxDecode *dec, DmtxRegion *reg, int step0, int step1, int streamDir, int houghAvoid);
static DmtxBestLine FindBestSolidLine2(DmtxDecode *dec, DmtxPixelLoc loc0, int tripSteps, int sign, int houghAvoid);
static DmtxPassFail FindTravelLimits(DmtxDecode *dec, DmtxRegion *reg, DmtxBestLine *line);
static DmtxPassFail MatrixRegionAlignCalibEdge(DmtxDecode *dec, DmtxRegion *reg, int whichEdge);
static DmtxBresLine BresLineInit(DmtxPixelLoc loc0, DmtxPixelLoc loc1, DmtxPixelLoc locInside);
static DmtxPassFail BresLineGetStep(DmtxBresLine line, DmtxPixelLoc target, int *travel, int *outward);
static DmtxPassFail BresLineStep(DmtxBresLine *line, int travel, int outward);
/*static void WriteDiagnosticImage(DmtxDecode *dec, DmtxRegion *reg, char *imagePath);*/

/* dmtxdecode.c */
static void TallyModuleJumps(DmtxDecode *dec, DmtxRegion *reg, int tally[][24], int xOrigin, int yOrigin, int mapWidth, int mapHeight, DmtxDirection dir);
static DmtxPassFail PopulateArrayFromMatrix(DmtxDecode *dec, DmtxRegion *reg, DmtxMessage *msg);

/* dmtxdecodescheme.c */
static void DecodeDataStream(DmtxMessage *msg, int sizeIdx, unsigned char *outputStart);
static int GetEncodationScheme(unsigned char cw);
static void PushOutputWord(DmtxMessage *msg, int value);
static void PushOutputC40TextWord(DmtxMessage *msg, C40TextState *state, int value);
static void PushOutputMacroHeader(DmtxMessage *msg, int macroType);
static void PushOutputMacroTrailer(DmtxMessage *msg);
static unsigned char *DecodeSchemeAscii(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd);
static unsigned char *DecodeSchemeC40Text(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd, DmtxScheme encScheme);
static unsigned char *DecodeSchemeX12(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd);
static unsigned char *DecodeSchemeEdifact(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd);
static unsigned char *DecodeSchemeBase256(DmtxMessage *msg, unsigned char *ptr, unsigned char *dataEnd);

/* dmtxencode.c */
static void PrintPattern(DmtxEncode *encode);
static int EncodeDataCodewords(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest, DmtxScheme scheme);

/* dmtxplacemod.c */
static int ModulePlacementEcc200(unsigned char *modules, unsigned char *codewords, int sizeIdx, int moduleOnColor);
static void PatternShapeStandard(unsigned char *modules, int mappingRows, int mappingCols, int row, int col, unsigned char *codeword, int moduleOnColor);
static void PatternShapeSpecial1(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor);
static void PatternShapeSpecial2(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor);
static void PatternShapeSpecial3(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor);
static void PatternShapeSpecial4(unsigned char *modules, int mappingRows, int mappingCols, unsigned char *codeword, int moduleOnColor);
static void PlaceModule(unsigned char *modules, int mappingRows, int mappingCols, int row, int col,
      unsigned char *codeword, int mask, int moduleOnColor);

/* dmtxreedsol.c */
static DmtxPassFail RsEncode(DmtxMessage *message, int sizeIdx);
static DmtxPassFail RsDecode(unsigned char *code, int sizeIdx, int fix);
static DmtxPassFail RsGenPoly(DmtxByteList *gen, int errorWordCount);
static DmtxBoolean RsComputeSyndromes(DmtxByteList *syn, const DmtxByteList *rec, int blockErrorWords);
static DmtxBoolean RsFindErrorLocatorPoly(DmtxByteList *elp, const DmtxByteList *syn, int errorWordCount, int maxCorrectable);
static DmtxBoolean RsFindErrorLocations(DmtxByteList *loc, const DmtxByteList *elp);
static DmtxPassFail RsRepairErrors(DmtxByteList *rec, const DmtxByteList *loc, const DmtxByteList *elp, const DmtxByteList *syn);

/* dmtxscangrid.c */
static DmtxScanGrid InitScanGrid(DmtxDecode *dec);
static int PopGridLocation(DmtxScanGrid *grid, /*@out@*/ DmtxPixelLoc *locPtr);
static int GetGridCoordinates(DmtxScanGrid *grid, /*@out@*/ DmtxPixelLoc *locPtr);
static void SetDerivedFields(DmtxScanGrid *grid);

/* dmtxsymbol.c */
static int FindSymbolSize(int dataWords, int sizeIdxRequest);

/* dmtximage.c */
static int GetBitsPerPixel(int pack);

/* dmtxencodestream.c */
static DmtxEncodeStream StreamInit(DmtxByteList *input, DmtxByteList *output);
static void StreamCopy(DmtxEncodeStream *dst, DmtxEncodeStream *src);
static void StreamMarkComplete(DmtxEncodeStream *stream, int sizeIdx);
static void StreamMarkInvalid(DmtxEncodeStream *stream, int reasonIdx);
static void StreamMarkFatal(DmtxEncodeStream *stream, int reasonIdx);
static void StreamOutputChainAppend(DmtxEncodeStream *stream, DmtxByte value);
static DmtxByte StreamOutputChainRemoveLast(DmtxEncodeStream *stream);
static void StreamOutputSet(DmtxEncodeStream *stream, int index, DmtxByte value);
static DmtxBoolean StreamInputHasNext(DmtxEncodeStream *stream);
static DmtxByte StreamInputPeekNext(DmtxEncodeStream *stream);
static DmtxByte StreamInputAdvanceNext(DmtxEncodeStream *stream);
static void StreamInputAdvancePrev(DmtxEncodeStream *stream);

/* dmtxencodescheme.c */
static int EncodeSingleScheme(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest, DmtxScheme scheme);
static void EncodeNextChunk(DmtxEncodeStream *stream, int scheme, int subScheme, int sizeIdxRequest);
static void EncodeChangeScheme(DmtxEncodeStream *stream, DmtxScheme targetScheme, int unlatchType);
static int GetRemainingSymbolCapacity(int outputLength, int sizeIdx);

/* dmtxencodeoptimize.c */
static int EncodeOptimizeBest(DmtxByteList *input, DmtxByteList *output, int sizeIdxRequest);
static void StreamAdvanceFromBest(DmtxEncodeStream *streamNext,
      DmtxEncodeStream *streamList, int targeteState, int sizeIdxRequest);
static void AdvanceAsciiCompact(DmtxEncodeStream *streamNext, DmtxEncodeStream *streamList,
      int state, int inputNext, int sizeIdxRequest);
static void AdvanceCTX(DmtxEncodeStream *streamNext, DmtxEncodeStream *streamList,
      int state, int inputNext, int ctxValueCount, int sizeIdxRequest);
static void AdvanceEdifact(DmtxEncodeStream *streamNext, DmtxEncodeStream *streamList,
      int state, int inputNext, int sizeIdxRequest);
static int GetScheme(int state);
static DmtxBoolean ValidStateSwitch(int fromState, int targetState);

/* dmtxencodeascii.c */
static void EncodeNextChunkAscii(DmtxEncodeStream *stream, int option);
static void AppendValueAscii(DmtxEncodeStream *stream, DmtxByte value);
static void CompleteIfDoneAscii(DmtxEncodeStream *stream, int sizeIdxRequest);
static void PadRemainingInAscii(DmtxEncodeStream *stream, int sizeIdx);
static DmtxByteList EncodeTmpRemainingInAscii(DmtxEncodeStream *stream, DmtxByte *storage, int capacity, DmtxPassFail *passFail);
static DmtxByte Randomize253State(DmtxByte cwValue, int cwPosition);

/* dmtxencodec40textx12.c */
static void EncodeNextChunkCTX(DmtxEncodeStream *stream, int sizeIdxRequest);
static void AppendValuesCTX(DmtxEncodeStream *stream, DmtxByteList *valueList);
static void AppendUnlatchCTX(DmtxEncodeStream *stream);
static void CompleteIfDoneCTX(DmtxEncodeStream *stream, int sizeIdxRequest);
static void CompletePartialC40Text(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest);
static void CompletePartialX12(DmtxEncodeStream *stream, DmtxByteList *valueList, int sizeIdxRequest);
static DmtxBoolean PartialX12ChunkRemains(DmtxEncodeStream *stream);
static void PushCTXValues(DmtxByteList *valueList, DmtxByte inputValue, int targetScheme, DmtxPassFail *passFail);
static DmtxBoolean IsCTX(int scheme);
static void ShiftValueListBy3(DmtxByteList *list, DmtxPassFail *passFail);

/* dmtxencodeedifact.c */
static void EncodeNextChunkEdifact(DmtxEncodeStream *stream);
static void AppendValueEdifact(DmtxEncodeStream *stream, DmtxByte value);
static void CompleteIfDoneEdifact(DmtxEncodeStream *stream, int sizeIdxRequest);

/* dmtxencodebase256.c */
static void EncodeNextChunkBase256(DmtxEncodeStream *stream);
static void AppendValueBase256(DmtxEncodeStream *stream, DmtxByte value);
static void CompleteIfDoneBase256(DmtxEncodeStream *stream, int sizeIdxRequest);
static void UpdateBase256ChainHeader(DmtxEncodeStream *stream, int perfectSizeIdx);
static void Base256OutputChainInsertFirst(DmtxEncodeStream *stream);
static void Base256OutputChainRemoveFirst(DmtxEncodeStream *stream);
static DmtxByte Randomize255State(DmtxByte cwValue, int cwPosition);
static unsigned char UnRandomize255State(unsigned char value, int idx);

static const int dmtxNeighborNone = 8;
static const int dmtxPatternX[] = { -1,  0,  1,  1,  1,  0, -1, -1 };
static const int dmtxPatternY[] = { -1, -1, -1,  0,  1,  1,  1,  0 };
static const DmtxPointFlow dmtxBlankEdge = { 0, 0, 0, DmtxUndefined, { -1, -1 } };

/*@ +charint @*/

static int rHvX[] =
    {  256,  256,  256,  256,  255,  255,  255,  254,  254,  253,  252,  251,  250,  249,  248,
       247,  246,  245,  243,  242,  241,  239,  237,  236,  234,  232,  230,  228,  226,  224,
       222,  219,  217,  215,  212,  210,  207,  204,  202,  199,  196,  193,  190,  187,  184,
       181,  178,  175,  171,  168,  165,  161,  158,  154,  150,  147,  143,  139,  136,  132,
       128,  124,  120,  116,  112,  108,  104,  100,   96,   92,   88,   83,   79,   75,   71,
        66,   62,   58,   53,   49,   44,   40,   36,   31,   27,   22,   18,   13,    9,    4,
         0,   -4,   -9,  -13,  -18,  -22,  -27,  -31,  -36,  -40,  -44,  -49,  -53,  -58,  -62,
       -66,  -71,  -75,  -79,  -83,  -88,  -92,  -96, -100, -104, -108, -112, -116, -120, -124,
      -128, -132, -136, -139, -143, -147, -150, -154, -158, -161, -165, -168, -171, -175, -178,
      -181, -184, -187, -190, -193, -196, -199, -202, -204, -207, -210, -212, -215, -217, -219,
      -222, -224, -226, -228, -230, -232, -234, -236, -237, -239, -241, -242, -243, -245, -246,
      -247, -248, -249, -250, -251, -252, -253, -254, -254, -255, -255, -255, -256, -256, -256 };

static int rHvY[] =
    {    0,    4,    9,   13,   18,   22,   27,   31,   36,   40,   44,   49,   53,   58,   62,
        66,   71,   75,   79,   83,   88,   92,   96,  100,  104,  108,  112,  116,  120,  124,
       128,  132,  136,  139,  143,  147,  150,  154,  158,  161,  165,  168,  171,  175,  178,
       181,  184,  187,  190,  193,  196,  199,  202,  204,  207,  210,  212,  215,  217,  219,
       222,  224,  226,  228,  230,  232,  234,  236,  237,  239,  241,  242,  243,  245,  246,
       247,  248,  249,  250,  251,  252,  253,  254,  254,  255,  255,  255,  256,  256,  256,
       256,  256,  256,  256,  255,  255,  255,  254,  254,  253,  252,  251,  250,  249,  248,
       247,  246,  245,  243,  242,  241,  239,  237,  236,  234,  232,  230,  228,  226,  224,
       222,  219,  217,  215,  212,  210,  207,  204,  202,  199,  196,  193,  190,  187,  184,
       181,  178,  175,  171,  168,  165,  161,  158,  154,  150,  147,  143,  139,  136,  132,
       128,  124,  120,  116,  112,  108,  104,  100,   96,   92,   88,   83,   79,   75,   71,
        66,   62,   58,   53,   49,   44,   40,   36,   31,   27,   22,   18,   13,    9,    4 };

/*@ -charint @*/

enum DmtxErrorMessage {
   DmtxErrorUnknown,
   DmtxErrorUnsupportedCharacter,
   DmtxErrorNotOnByteBoundary,
   DmtxErrorIllegalParameterValue,
   DmtxErrorEmptyList,
   DmtxErrorOutOfBounds,
   DmtxErrorMessageTooLarge,
   DmtxErrorCantCompactNonDigits,
   DmtxErrorUnexpectedScheme,
   DmtxErrorIncompleteValueList
};

static char *dmtxErrorMessage[] = {
   "Unknown error",
   "Unsupported character",
   "Not on byte boundary",
   "Illegal parameter value",
   "Encountered empty list",
   "Out of bounds",
   "Message too large",
   "Can't compact non-digits",
   "Encountered unexpected scheme",
   "Encountered incomplete value list"
};

#endif
Added jni/libdmtx/dmtxsymbol.c.










































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxsymbol.c
 * \brief Data Matrix symbol attributes
 */

/**
 * \brief  Retrieve property based on symbol size
 * \param  attribute
 * \param  sizeIdx
 * \return Attribute value
 */
extern int
dmtxGetSymbolAttribute(int attribute, int sizeIdx)
{
   static const int symbolRows[] = { 10, 12, 14, 16, 18, 20,  22,  24,  26,
                                                 32, 36, 40,  44,  48,  52,
                                                 64, 72, 80,  88,  96, 104,
                                                        120, 132, 144,
                                                  8,  8, 12,  12,  16,  16 };

   static const int symbolCols[] = { 10, 12, 14, 16, 18, 20,  22,  24,  26,
                                                 32, 36, 40,  44,  48,  52,
                                                 64, 72, 80,  88,  96, 104,
                                                        120, 132, 144,
                                                 18, 32, 26,  36,  36,  48 };

   static const int dataRegionRows[] = { 8, 10, 12, 14, 16, 18, 20, 22, 24,
                                                    14, 16, 18, 20, 22, 24,
                                                    14, 16, 18, 20, 22, 24,
                                                            18, 20, 22,
                                                     6,  6, 10, 10, 14, 14 };

   static const int dataRegionCols[] = { 8, 10, 12, 14, 16, 18, 20, 22, 24,
                                                    14, 16, 18, 20, 22, 24,
                                                    14, 16, 18, 20, 22, 24,
                                                            18, 20, 22,
                                                    16, 14, 24, 16, 16, 22 };

   static const int horizDataRegions[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1,
                                                    2, 2, 2, 2, 2, 2,
                                                    4, 4, 4, 4, 4, 4,
                                                          6, 6, 6,
                                                    1, 2, 1, 2, 2, 2 };

   static const int interleavedBlocks[] = { 1, 1, 1, 1, 1, 1, 1,  1, 1,
                                                     1, 1, 1, 1,  1, 2,
                                                     2, 4, 4, 4,  4, 6,
                                                           6, 8, 10,
                                                     1, 1, 1, 1,  1, 1 };

   static const int symbolDataWords[] = { 3, 5, 8,  12,   18,   22,   30,   36,  44,
                                                    62,   86,  114,  144,  174, 204,
                                                   280,  368,  456,  576,  696, 816,
                                                              1050, 1304, 1558,
                                                     5,   10,   16,   22,   32,  49 };

   static const int blockErrorWords[] = { 5, 7, 10, 12, 14, 18, 20, 24, 28,
                                                    36, 42, 48, 56, 68, 42,
                                                    56, 36, 48, 56, 68, 56,
                                                            68, 62, 62,
                                                     7, 11, 14, 18, 24, 28 };

   static const int blockMaxCorrectable[] = { 2, 3, 5,  6,  7,  9,  10,  12,  14,
                                                       18, 21, 24,  28,  34,  21,
                                                       28, 18, 24,  28,  34,  28,
                                                               34,  31,  31,
                                                   3,  5,  7,   9,  12,  14 };

   if(sizeIdx < 0 || sizeIdx >= DmtxSymbolSquareCount + DmtxSymbolRectCount)
      return DmtxUndefined;

   switch(attribute) {
      case DmtxSymAttribSymbolRows:
         return symbolRows[sizeIdx];
      case DmtxSymAttribSymbolCols:
         return symbolCols[sizeIdx];
      case DmtxSymAttribDataRegionRows:
         return dataRegionRows[sizeIdx];
      case DmtxSymAttribDataRegionCols:
         return dataRegionCols[sizeIdx];
      case DmtxSymAttribHorizDataRegions:
         return horizDataRegions[sizeIdx];
      case DmtxSymAttribVertDataRegions:
         return (sizeIdx < DmtxSymbolSquareCount) ? horizDataRegions[sizeIdx] : 1;
      case DmtxSymAttribMappingMatrixRows:
         return dataRegionRows[sizeIdx] *
               dmtxGetSymbolAttribute(DmtxSymAttribVertDataRegions, sizeIdx);
      case DmtxSymAttribMappingMatrixCols:
         return dataRegionCols[sizeIdx] * horizDataRegions[sizeIdx];
      case DmtxSymAttribInterleavedBlocks:
         return interleavedBlocks[sizeIdx];
      case DmtxSymAttribBlockErrorWords:
         return blockErrorWords[sizeIdx];
      case DmtxSymAttribBlockMaxCorrectable:
         return blockMaxCorrectable[sizeIdx];
      case DmtxSymAttribSymbolDataWords:
         return symbolDataWords[sizeIdx];
      case DmtxSymAttribSymbolErrorWords:
         return blockErrorWords[sizeIdx] * interleavedBlocks[sizeIdx];
      case DmtxSymAttribSymbolMaxCorrectable:
         return blockMaxCorrectable[sizeIdx] * interleavedBlocks[sizeIdx];
   }

   return DmtxUndefined;
}

/**
 * \brief  Retrieve data size for a specific symbol size and block number
 * \param  sizeIdx
 * \param  blockIdx
 * \return Attribute value
 */
extern int
dmtxGetBlockDataSize(int sizeIdx, int blockIdx)
{
   int symbolDataWords;
   int interleavedBlocks;
   int count;

   symbolDataWords = dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx);
   interleavedBlocks = dmtxGetSymbolAttribute(DmtxSymAttribInterleavedBlocks, sizeIdx);

   if(symbolDataWords < 1 || interleavedBlocks < 1)
      return DmtxUndefined;

   count = (int)(symbolDataWords/interleavedBlocks);

   return (sizeIdx == DmtxSymbol144x144 && blockIdx < 8) ? count + 1 : count;
}

/**
 * \brief  Determine symbol size based on data size and requested properties
 * \param  dataWords
 * \param  sizeIdxRequest
 * \return Symbol size index (or DmtxUndefined if none)
 */
static int
FindSymbolSize(int dataWords, int sizeIdxRequest)
{
   int sizeIdx;
   int idxBeg, idxEnd;

   if(dataWords <= 0)
      return DmtxUndefined;

   if(sizeIdxRequest == DmtxSymbolSquareAuto || sizeIdxRequest == DmtxSymbolRectAuto) {

      if(sizeIdxRequest == DmtxSymbolSquareAuto) {
         idxBeg = 0;
         idxEnd = DmtxSymbolSquareCount;
      }
      else {
         idxBeg = DmtxSymbolSquareCount;
         idxEnd = DmtxSymbolSquareCount + DmtxSymbolRectCount;
      }

      for(sizeIdx = idxBeg; sizeIdx < idxEnd; sizeIdx++) {
         if(dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx) >= dataWords)
            break;
      }

      if(sizeIdx == idxEnd)
         return DmtxUndefined;
   }
   else {
      sizeIdx = sizeIdxRequest;
   }

   if(dataWords > dmtxGetSymbolAttribute(DmtxSymAttribSymbolDataWords, sizeIdx))
      return DmtxUndefined;

   return sizeIdx;
}
Added jni/libdmtx/dmtxtime.c.


































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxtime.c
 * \brief Time handling
 */

#define DMTX_USEC_PER_SEC 1000000

#if defined(HAVE_SYS_TIME_H) && defined(HAVE_GETTIMEOFDAY)

#include <sys/time.h>
#include <time.h>
#define DMTX_TIME_PREC_USEC 1

/**
 * \brief  GETTIMEOFDAY version
 * \return Time now
 */
extern DmtxTime
dmtxTimeNow(void)
{
   DmtxPassFail err;
   struct timeval tv;
   DmtxTime tNow;

   err = gettimeofday(&tv, NULL);
   if(err != 0)
      ; /* XXX handle error better here */

   tNow.sec = tv.tv_sec;
   tNow.usec = tv.tv_usec;

   return tNow;
}

#elif defined(_MSC_VER)

#include <Windows.h>
#define DMTX_TIME_PREC_USEC 1

/**
 * \brief  MICROSOFT VC++ version
 * \return Time now
 */
extern DmtxTime
dmtxTimeNow(void)
{
   FILETIME ft;
   unsigned __int64 tm;
   DmtxTime tNow;

   GetSystemTimeAsFileTime(&ft);

   tm = ft.dwHighDateTime;
   tm <<= 32;
   tm |= ft.dwLowDateTime;
   tm /= 10;

   tNow.sec = tm / 1000000UL;
   tNow.usec = tm % 1000000UL;

   return tNow;
}

#else

#include <time.h>
#define DMTX_TIME_PREC_USEC 1000000

/**
 * \brief  Generic 1 second resolution version
 * \return Time now
 */
extern DmtxTime
dmtxTimeNow(void)
{
   time_t s;
   DmtxTime tNow;

   s = time(NULL);
   if(errno != 0)
      ; /* XXX handle error better here */

   tNow.sec = s;
   tNow.usec = 0;

   return tNow;
}

#endif

/**
 * \brief  Add milliseconds to time t
 * \param  t
 * \param  msec
 * \return Adjusted time
 */
extern DmtxTime
dmtxTimeAdd(DmtxTime t, long msec)
{
   int usec;

   usec = msec * 1000;

   /* Ensure that time difference will register on local system */
   if(usec > 0 && usec < DMTX_TIME_PREC_USEC)
      usec = DMTX_TIME_PREC_USEC;

   /* Add time */
   t.sec += usec/DMTX_USEC_PER_SEC;
   t.usec += usec%DMTX_USEC_PER_SEC;

   /* Roll extra usecs into secs */
   while(t.usec >= DMTX_USEC_PER_SEC) {
      t.sec++;
      t.usec -= DMTX_USEC_PER_SEC;
   }

   return t;
}

/**
 * \brief  Determine whether the received timeout has been exceeded
 * \param  timeout
 * \return 1 (true) | 0 (false)
 */
extern int
dmtxTimeExceeded(DmtxTime timeout)
{
   DmtxTime now;

   now = dmtxTimeNow();

   return (now.sec > timeout.sec || (now.sec == timeout.sec && now.usec > timeout.usec));
}

#undef DMTX_TIME_PREC_USEC
#undef DMTX_USEC_PER_SEC
Added jni/libdmtx/dmtxvector2.c.
































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxvector2.c
 * \brief 2D Vector math
 */

/**
 *
 *
 */
extern DmtxVector2 *
dmtxVector2AddTo(DmtxVector2 *v1, const DmtxVector2 *v2)
{
   v1->X += v2->X;
   v1->Y += v2->Y;

   return v1;
}

/**
 *
 *
 */
extern DmtxVector2 *
dmtxVector2Add(DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2)
{
   *vOut = *v1;

   return dmtxVector2AddTo(vOut, v2);
}

/**
 *
 *
 */
extern DmtxVector2 *
dmtxVector2SubFrom(DmtxVector2 *v1, const DmtxVector2 *v2)
{
   v1->X -= v2->X;
   v1->Y -= v2->Y;

   return v1;
}

/**
 *
 *
 */
extern DmtxVector2 *
dmtxVector2Sub(DmtxVector2 *vOut, const DmtxVector2 *v1, const DmtxVector2 *v2)
{
   *vOut = *v1;

   return dmtxVector2SubFrom(vOut, v2);
}

/**
 *
 *
 */
extern DmtxVector2 *
dmtxVector2ScaleBy(DmtxVector2 *v, double s)
{
   v->X *= s;
   v->Y *= s;

   return v;
}

/**
 *
 *
 */
extern DmtxVector2 *
dmtxVector2Scale(DmtxVector2 *vOut, const DmtxVector2 *v, double s)
{
   *vOut = *v;

   return dmtxVector2ScaleBy(vOut, s);
}

/**
 *
 *
 */
extern double
dmtxVector2Cross(const DmtxVector2 *v1, const DmtxVector2 *v2)
{
   return (v1->X * v2->Y) - (v1->Y * v2->X);
}

/**
 *
 *
 */
extern double
dmtxVector2Norm(DmtxVector2 *v)
{
   double mag;

   mag = dmtxVector2Mag(v);

   if(mag <= DmtxAlmostZero)
      return -1.0; /* XXX this doesn't look clean */

   dmtxVector2ScaleBy(v, 1/mag);

   return mag;
}

/**
 *
 *
 */
extern double
dmtxVector2Dot(const DmtxVector2 *v1, const DmtxVector2 *v2)
{
   return (v1->X * v2->X) + (v1->Y * v2->Y);
}

/**
 *
 *
 */
extern double
dmtxVector2Mag(const DmtxVector2 *v)
{
   return sqrt(v->X * v->X + v->Y * v->Y);
}

/**
 *
 *
 */
extern double
dmtxDistanceFromRay2(const DmtxRay2 *r, const DmtxVector2 *q)
{
   DmtxVector2 vSubTmp;

   /* Assumes that v is a unit vector */
   assert(fabs(1.0 - dmtxVector2Mag(&(r->v))) <= DmtxAlmostZero);

   return dmtxVector2Cross(&(r->v), dmtxVector2Sub(&vSubTmp, q, &(r->p)));
}

/**
 *
 *
 */
extern double
dmtxDistanceAlongRay2(const DmtxRay2 *r, const DmtxVector2 *q)
{
   DmtxVector2 vSubTmp;

#ifdef DEBUG
   /* Assumes that v is a unit vector */
   if(fabs(1.0 - dmtxVector2Mag(&(r->v))) > DmtxAlmostZero) {
      ; /* XXX big error goes here */
   }
#endif

   return dmtxVector2Dot(dmtxVector2Sub(&vSubTmp, q, &(r->p)), &(r->v));
}

/**
 *
 *
 */
extern DmtxPassFail
dmtxRay2Intersect(DmtxVector2 *point, const DmtxRay2 *p0, const DmtxRay2 *p1)
{
   double numer, denom;
   DmtxVector2 w;

   denom = dmtxVector2Cross(&(p1->v), &(p0->v));
   if(fabs(denom) <= DmtxAlmostZero)
      return DmtxFail;

   dmtxVector2Sub(&w, &(p1->p), &(p0->p));
   numer = dmtxVector2Cross(&(p1->v), &w);

   return dmtxPointAlongRay2(point, p0, numer/denom);
}

/**
 *
 *
 */
extern DmtxPassFail
dmtxPointAlongRay2(DmtxVector2 *point, const DmtxRay2 *r, double t)
{
   DmtxVector2 vTmp;

   /* Ray should always have unit length of 1 */
   assert(fabs(1.0 - dmtxVector2Mag(&(r->v))) <= DmtxAlmostZero);

   dmtxVector2Scale(&vTmp, &(r->v), t);
   dmtxVector2Add(point, &(r->p), &vTmp);

   return DmtxPass;
}
Added jni/libdmtx/libdmtx.pc.in.






















>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: libdmtx
URL: http://www.libdmtx.org/
Description: Library for reading and writing Data Matrix barcodes
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -ldmtx
Cflags: -I${includedir}
Added jni/libdmtx/man/libdmtx.3.




















































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
.\" Man page for the libdmtx project.
.\"
.\" To view: $ groff -man -T ascii libdmtx.3 | less
.\" To text: $ groff -man -T ascii libdmtx.3 | col -b | expand
.\"
.TH LIBDMTX 3 "June 2, 2011"
.SH NAME
libdmtx \- Data Matrix Encoding & Decoding Library 0.7.5
.SH SYNOPSIS
\fB#include <dmtx.h>\fP

cc file.c -ldmtx

.SH DESCRIPTION
\fIlibdmtx\fP is a software library that enables programs to read and write Data Matrix barcodes of the modern ECC200 variety. The library runs natively on several platforms, and can be accessed by multiple languages using the libdmtx language wrappers. The utility programs \fIdmtxread\fP and \fIdmtxwrite\fP provide a command line interface for libdmtx, and serve as a good reference for developers writing their own libdmtx-enabled programs.

Data Matrix barcodes store data as a pattern of ON and OFF modules (often black on white) in a grid pattern that resembles a checkerboard. Like other 2D symbologies, Data Matrix barcodes have a large data capacity compared to their traditional 1D cousins, and employ sophisticated error correction techniques. Data Matrix barcodes can be square or rectangle in shape, and offer several encodation schemes for optimized storage of text and/or binary data. The Data Matrix symbology was invented and released into the public domain by RVSI Acuity CiMatrix.

.SH ENCODING - Generating Data Matrix Barcodes
C/C++ programs can generate a barcode with just a few basic calls to libdmtx:

1. Call \fBdmtxEncodeCreate()\fP

Creates a new \fBDmtxEncode\fP structure and initializes the encoding process. This function must be called before using the other encoding functions.

2. Call \fBdmtxEncodeSetProp()\fP [optional]

Allows you to control specific aspects of the encoding behavior. If this function is not called, libdmtx will use the defaults set by \fBdmtxEncodeCreate()\fP above. The complementary function, \fBdmtxEncodeGetProp()\fP, allows you to detect the current settings.

3. Call either \fBdmtxEncodeDataMatrix()\fP or \fBdmtxEncodeDataMosaic()\fP

Call one of these functions to generate an image of the desired barcode type. Your program is responsible for dispatching the resulting output to its destination, whether that means displaying it on a screen, writing an image file, copying it elsewhere, etc...

4. Call \fBdmtxEncodeDestroy()\fP

Releases memory allocated during the encoding process.

.SH DECODING - Reading Data Matrix Barcodes
Barcode reading takes more steps than barcode generation, mainly because libdmtx must find a barcode region before it can decode the message. However, this too is a relatively simple process that uses 4 main structures:

\fBDmtxImage\fP holds image properties and a pointer to pixel data held by the calling program.

\fBDmtxDecode\fP holds values for controlling decode behavior and tracking scan progress. When scanning a new image, calling programs should always create a new \fBDmtxDecode\fP structure instead of reusing an old one.

\fBDmtxRegion\fP defines a 4-sided region in pixel coordinates. Regions may be found in almost any orientation, and their corners won't necessarily form right angles. libdmtx uses this structure to store the location of potential barcodes, which are then returned to the calling program one-at-a-time.

\fBDmtxMessage\fP holds the decoded message after being extracted from the barcode region. A successfully decoded region will produce exactly one message.

Use the following functions to find and decode Data Matrix barcodes:

1. Call \fBdmtxImageCreate()\fP

Creates and initializes a new \fBDmtxImage\fP structure using pixel data provided by the calling application. Parameters include a pointer to the existing pixel array, image width, height, and the pixel packing format.

2. Call \fBdmtxImageSetProp()\fP [optional]

Sets image properties to control the pixel mapping logic. These settings allow libdmtx to understand many native in-memory image layouts, thus preventing the extra work of transforming and copying data to a one-size-fits-all format. A \fBdmtxDecodeGetProp()\fP function is also available for detecting the current image properties.

3. Call \fBdmtxDecodeCreate()\fP

Creates and initializes a new \fBDmtxDecode\fP struct, which designates the image to be scanned and initializes the scan grid pattern. This function must be called before any other scanning functions.

4. Call \fBdmtxDecodeSetProp()\fP [optional]

Sets internal properties to control decoding behavior. This feature allows you to optimize performance and accuracy for specific image conditions. A \fBdmtxDecodeGetProp()\fP function is also available.

5. Call \fBdmtxRegionFindNext()\fP

Searches every pixel location in a grid pattern looking for potential barcode regions. A \fBDmtxRegion\fP is returned whenever a potential barcode region is found, or if the final pixel location has been scanned. Subsequent calls to this function will resume the search where the previous call left off.

6. Call either \fBdmtxDecodeMatrixRegion()\fP or \fBdmtxDecodeMosaicRegion()\fP

Extracts raw data from the barcode region and decodes the underlying message.

7. Call \fBdmtxMessageDestroy()\fP

Releases memory held by a \fBDmtxMessage\fP struct. The complementary function, \fBdmtxMessageCreate()\fP, is automatically called by \fBdmtxDecodeMatrixRegion()\fP and therefore is not normally used by the calling program.

8. Call \fBdmtxRegionDestroy()\fP

Releases memory held by a \fBDmtxRegion\fP struct. The complementary function, \fBdmtxRegionCreate()\fP, is automatically called by \fBdmtxRegionFindNext()\fP (actually \fBdmtxRegionScanPixel()\fP) and therefore is not normally used by the calling program.

9. Call \fBdmtxDecodeDestroy()\fP

Releases memory held by a \fBDmtxDecode\fP struct. This is the complementary function to \fBdmtxDecodeCreate()\fP.

10. Call \fBdmtxImageDestroy()\fP

Releases memory held by a \fBDmtxImage\fP struct, excluding the pixel array passed to \fBdmtxImageCreate()\fP. The calling program is responsible for releasing the pixel array memory, if required.

.SH EXAMPLE PROGRAM

This example program (available as simple_test.c in the source package) demonstrates \fIlibdmtx\fP functionality in both directions: encoding and decoding. It creates a Data Matrix barcode in memory, reads it back, and prints the decoded message. The final output message should match the original input string.

  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
  #include <assert.h>
  #include <dmtx.h>

  int
  main(int argc, char *argv[])
  {
     size_t          width, height, bytesPerPixel;
     unsigned char   str[] = "30Q324343430794<OQQ";
     unsigned char  *pxl;
     DmtxEncode     *enc;
     DmtxImage      *img;
     DmtxDecode     *dec;
     DmtxRegion     *reg;
     DmtxMessage    *msg;

     fprintf(stdout, "input:  \\"%s\\"\\n", str);

     /* 1) ENCODE a new Data Matrix barcode image (in memory only) */

     enc = dmtxEncodeCreate();
     assert(enc != NULL);
     dmtxEncodeDataMatrix(enc, strlen(str), str);

     /* 2) COPY the new image data before releasing encoding memory */

     width = dmtxImageGetProp(enc->image, DmtxPropWidth);
     height = dmtxImageGetProp(enc->image, DmtxPropHeight);
     bytesPerPixel = dmtxImageGetProp(enc->image, DmtxPropBytesPerPixel);

     pxl = (unsigned char *)malloc(width * height * bytesPerPixel);
     assert(pxl != NULL);
     memcpy(pxl, enc->image->pxl, width * height * bytesPerPixel);

     dmtxEncodeDestroy(&enc);

     /* 3) DECODE the Data Matrix barcode from the copied image */

     img = dmtxImageCreate(pxl, width, height, DmtxPack24bppRGB);
     assert(img != NULL);

     dec = dmtxDecodeCreate(img, 1);
     assert(dec != NULL);

     reg = dmtxRegionFindNext(dec, NULL);
     if(reg != NULL) {
        msg = dmtxDecodeMatrixRegion(dec, reg, DmtxUndefined);
        if(msg != NULL) {
           fputs("output: \\"", stdout);
           fwrite(msg->output, sizeof(unsigned char), msg->outputIdx, stdout);
           fputs("\\"\\n", stdout);
           dmtxMessageDestroy(&msg);
        }
        dmtxRegionDestroy(&reg);
     }

     dmtxDecodeDestroy(&dec);
     dmtxImageDestroy(&img);
     free(pxl);

     exit(0);
  }

.SH "SEE ALSO"
\fIdmtxread\fP(1), \fIdmtxwrite\fP(1), \fIdmtxquery\fP(1)
.SH STANDARDS
ISO/IEC 16022:2000
.PP
ANSI/AIM BC11 ISS
.SH BUGS
Email bug reports to mike@dragonflylogic.com
.SH AUTHOR
Copyright (C) 2008, 2009 Mike Laughton
.\" end of man page
Added jni/libdmtx/script/check_all.sh.








































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/bin/sh

function RunTest()
{
   SCRIPT="$1"
   SCRIPT_TYPE=$(echo "$SCRIPT" | awk -F'.' '{print $NF}')

   echo "   $SCRIPT"

   ERRORS=0
   for dir in $(find "$LIBDMTX" -type d); do

      if [[ "$dir" != "$LIBDMTX" &&
            "$dir" != "$LIBDMTX/test/simple_test" ]]; then
         continue
      fi

      for file in $(find $dir -maxdepth 1); do

         EXT=$(echo $file | awk -F'.' '{print $NF}')
         if [[ "$EXT" != "c" && "$EXT" != "h" && "$EXT" != "sh" && \
               "$EXT" != "py" && "$EXT" != "pl" ]]; then
            continue
         fi

         if [[ "$(basename $file)" = "config.h" ||
               "$(basename $file)" = "ltmain.sh" ]]; then
            continue
         fi

         if [[ $(cat $file | wc -l) -le 10 ]]; then
            #echo "      skipping \"$file\" (trivial file)"
            continue
         fi

         if [[ "$SCRIPT_TYPE" = "sh" ]]; then
            $LIBDMTX/script/$SCRIPT $file
            ERRORS=$(( ERRORS + $? ))
         elif [[ "$SCRIPT_TYPE" = "pl" ]]; then
            PERL=$(which perl)
            if [[ $? -ne 0 ]]; then
               echo "No perl interpreter found.  Skipping $SCRIPT test."
            else
               $PERL $LIBDMTX/script/$SCRIPT $file
               ERRORS=$(( ERRORS + $? ))
            fi
         fi
      done
   done

   return $ERRORS
}

LIBDMTX="$1"
if [[ -z "$LIBDMTX" || ! -d "$LIBDMTX/script" ]]; then
   echo "Must provide valid LIBDMTX directory"
   exit 1
fi

RunTest check_comments.sh
RunTest check_copyright.sh
RunTest check_license.sh
RunTest check_spacing.sh
RunTest check_whitespace.sh
RunTest check_headers.pl
RunTest check_todo.sh

exit 0
Added jni/libdmtx/script/check_comments.sh.


































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh

FILE="$1"

LINE=$(grep -n "\*\{10\}" $FILE)
if [[ $? -eq 0 ]]; then
   echo -e "Bad comment style found in $FILE on line(s):\n$LINE"
   exit 1
fi

LINE=$(sed -n -e '1 =' -e '2,$ p' $FILE | grep -n "^\/\*\$")
if [[ $? -eq 0 ]]; then
   echo -e "Bad comment style found in $FILE on line(s):\n$LINE"
   exit 2
fi

exit 0
Added jni/libdmtx/script/check_copyright.sh.
























>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh

FILE="$1"

# Every nontrivial source file must include a copyright line
COPYRIGHT=$(grep "Copyright 2[[:digit:]]\{3\}" $FILE)
if [[ $? -ne 0 ]]; then
   echo "Missing copyright text in $FILE"
   exit 1
fi

exit 0
Added jni/libdmtx/script/check_headers.pl.










































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/perl -w

use strict;
use File::Basename;

# TODO: Test still misses first function of each file

my $errorCount = 0;
undef my $closeLineNbr;
undef my $lineNbrs;

while(<>) {
   chomp;

   if(m/^}$/) {
      $closeLineNbr = $.;
   }
   elsif(!defined($closeLineNbr) || m/^$/ || m/^\*/ || m/^#/) {
      next;
   }
   elsif(m/^\/\*\*$/) {
      undef $closeLineNbr;
   }
   else {
      $lineNbrs = (defined $lineNbrs) ? "$lineNbrs, $." : $.;
      $errorCount++;
      undef $closeLineNbr;
   }
}

if($errorCount > 0) {
   print "Missing header comment in file \"" . basename($ARGV) .
         "\" at line(s) $lineNbrs\n";
   exit(1);
}

exit(0);
Added jni/libdmtx/script/check_license.sh.


























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/sh

FILE="$1"

TEST1="^ \* libdmtx - Data Matrix Encoding/Decoding Library\$"
TEST2="^ \* See LICENSE file in the main project directory for full\$"
TEST3="^ \* terms of use and distribution.\$"
TEST4="^ \* Contact: Mike Laughton <mike@dragonflylogic.com>\$"

COUNT=0

grep --silent "$TEST1" $FILE
COUNT=$(( COUNT + $? ))

grep --silent "$TEST2" $FILE
COUNT=$(( COUNT + $? ))

grep --silent "$TEST3" $FILE
COUNT=$(( COUNT + $? ))

grep --silent "$TEST4" $FILE
COUNT=$(( COUNT + $? ))

if [[ "$COUNT" -gt 0 ]]; then
   echo "Missing license text in $FILE"
   exit 1
fi

exit 0
Added jni/libdmtx/script/check_spacing.sh.














































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/sh

set -u

FILE=$1

PATTERN="XXC_XX_X_XXX"
COPYRIGHT=0

for i in $(seq 1 12); do
   LINE_TYPE=$(echo $PATTERN | cut -c$i)
   LINE_NBR=$((i + COPYRIGHT))
   if [[ "$LINE_TYPE" = "C" ]]; then
      while true; do
         sed -n "${LINE_NBR}p" $FILE | grep --silent "^ \* Copyright"
         if [[ $? -eq 0 ]]; then
            COPYRIGHT=$((COPYRIGHT+1))
            LINE_NBR=$((i + COPYRIGHT))
         else
            COPYRIGHT=$((COPYRIGHT-1))
            break
         fi
      done
   elif [[ "$LINE_TYPE" = "X" ]]; then
      sed -n "$LINE_NBR p" $FILE | grep --silent "^..*$"
      if [[ $? -ne 0 ]]; then
         echo "Expected line $LINE_NBR to be non-empty in $FILE"
         exit 1
      fi
   else
      sed -n "$LINE_NBR p" $FILE | grep --silent "^[\/ ]\*$"
      if [[ $? -ne 0 ]]; then
         echo "Expected line $LINE_NBR to be empty in $FILE"
         exit 1
      fi
   fi
done

exit 0
Added jni/libdmtx/script/check_splint.sh.












>
>
>
>
>
>
1
2
3
4
5
6
#!/bin/sh

#splint -linelen 999 -Disgreater -Disless dmtx.c
splint -linelen 999 dmtx.c

exit $?
Added jni/libdmtx/script/check_todo.sh.






















>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh

FILE="$1"

COUNT=$(grep -i -e "XXX" -e "TODO" -e "FIXME" $FILE | wc -l)
if [[ "$COUNT" -gt 0 ]]; then
   printf "%4d TODO(s) remain in $FILE\n" $COUNT
   exit 1
fi

exit 0
Added jni/libdmtx/script/check_whitespace.sh.






















>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh

FILE="$1"

LINE=$(grep -n " $" $FILE)
if [[ $? -eq 0 ]]; then
   echo -e "Trailing whitespace found in $FILE on line(s):\n$LINE"
   exit 1
fi

exit 0
Added jni/libdmtx/script/common_tasks.txt.






















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/make/me/a/sandwich

Common Tasks
-----------------------------------------------------------------

Generate splint warnings
$ splint -posix-strict-lib dmtx.c


Release Checklist
-----------------------------------------------------------------

1) o Include newly added files in lists below if appropriate

2) o Create copy of this file as living checklist

3) o Test for common style and formatting issues

   o $ script/check_all.sh .

4) o Review and close applicable bugs and feature requests

5) o Write and finalize release documentation

   o ReleaseNotes.txt (not in Git or source distribution)

   o ChangeLog
   o LICENSE                 o KNOWNBUG
   o NEWS                    o TODO

   o README
   o README.freebsd          o README.cygwin
   o README.mingw            o README.linux
   o README.unix             o README.osx

   o man/libdmtx.3

6) o Update version number in appropriate files

   o configure.ac
   o dmtx.h
   o man/libdmtx.3

7) o Update release date in appropriate files

   o TODO
   o man/libdmtx.3 (be sure to sync w/ simple_test.c)

8) o Perform final test build

   o $ git status # no staged commits
   o $ git pull # get any pending updates
   o # final commit
   o $ sudo make uninstall && make clean && make distclean
   o $ ./autogen.sh && ./configure && make && make check && sudo make install
   o # Run tests and confirm it works. Start step over if changes are needed.

9) o Build and test tarballs

   o $ cd ..
   o $ git clone git://libdmtx.git.sourceforge.net/gitroot/libdmtx/libdmtx release
   o $ cd release
   o $ rm -Rf .git
   o $ find . -type d -name ".git"
   o $ ./autogen.sh && ./configure # don't build though
   o $ make dist-gzip
   o $ make dist-bzip2
   o $ make dist-zip
   o Verify no extraneous files made their way into the
     distribution (especially in the wrapper directories)
   o $ md5sum libdmtx-0.8.0.* > MD5SUM.txt

10) o SourceForge release administration

    o Upload files to SourceForge
    o Publish news item

11) o Tag final release in Git (do this only after uploading to
      SourceForge in case something changes at the last minute)

    o $ git tag -a -m "Tagged v0.7.4" v0.7.4
    o $ git push origin --tags

12) o Update minor number in unstable trunk (e.g., 0.8.0 -> 0.8.1)

    o Use file list from step 6 above
    o $ ./autogen.sh
    o $ ./configure
    o $ git commit -a
    o $ git push

13) o Check out tagged version so dmtx-utils and dmtx-wrapper
      builds will inherit correct version numbers

    o $ git checkout v0.7.4
    o $ ./autogen.sh
    o $ ./configure
    o $ make clean
    o $ make
    o # sudo make install

13) o Update libdmtx.org with news item, download entry, and new
      project status

14) o Send message to libdmtx-announcements@lists.sourceforge.net
      with subject "libdmtx: 0.8.0 Released" and ReleaseNotes.txt
      as message body
Added jni/libdmtx/tcldmtx.c.








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
/*
 * tcldmtx.c --
 *
 *      This file contains the implementation of the "dmtx" Tcl
 *      command. This command wraps the libdmtx library to scan
 *	dot-matrix codes.
 *
 * Copyright (c) 2015 Christian Werner <chw@ch-werner.de>
 *
 * See the file "LICENSE" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include <tcl.h>
#include <tk.h>
#include <dmtx.h>
#include <string.h>

/*
 * Structure used for asynchronous decoding carried  out by a
 * dedicated thread.
 */

typedef struct {
    int run;			/* Controls thread loop */
    Tcl_Mutex mutex;		/* Lock for this struct */
    Tcl_Condition cond;		/* For waking up thread */
    Tcl_ThreadId tid;		/* Thread identifier */
    Tcl_Interp *interp;		/* Interpreter using DMTX decoder */
    Tcl_AsyncHandler async;	/* For signalling result */
    unsigned char *pixPtr;	/* Thread input: pixel array */
    DmtxImage *imgPtr;		/* Thread input: DMTX image struct */
    int scale;			/* Thread input: scale */
    int maxTime;		/* Thread input: time limit */
    int time;			/* Thread output: time consumed */
    DmtxMessage *msgPtr;	/* Thread output: result */
    int nCmdObjs;		/* Callback, number items */
    Tcl_Obj **cmdObjs;		/* Callback, items plus 3 for result */
} AsyncDecode;

/*
 * Decoder thread, waits per condition for a decode request.
 * Reports the result back by an asynchronous event which
 * triggers an do-when-idle handler in the requesting thread.
 */

static Tcl_ThreadCreateType
DmtxThread(ClientData clientData)
{
    AsyncDecode *aPtr = (AsyncDecode *) clientData;
    DmtxDecode *decPtr;
    DmtxRegion *regPtr;
    DmtxMessage *msgPtr;
    DmtxTime timeout;
    Tcl_WideInt tw[2];

    Tcl_MutexLock(&aPtr->mutex);
    while (aPtr->run) {
	Tcl_ConditionWait(&aPtr->cond, &aPtr->mutex, NULL);
	if (aPtr->imgPtr == NULL) {
	    continue;
	}
	Tcl_MutexUnlock(&aPtr->mutex);
	timeout = dmtxTimeNow();
	tw[0] = (Tcl_WideInt) timeout.sec * 1000 + timeout.usec / 1000;
	decPtr = dmtxDecodeCreate(aPtr->imgPtr, aPtr->scale);
	if (decPtr == NULL) {
decErr:
	    timeout = dmtxTimeNow();
	    tw[1] = (Tcl_WideInt) timeout.sec * 1000 + timeout.usec / 1000;
	    Tcl_MutexLock(&aPtr->mutex);
	    dmtxImageDestroy(&aPtr->imgPtr);
	    Tcl_Free((char *) aPtr->pixPtr);
	    aPtr->pixPtr = NULL;
	    aPtr->time = tw[1] - tw[0];
	    if (aPtr->time < 0) {
		aPtr->time = -1;
	    }
	    Tcl_AsyncMark(aPtr->async);
	    continue;
	}
	timeout = dmtxTimeAdd(timeout, aPtr->maxTime);
	regPtr = dmtxRegionFindNext(decPtr, &timeout);
	if (regPtr == NULL) {
	    goto decErr;
	}
        msgPtr = dmtxDecodeMatrixRegion(decPtr, regPtr, DmtxUndefined);
	dmtxDecodeDestroy(&decPtr);
	timeout = dmtxTimeNow();
	tw[1] = (Tcl_WideInt) timeout.sec * 1000 + timeout.usec / 1000;
	Tcl_MutexLock(&aPtr->mutex);
	dmtxImageDestroy(&aPtr->imgPtr);
	Tcl_Free((char *) aPtr->pixPtr);
	aPtr->pixPtr = NULL;
	aPtr->time = tw[1] - tw[0];
	if (aPtr->time < 0) {
	    aPtr->time = -1;
	}
        if (msgPtr != NULL) {
	    aPtr->msgPtr = msgPtr;
	    Tcl_AsyncMark(aPtr->async);
	}
    }
    Tcl_MutexUnlock(&aPtr->mutex);
    TCL_THREAD_CREATE_RETURN; 
}

/*
 * Process asynchronous result callback. Function executes
 * as a do-when-idle handler.
 */

static void
DmtxDecodeDone(ClientData clientData)
{
    AsyncDecode *aPtr = (AsyncDecode *) clientData;
    int ret, i, nCmdObjs = 0;
    Tcl_Obj **cmdObjs;

    Tcl_Preserve(aPtr);
    Tcl_Preserve(aPtr->interp);
    Tcl_MutexLock(&aPtr->mutex);
    cmdObjs = aPtr->cmdObjs;
    if (cmdObjs != NULL) {
	nCmdObjs = aPtr->nCmdObjs;
	if ((aPtr->msgPtr == NULL) || (aPtr->msgPtr->outputIdx <= 0)) {
	    cmdObjs[nCmdObjs] = Tcl_NewIntObj(0);
	    cmdObjs[nCmdObjs + 1] = Tcl_NewIntObj(aPtr->time);
	    cmdObjs[nCmdObjs + 2] = Tcl_NewObj();
	} else {
	    cmdObjs[nCmdObjs] = Tcl_NewIntObj(1);
	    cmdObjs[nCmdObjs + 1] = Tcl_NewIntObj(aPtr->time);
	    cmdObjs[nCmdObjs + 2] =
		Tcl_NewByteArrayObj(aPtr->msgPtr->output,
				    aPtr->msgPtr->outputIdx);
	}
    }
    aPtr->nCmdObjs = 0;
    aPtr->cmdObjs = NULL;
    if (aPtr->msgPtr != NULL) {
	dmtxMessageDestroy(&aPtr->msgPtr);
    }
    Tcl_MutexUnlock(&aPtr->mutex);
    if (cmdObjs != NULL) {
	Tcl_IncrRefCount(cmdObjs[nCmdObjs]);
	Tcl_IncrRefCount(cmdObjs[nCmdObjs + 1]);
	Tcl_IncrRefCount(cmdObjs[nCmdObjs + 2]);
	ret = Tcl_EvalObjv(aPtr->interp, nCmdObjs + 3, cmdObjs,
			   TCL_GLOBAL_ONLY);
	for (i = 0; i < nCmdObjs + 3; i++) {
	    if (cmdObjs[i] != NULL) {
		Tcl_DecrRefCount(cmdObjs[i]);
		cmdObjs[i] = NULL;
	    }
	}
	Tcl_Free((char *) cmdObjs);
	if (ret == TCL_ERROR) {
	    Tcl_AddErrorInfo(aPtr->interp, "\n    (dmtx event handler)");
	    Tcl_BackgroundException(aPtr->interp, ret);
	}
    }
    Tcl_Release(aPtr->interp);
    Tcl_Release(aPtr);
}

/*
 * Function triggered by asynchronous event from decoder thread
 * dispatching do-when-idle handler to invoke Tcl callback.
 */

static int
DmtxDecodeHandler(ClientData clientData, Tcl_Interp *interp, int code)
{
    Tcl_DoWhenIdle(DmtxDecodeDone, clientData);
    return code;
}

/*
 * Stop the decoder thread, if any.
 */

static void
DmtxAsyncStop(AsyncDecode *aPtr)
{
    int i;

    Tcl_CancelIdleCall(DmtxDecodeDone, (ClientData) aPtr);
    Tcl_MutexLock(&aPtr->mutex);
    if (aPtr->msgPtr != NULL) {
	dmtxMessageDestroy(&aPtr->msgPtr);
    }
    if (aPtr->run) {
	int dummy;

	aPtr->run = 0;
	Tcl_ConditionNotify(&aPtr->cond);
	Tcl_MutexUnlock(&aPtr->mutex);
	Tcl_JoinThread(aPtr->tid, &dummy);
	aPtr->tid = NULL;
	Tcl_MutexLock(&aPtr->mutex);
    }
    Tcl_MutexUnlock(&aPtr->mutex);
    Tcl_ConditionFinalize(&aPtr->cond);
    Tcl_MutexFinalize(&aPtr->mutex);
    if (aPtr->async != NULL) {
	Tcl_AsyncDelete(aPtr->async);
	aPtr->async = NULL;
    }
    if (aPtr->cmdObjs != NULL) {
	for (i = 0; i < aPtr->nCmdObjs + 3; i++) {
	    if (aPtr->cmdObjs[i] != NULL) {
		Tcl_DecrRefCount(aPtr->cmdObjs[i]);
		aPtr->cmdObjs[i] = NULL;
	    }
	}
	Tcl_Free((char *) aPtr->cmdObjs);
    }
    aPtr->nCmdObjs = 0;
    aPtr->cmdObjs = NULL;
}

/*
 * Check/start the decoder thread. Error cases:
 * - thread could not be started
 * - thread is already started but still processing a request
 */

static int
DmtxAsyncStart(Tcl_Interp *interp, AsyncDecode *aPtr)
{
    int success = 0;

    Tcl_MutexLock(&aPtr->mutex);
    if (!aPtr->run) {
	if (Tcl_CreateThread(&aPtr->tid, DmtxThread, (ClientData) aPtr,
			     TCL_THREAD_STACK_DEFAULT, TCL_THREAD_JOINABLE)
	    == TCL_OK) {
	    aPtr->async = Tcl_AsyncCreate(DmtxDecodeHandler, (ClientData) aPtr);
	    aPtr->interp = interp;
	    aPtr->run = success = 1;
	}
    } else if ((aPtr->pixPtr != NULL) || (aPtr->imgPtr != NULL) ||
	       (aPtr->cmdObjs != NULL) || (aPtr->msgPtr != NULL)) {
	success = -1;
    } else {
	success = 1;
    }
    Tcl_MutexUnlock(&aPtr->mutex);
    if (success < 0) {
	Tcl_SetResult(interp, "decode process still running", TCL_STATIC);
	return TCL_ERROR;
    }
    if (success == 0) {
	Tcl_SetResult(interp, "decode process not started", TCL_STATIC);
	return TCL_ERROR;
    }
    return TCL_OK;
}

/*
 * Free dmtx::async_decode command client data structure.
 */

static void
DmtxAsyncFree(char *clientData)
{
    AsyncDecode *aPtr = (AsyncDecode *) clientData;

    DmtxAsyncStop(aPtr);
    Tcl_Free((char *) aPtr);
}

/*
 * Callback for deletion of dmtx::async_decode command.
 */

static void
DmtxAsyncCmdDeleted(ClientData clientData)
{
    Tcl_EventuallyFree(clientData, DmtxAsyncFree);
}

/*
 * dmtx::async_decode Tcl command, asynchronous decoding.
 *
 * Command formats/arguments are
 *
 * stop decoder thread
 *
 *   dmtx::async_decode stop
 *
 * start decoding an image
 *
 *   dmtx::async_decode photo callback ?scale timeout?
 *
 *   photo	photo image name
 *   callback	procedure to invoke on end of decoding request
 *   		with these arguments
 *
 * 		flag	1 when dot matrix code decoded, else 0
 * 		time	decode/processing time in milliseconds
 * 		data	decoded dot matrix code as byte array,
 * 			if decode failed, this is empty
 *
 *   scale	optional: scale down image for dmtx library,
 *   		default is 1
 *   timeout	optional: maximum decode time in milliseconds,
 *		default is 1000 ms
 */

static int
DmtxAsyncDecodeObjCmd(ClientData clientData, Tcl_Interp *interp,
		      int objc,  Tcl_Obj *CONST objv[])
{
    AsyncDecode *aPtr = (AsyncDecode *) clientData;
    Tk_PhotoHandle handle;
    Tk_PhotoImageBlock block;
    int scale = 1, bpp, x, y, i, millis = 1000, nCmdObjs;
    unsigned char *pixPtr;
    DmtxImage *imgPtr;
    Tcl_Obj **cmdObjs;

    if (objc > 5) {
	Tcl_WrongNumArgs(interp, 1, objv,
			 "stop|photo ?callback? ?scale timeout?");
	return TCL_ERROR;
    }
    if ((objc == 2) && (strcmp(Tcl_GetString(objv[1]), "stop") == 0)) {
	DmtxAsyncStop(aPtr);
	return TCL_OK;
    }
    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "photo callback ?scale timeout?");
	return TCL_ERROR;
    }
    if ((objc > 3) &&
	(Tcl_GetIntFromObj(interp, objv[3], &scale) != TCL_OK)) {
	return TCL_ERROR;
    }
    if (scale < 1) {
	scale = 1;
    } else if (scale > 32) {
	scale = 32;
    }
    if ((objc > 4) &&
	(Tcl_GetIntFromObj(interp, objv[4], &millis) != TCL_OK)) {
	return TCL_ERROR;
    }
    if (millis <= 0) {
	millis = 1000;
    }
    handle = Tk_FindPhoto(interp, Tcl_GetString(objv[1]));
    if (handle == NULL) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("photo \"%s\" not found",
					       Tcl_GetString(objv[1])));
	return TCL_ERROR;
    }
    if (Tk_PhotoGetImage(handle, &block) != 1) {
	Tcl_SetResult(interp, "error retrieving photo image", TCL_STATIC);
	return TCL_ERROR;
    }
    if (block.pixelSize == 1) {
	bpp = 1;
    } else if ((block.pixelSize == 3) || (block.pixelSize == 4)) {
	bpp = 3;
    } else {
	Tcl_SetResult(interp, "unsupported photo image depth", TCL_STATIC);
	return TCL_ERROR;
    }
    if (DmtxAsyncStart(interp, aPtr) != TCL_OK) {
	return TCL_ERROR;
    }
    pixPtr =
	(unsigned char *) Tcl_AttemptAlloc(block.width * block.height * bpp);
    if (pixPtr == NULL) {
	Tcl_SetResult(interp, "out of memory", TCL_STATIC);
	return TCL_ERROR;
    }
    for (y = 0; y < block.height; y++) {
	unsigned char *srcPtr, *dstPtr;

	srcPtr = block.pixelPtr + y * block.pitch;
	dstPtr = pixPtr + y * block.width * bpp;
	for (x = 0; x < block.width; x++) {
	    dstPtr[0] = srcPtr[block.offset[0]];
	    if (bpp > 1) {
		dstPtr[1] = srcPtr[block.offset[1]];
		dstPtr[2] = srcPtr[block.offset[2]];
	    }
	    dstPtr += bpp;
	    srcPtr += block.pixelSize;
	}
    }
    imgPtr = dmtxImageCreate(pixPtr, block.width, block.height, (bpp > 1) ?
			     DmtxPack24bppRGB : DmtxPack8bppK);
    if (imgPtr == NULL) {
	Tcl_Free((char *) pixPtr);
	Tcl_SetResult(interp, "error creating internal image", TCL_STATIC);
	return TCL_ERROR;
    }
    if (Tcl_ListObjGetElements(interp, objv[2], &nCmdObjs, &cmdObjs)
	!= TCL_OK) {
	dmtxImageDestroy(&imgPtr);
	Tcl_Free((char *) pixPtr);
	return TCL_ERROR;
    }
    if (nCmdObjs <= 0) {
	Tcl_SetResult(interp, "empty callback", TCL_STATIC);
	dmtxImageDestroy(&imgPtr);
	Tcl_Free((char *) pixPtr);
	return TCL_ERROR;
    }
    Tcl_MutexLock(&aPtr->mutex);
    aPtr->pixPtr = pixPtr;
    aPtr->imgPtr = imgPtr;
    aPtr->scale = scale;
    aPtr->maxTime = millis;
    aPtr->nCmdObjs = nCmdObjs;
    aPtr->cmdObjs =
	(Tcl_Obj **) Tcl_Alloc((nCmdObjs + 3) * sizeof (Tcl_Obj *));
    for (i = 0; i < nCmdObjs; i++) {
	aPtr->cmdObjs[i] = cmdObjs[i];
	Tcl_IncrRefCount(aPtr->cmdObjs[i]);
    }
    aPtr->cmdObjs[i++] = NULL;
    aPtr->cmdObjs[i++] = NULL;
    aPtr->cmdObjs[i++] = NULL;
    Tcl_ConditionNotify(&aPtr->cond);
    Tcl_MutexUnlock(&aPtr->mutex);
    return TCL_OK;
}

/*
 * dmtx::decode Tcl command, synchronous decoding.
 *
 * Command arguments are
 *
 *   dmtx::decode photo ?scale timeout?
 *
 *   photo	photo image name
 *   scale	optional: scale down image for dmtx library,
 *   		default is 1
 *   timeout	optional: maximum decode time in milliseconds,
 *		default is unlimited
 *
 * Result is a three element list made up of
 *
 *   flag	1 when dot matrix code decoded, else 0
 *   time	decode/processing time in milliseconds
 *   data	decoded dot matrix code as byte array
 * 		if decode failed, this is empty
 */

static int
DmtxDecodeObjCmd(ClientData unused, Tcl_Interp *interp,
		 int objc,  Tcl_Obj *CONST objv[])
{
    Tk_PhotoHandle handle;
    Tk_PhotoImageBlock block;
    int scale = 1, bpp, x, y;
    unsigned char *pixPtr;
    DmtxImage *imgPtr;
    DmtxDecode *decPtr;
    DmtxRegion *regPtr;
    DmtxTime timeout, now, *timeoutPtr = NULL;
    Tcl_WideInt tw[2];
    Tcl_Obj *list[3];

    if ((objc < 2) || (objc > 4)) {
	Tcl_WrongNumArgs(interp, 1, objv, "photo ?scale timeout?");
	return TCL_ERROR;
    }
    if ((objc > 2) && (Tcl_GetIntFromObj(interp, objv[2], &scale) != TCL_OK)) {
	return TCL_ERROR;
    }
    if (scale < 1) {
	scale = 1;
    } else if (scale > 32) {
	scale = 32;
    }
    now = dmtxTimeNow();
    tw[0] = (Tcl_WideInt) now.sec * 1000 + now.usec / 1000;
    if (objc > 3) {
	int millis;

	if (Tcl_GetIntFromObj(interp, objv[3], &millis) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (millis > 0) {
	    timeout = now;
	    timeout = dmtxTimeAdd(timeout, millis);
	    timeoutPtr = &timeout;
	}
    }
    handle = Tk_FindPhoto(interp, Tcl_GetString(objv[1]));
    if (handle == NULL) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("photo \"%s\" not found",
					       Tcl_GetString(objv[1])));
	return TCL_ERROR;
    }
    if (Tk_PhotoGetImage(handle, &block) != 1) {
	Tcl_SetResult(interp, "error retrieving photo image", TCL_STATIC);
	return TCL_ERROR;
    }
    if (block.pixelSize == 1) {
	bpp = 1;
    } else if ((block.pixelSize == 3) || (block.pixelSize == 4)) {
	bpp = 3;
    } else {
	Tcl_SetResult(interp, "unsupported photo image depth", TCL_STATIC);
	return TCL_ERROR;
    }
    pixPtr =
	(unsigned char *) Tcl_AttemptAlloc(block.width * block.height * bpp);
    if (pixPtr == NULL) {
	Tcl_SetResult(interp, "out of memory", TCL_STATIC);
	return TCL_ERROR;
    }
    for (y = 0; y < block.height; y++) {
	unsigned char *srcPtr, *dstPtr;

	srcPtr = block.pixelPtr + y * block.pitch;
	dstPtr = pixPtr + y * block.width * bpp;
	for (x = 0; x < block.width; x++) {
	    dstPtr[0] = srcPtr[block.offset[0]];
	    if (bpp > 1) {
		dstPtr[1] = srcPtr[block.offset[1]];
		dstPtr[2] = srcPtr[block.offset[2]];
	    }
	    dstPtr += bpp;
	    srcPtr += block.pixelSize;
	}
    }
    imgPtr = dmtxImageCreate(pixPtr, block.width, block.height, (bpp > 1) ?
			     DmtxPack24bppRGB : DmtxPack8bppK);
    if (imgPtr == NULL) {
	Tcl_Free((char *) pixPtr);
	Tcl_SetResult(interp, "error creating internal image", TCL_STATIC);
	return TCL_ERROR;
    }
    decPtr = dmtxDecodeCreate(imgPtr, scale);
    if (decPtr == NULL) {
	dmtxImageDestroy(&imgPtr);
	Tcl_Free((char *) pixPtr);
	Tcl_SetResult(interp, "error creating decoder", TCL_STATIC);
	return TCL_ERROR;
    }
    regPtr = dmtxRegionFindNext(decPtr, timeoutPtr);
    if (regPtr != NULL) {
	DmtxMessage *msgPtr;

        msgPtr = dmtxDecodeMatrixRegion(decPtr, regPtr, DmtxUndefined);
	now = dmtxTimeNow();
	tw[1] = (Tcl_WideInt) now.sec * 1000 + now.usec / 1000;
        if ((msgPtr != NULL) && (msgPtr->outputIdx > 0)) {
	    list[0] = Tcl_NewIntObj(1);
	    list[2] = Tcl_NewByteArrayObj(msgPtr->output,
					  msgPtr->outputIdx);
	} else {
	    list[0] = Tcl_NewIntObj(0);
	    list[2] = Tcl_NewObj();
	}
	if (msgPtr != NULL) {
	    dmtxMessageDestroy(&msgPtr);
	}
        dmtxRegionDestroy(&regPtr);
    } else {
	now = dmtxTimeNow();
	tw[1] = (Tcl_WideInt) now.sec * 1000 + now.usec / 1000;
	list[0] = Tcl_NewIntObj(0);
	list[2] = Tcl_NewObj();
    }
    x = tw[1] - tw[0];
    if (x < 0) {
	x = -1;
    }
    list[1] = Tcl_NewIntObj(x);
    Tcl_SetObjResult(interp, Tcl_NewListObj(3, list));
    dmtxDecodeDestroy(&decPtr);
    dmtxImageDestroy(&imgPtr);
    Tcl_Free((char *) pixPtr);
    return TCL_OK;
}

/*
 * Module initializer.
 */

int
Dmtx_Init(Tcl_Interp *interp)
{
    AsyncDecode *aPtr;

#ifdef USE_TCL_STUBS
    if (Tcl_InitStubs(interp, "8.4", 0) == NULL)
#else
    if (Tcl_PkgRequire(interp, "Tcl", "8.4", 0) == NULL)
#endif
    {
	return TCL_ERROR;
    }
#ifdef USE_TK_STUBS
    if (Tk_InitStubs(interp, "8.4", 0) == NULL)
#else
    if (Tcl_PkgRequire(interp, "Tk", "8.4", 0) == NULL)
#endif
    {
	return TCL_ERROR;
    }
    Tcl_CreateObjCommand(interp, "dmtx::decode", DmtxDecodeObjCmd,
			 (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
    aPtr = (AsyncDecode *) Tcl_Alloc(sizeof (AsyncDecode));
    memset(aPtr, 0, sizeof (AsyncDecode));
    Tcl_CreateObjCommand(interp, "dmtx::async_decode",
			 DmtxAsyncDecodeObjCmd, (ClientData) aPtr,
			 DmtxAsyncCmdDeleted);
    Tcl_PkgProvide(interp, "dmtx", DMTX_VERSION);
    return TCL_OK;
}

/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * tab-width: 8
 * End:
 */
Added jni/libdmtx/test/Makefile.am.




>
>
1
2
SUBDIRS = simple_test
#SUBDIRS = multi_test rotate_test simple_test unit_test
Added jni/libdmtx/test/compare_test/Makefile.






















>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
test:
	@./compare_generated.sh
	@./compare_confirmed.sh
	@./compare_siemens.sh

clean:
	rm -f compare_generated/barcode_*_?.pnm
	rm -f compare_confirmed/barcode_*_?.pnm
	rm -f compare_siemens/siemens_*_?.pnm

.PHONY: test clean
Added jni/libdmtx/test/compare_test/TODO.






>
>
>
1
2
3
o Test that "best" option is always as good or better than others
o Measure how often "best" gives exact results as a straight option
o Count how often "best" beats "fast" (and visa versa)
Added jni/libdmtx/test/compare_test/compare_confirmed.sh.














































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/sh

ERROR_COUNT=0

echo "Comparing generated barcodes against confirmed results"
echo "-----------------------------------------------------------------"

for CONFIRMED in compare_confirmed/barcode_*_?.png; do

   GENERATED="compare_generated/$(basename $CONFIRMED | sed -e 's/^confirmed_/barcode_/')"
   if [[ ! -s "$GENERATED" ]]; then
      echo "FILE MISSING: Please run compare_generated.sh first."
      exit 1
   fi

   GENERATED_MD5SUM=$(convert -depth 8 -type TrueColor $GENERATED pnm: | md5sum)
   GENERATED_ERROR=$?

   CONFIRMED_MD5SUM=$(convert -depth 8 -type TrueColor $CONFIRMED pnm: | md5sum)
   CONFIRMED_ERROR=$?

   if [[ "$GENERATED_ERROR" -ne 0 || "$CONFIRMED_ERROR" -ne 0 ]]; then
      echo "Error: convert failed"
      exit 1
   fi

   if [[ "$GENERATED_MD5SUM" == "$CONFIRMED_MD5SUM" ]]; then
      echo "SUCCESS: $(basename $CONFIRMED)"
   else
      echo "FAILURE: $(basename $GENERATED)"
      ERROR_COUNT=$[$ERROR_COUNT + 1]
   fi

done

echo "$ERROR_COUNT difference(s) found"
echo ""

exit 0
Added jni/libdmtx/test/compare_test/compare_confirmed/barcode_004_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_confirmed/barcode_014_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_confirmed/barcode_060_e.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_generated.sh.
































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/bin/sh

#SCHEMES="b f a c t x e 8"
SCHEMES="b a c t x e 8"
DMTXWRITE="$(which dmtxwrite)"
DMTXREAD="$(which dmtxread)"
MOGRIFY=$(which mogrify)
COMPARE_DIR="compare_generated"

if [[ ! -x "$DMTXWRITE" ]]; then
   echo "Unable to execute \"$DMTXWRITE\""
   exit 1
fi

if [[ ! -x "$DMTXREAD" ]]; then
   echo "Unable to execute \"$DMTXREAD\""
   exit 1
fi

if [[ ! -x "$MOGRIFY" ]]; then
   echo "Unable to find or execute mogrify"
   exit 1
fi

if [[ ! -d "$COMPARE_DIR" ]]; then
   $(which mkdir) "$COMPARE_DIR"
fi

ERROR_COUNT=0

echo "Generating and reading back barcodes from input messages"
echo "-----------------------------------------------------------------"

for file in input_messages/message_*.dat; do

   ENCODE=$(cat $file)
   MESSAGE=$(basename $file .dat | cut -d'_' -f2)

   for scheme in $SCHEMES; do

      OUTPUT="${COMPARE_DIR}/barcode_${MESSAGE}_${scheme}"
      $DMTXWRITE -e$scheme -o ${OUTPUT}.png $file 1>/dev/null 2>&1
      ERROR=$?
      if [[ "$ERROR" -eq 70 ]]; then
         # XXX revisit this to use more specific error code when available
         echo "   SKIP: message $MESSAGE scheme ${scheme} (unsupported character)"
         continue;
      elif [[ "$ERROR" -ne 0 && "$ERROR" -ne 70 ]]; then
         echo "  ERROR: dmtxwrite failed"
         exit "$ERROR";
      fi

      $MOGRIFY -depth 8 -type TrueColor ${OUTPUT}.png
      ERROR=$?
      if [[ $? -ne 0 ]]; then
         echo "  ERROR: mogrify failed"
         exit "$ERROR";
      fi

      DECODE=$($DMTXREAD ${OUTPUT}.png)
      ERROR=$?
      if [[ $? -ne 0 ]]; then
         echo " ERROR: dmtxread failed"
         exit "$ERROR";
      fi

      if [[ "$ENCODE" == "$DECODE" ]]; then
         echo "SUCCESS: message $MESSAGE scheme ${scheme}"
      else
         echo "FAILURE: message $MESSAGE scheme ${scheme}"
         ERROR_COUNT=$[$ERROR_COUNT + 1]
      fi

   done
done

echo "$ERROR_COUNT error(s) encountered"
echo ""

exit 0
Added jni/libdmtx/test/compare_test/compare_siemens.sh.




























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/sh

ERROR_COUNT=0

for PNG_BARCODE in compare_siemens/siemens_*_?.png; do
   PNM_BARCODE=$(echo $PNG_BARCODE | sed -e 's/\.png$/.pnm/')
   convert -depth 8 -type TrueColor $PNG_BARCODE $PNM_BARCODE
done

echo "Comparing generated barcodes against Seimens results"
echo "-----------------------------------------------------------------"

for file in compare_siemens/siemens_*_?.pnm; do

   TEST_BARCODE=compare_generated/$(basename $file | sed -e 's/^siemens_/barcode_/')
   if [[ ! -r "$TEST_BARCODE" ]]; then
      continue
   fi

   cmp $file $TEST_BARCODE
   if [[ $? -ne 0 ]]; then
      ERROR_COUNT=$[$ERROR_COUNT + 1]
   fi

done

echo "$ERROR_COUNT difference(s) found"
echo ""

exit 0
Added jni/libdmtx/test/compare_test/compare_siemens/siemens_000_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_000_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_000_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_000_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_000_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_001_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_001_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_001_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_001_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_001_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_002_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_002_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_002_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_002_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_002_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_003_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_003_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_003_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_003_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_003_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_004_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_004_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_004_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_004_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_004_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_005_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_005_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_005_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_005_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_005_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_006_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_006_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_006_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_006_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_006_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_007_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_007_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_007_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_007_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_007_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_008_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_008_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_008_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_008_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_008_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_009_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_009_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_009_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_009_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_009_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_010_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_010_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_010_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_010_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_010_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_011_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_011_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_011_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_011_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_011_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_012_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_012_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_012_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_012_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_012_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_013_8.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_013_a.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_013_c.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_013_f.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/compare_siemens/siemens_013_t.png.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_000.dat.


>
1
abcdefghijklmnopqrsABCDEFGHIJKLMNOPQRS
Added jni/libdmtx/test/compare_test/input_messages/message_001.dat.


>
1
abcdefghijklmABCDEFGHIJKLM0123456789
Added jni/libdmtx/test/compare_test/input_messages/message_002.dat.




>
>
1
2
libdmtx is a shared library for Linux that can be used to read (scan & decode) and write (encode & print) 2D Data Matrix barcode symbols.  It is released under the LGPL and can be used and distributed freely under these terms.
Data Matrix barcodes are two-dimensional symbols that hold a dense pattern of data with built-in error correction.  The Data Matrix symbology (sometimes referred to as DataMatrix) was invented and released into the public domain by RVSI Acuity CiMatrix.  Wikipedia has a good article on the symbology and its characteristics.
Added jni/libdmtx/test/compare_test/input_messages/message_003.dat.






>
>
>
1
2
3
This test case contains newline charactes,
including in the middle and at the end of
the message.
Added jni/libdmtx/test/compare_test/input_messages/message_004.dat.


>
1
123456
Added jni/libdmtx/test/compare_test/input_messages/message_005.dat.


>
1
123456789012345678901234567890123456789012345678901234567890
Added jni/libdmtx/test/compare_test/input_messages/message_006.dat.


>
1
30Q324343430794<OQQ
Added jni/libdmtx/test/compare_test/input_messages/message_007.dat.


>
1
between subtle shading and the absence of light
Added jni/libdmtx/test/compare_test/input_messages/message_008.dat.


>
1
as the raindrops penetrate the silence all around
Added jni/libdmtx/test/compare_test/input_messages/message_009.dat.


>
1
bathroom mirror casts confusing looks from me to me
Added jni/libdmtx/test/compare_test/input_messages/message_010.dat.


>
1
AND WHEN I SQUINTED THE WORLD SEEMED ROSE TINTED
Added jni/libdmtx/test/compare_test/input_messages/message_011.dat.


>
1
http://www.libdmtx.org
Added jni/libdmtx/test/compare_test/input_messages/message_012.dat.


>
1
and when i squinted the WORLD SEEMED ROSE TINTED
Added jni/libdmtx/test/compare_test/input_messages/message_013.dat.


>
1
123456789
Added jni/libdmtx/test/compare_test/input_messages/message_014.dat.


>
1
A1B2C3D4E5F6G7H8I9J0K1L2
Added jni/libdmtx/test/compare_test/input_messages/message_015.dat.


>
1
1234567
Added jni/libdmtx/test/compare_test/input_messages/message_016.dat.


>
1
12345678
Added jni/libdmtx/test/compare_test/input_messages/message_017.dat.


>
1
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus vitae diam ac ante tristique faucibus. In ac velit. Pellentesque enim ligula, accumsan vitae, convallis non, molestie quis, neque. Nullam in lacus. Praesent convallis. Suspendisse ut est non augue sollicitudin semper. Donec dui arcu, blandit ac, fermentum nec, tempor non, nibh. Nunc ut purus vel lorem dignissim consequat. Donec felis. Suspendisse vel dolor ac lacus ullamcorper nonummy. In hac habitasse platea dictumst. Ut dolor nunc, tincidunt id, cursus a, vehicula adipiscing, urna. Integer eget enim eu nunc elementum sollicitudin. Etiam sodales condimentum nulla. Nam blandit molestie felis. Ut faucibus sollicitudin sem.
Added jni/libdmtx/test/compare_test/input_messages/message_018.dat.


>
1
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus vitae diam ac ante tristique faucibus. In ac velit. Pellentesque enim ligula, accumsan vitae, convallis non, molestie quis, neque. Nullam in lacus. Praesent convallis. Suspendisse ut est non augue sollicitudin semper. Donec dui arcu, blandit ac, fermentum nec, tempor non, nibh. Nunc ut purus vel lorem dignissim consequat. Donec felis. Suspendisse vel dolor ac lacus ullamcorper nonummy. In hac habitasse platea dictumst. Ut dolor nunc, tincidunt id, cursus a, vehicula adipiscing, urna. Integer eget enim eu nunc elementum sollicitudin. Etiam sodales condimentum nulla. Nam blandit molestie felis.
Added jni/libdmtx/test/compare_test/input_messages/message_019.dat.


>
1
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus vitae diam ac ante tristique faucibus. In ac velit. Pellentesque enim ligula, accumsan vitae, convallis non, molestie quis, neque. Nullam in lacus. Praesent convallis. Suspendisse ut est non augue sollicitudin semper. Donec dui arcu, blandit ac, fermentum nec, tempor non, nibh. Nunc ut purus vel lorem dignissim consequat. Donec felis. Suspendisse vel dolor ac lacus ullamcorper nonummy. In hac habitasse platea dictumst. Ut dolor nunc, tincidunt id, cursus a, vehicula adipiscing, urna. Integer eget enim eu nunc elementum sollicitudin.
Added jni/libdmtx/test/compare_test/input_messages/message_020.dat.


>
1
HTTP://WWW.LIBDMTX.ORG
Added jni/libdmtx/test/compare_test/input_messages/message_021.dat.


>
1
http://www.mungewell.org/simon.asc
Added jni/libdmtx/test/compare_test/input_messages/message_022.dat.


>
1
ABC123!@#$abcdefghijkl
Added jni/libdmtx/test/compare_test/input_messages/message_023.dat.


>
1
ABCÈEFG
Added jni/libdmtx/test/compare_test/input_messages/message_024.dat.


>
1
Some sample text with an umläut in the middle
Added jni/libdmtx/test/compare_test/input_messages/message_025.dat.


>
1
דיה ×דומה
Added jni/libdmtx/test/compare_test/input_messages/message_026.dat.
















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Milvus milvus
Red Kite
Rotmilan
Milan royal
Milano Real
Luňák Äervený
Rød Glente
Rode Wouw
Isohaarahaukka
Aquila rossa
Nibbio reale
Glente
Glada
Vörös kanya
КраÑный коршун
Kania ruda
Haja Äervená
SarkanÄ klija
ΨαλιδιάÏης
Milhafre-real
Руда шуліка
Kızıl Çaylak
アカトビ
דיה ×דומה
Added jni/libdmtx/test/compare_test/input_messages/message_027.dat.


>
1
アカトビアカトビアカトビアカトビ
Added jni/libdmtx/test/compare_test/input_messages/message_028.dat.


>
1
アカトビアカトビアカトビアカト
Added jni/libdmtx/test/compare_test/input_messages/message_029.dat.


>
1
アカトビアカトビアカトビアカ
Added jni/libdmtx/test/compare_test/input_messages/message_030.dat.


>
1
1234567890
Added jni/libdmtx/test/compare_test/input_messages/message_031.dat.


>
1
12345678901
Added jni/libdmtx/test/compare_test/input_messages/message_032.dat.


>
1
123456789012
Added jni/libdmtx/test/compare_test/input_messages/message_033.dat.


>
1
1234567890123
Added jni/libdmtx/test/compare_test/input_messages/message_034.dat.


>
1
12345678901234
Added jni/libdmtx/test/compare_test/input_messages/message_035.dat.


>
1
123456789012345
Added jni/libdmtx/test/compare_test/input_messages/message_036.dat.


>
1
1234567890123456
Added jni/libdmtx/test/compare_test/input_messages/message_037.dat.


>
1
12345678901234567
Added jni/libdmtx/test/compare_test/input_messages/message_038.dat.


>
1
123456789012345678
Added jni/libdmtx/test/compare_test/input_messages/message_039.dat.


>
1
1234567890123456789
Added jni/libdmtx/test/compare_test/input_messages/message_040.dat.


>
1
Lorem ipsum dolor si
Added jni/libdmtx/test/compare_test/input_messages/message_041.dat.


>
1
Lorem ipsum dolor sit
Added jni/libdmtx/test/compare_test/input_messages/message_042.dat.


>
1
Lorem ipsum dolor sit 
Added jni/libdmtx/test/compare_test/input_messages/message_043.dat.


>
1
Lorem ipsum dolor sit a
Added jni/libdmtx/test/compare_test/input_messages/message_044.dat.


>
1
Lorem ipsum dolor sit am
Added jni/libdmtx/test/compare_test/input_messages/message_045.dat.


>
1
Lorem ipsum dolor sit ame
Added jni/libdmtx/test/compare_test/input_messages/message_046.dat.


>
1
Lorem ipsum dolor sit amet
Added jni/libdmtx/test/compare_test/input_messages/message_047.dat.


>
1
Lorem ipsum dolor sit amet,
Added jni/libdmtx/test/compare_test/input_messages/message_048.dat.


>
1
Lorem ipsum dolor sit amet, 
Added jni/libdmtx/test/compare_test/input_messages/message_049.dat.


>
1
Lorem ipsum dolor sit amet, c
Added jni/libdmtx/test/compare_test/input_messages/message_050.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_051.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_052.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_053.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_054.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_055.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_056.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_057.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_058.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_059.dat.

cannot compute difference between binary files

Added jni/libdmtx/test/compare_test/input_messages/message_060.dat.


>
1
AB
Added jni/libdmtx/test/multi_test/Makefile.am.


























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
AM_CPPFLAGS = -Wshadow -Wall -pedantic -ansi

check_PROGRAMS = multi_test

multi_test_SOURCES = dmtx.c dmtxaccel.c dmtxdecode2.c dmtxhough.c \
	dmtxregion2.c dmtxsobel.c dmtxvaluegrid.c kiss_fft.c kiss_fftr.c \
	multi_test.c multi_test.h visualize.c

if TARGET_MACOSX
multi_test_LDFLAGS = -lm -lSDL -lSDL_image -lSDL_gfx -lSDMmain -framework Cocoa -lpthread
else
multi_test_LDFLAGS = -lm -lSDL -lSDL_image -lSDL_gfx -lpthread -L/usr/local/lib -L/usr/lib/mingw
endif
Added jni/libdmtx/test/multi_test/_kiss_fft_guts.h.








































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
Copyright (c) 2003-2010, Mark Borgerding

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/* kiss_fft.h
   defines kiss_fft_scalar as either short or a float type
   and defines
   typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
#include "kiss_fft.h"
#include <limits.h>

#define MAXFACTORS 32
/* e.g. an fft of length 128 has 4 factors
 as far as kissfft is concerned
 4*4*4*2
 */

struct kiss_fft_state{
    int nfft;
    int inverse;
    int factors[2*MAXFACTORS];
    kiss_fft_cpx twiddles[1];
};

/*
  Explanation of macros dealing with complex math:

   C_MUL(m,a,b)         : m = a*b
   C_FIXDIV( c , div )  : if a fixed point impl., c /= div. noop otherwise
   C_SUB( res, a,b)     : res = a - b
   C_SUBFROM( res , a)  : res -= a
   C_ADDTO( res , a)    : res += a
 * */
#ifdef FIXED_POINT
#if (FIXED_POINT==32)
# define FRACBITS 31
# define SAMPPROD int64_t
#define SAMP_MAX 2147483647
#else
# define FRACBITS 15
# define SAMPPROD int32_t
#define SAMP_MAX 32767
#endif

#define SAMP_MIN -SAMP_MAX

#if defined(CHECK_OVERFLOW)
#  define CHECK_OVERFLOW_OP(a,op,b)  \
	if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
		fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) );  }
#endif


#   define smul(a,b) ( (SAMPPROD)(a)*(b) )
#   define sround( x )  (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS )

#   define S_MUL(a,b) sround( smul(a,b) )

#   define C_MUL(m,a,b) \
      do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \
          (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)

#   define DIVSCALAR(x,k) \
	(x) = sround( smul(  x, SAMP_MAX/k ) )

#   define C_FIXDIV(c,div) \
	do {    DIVSCALAR( (c).r , div);  \
		DIVSCALAR( (c).i  , div); }while (0)

#   define C_MULBYSCALAR( c, s ) \
    do{ (c).r =  sround( smul( (c).r , s ) ) ;\
        (c).i =  sround( smul( (c).i , s ) ) ; }while(0)

#else  /* not FIXED_POINT*/

#   define S_MUL(a,b) ( (a)*(b) )
#define C_MUL(m,a,b) \
    do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
        (m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
#   define C_FIXDIV(c,div) /* NOOP */
#   define C_MULBYSCALAR( c, s ) \
    do{ (c).r *= (s);\
        (c).i *= (s); }while(0)
#endif

#ifndef CHECK_OVERFLOW_OP
#  define CHECK_OVERFLOW_OP(a,op,b) /* noop */
#endif

#define  C_ADD( res, a,b)\
    do { \
	    CHECK_OVERFLOW_OP((a).r,+,(b).r)\
	    CHECK_OVERFLOW_OP((a).i,+,(b).i)\
	    (res).r=(a).r+(b).r;  (res).i=(a).i+(b).i; \
    }while(0)
#define  C_SUB( res, a,b)\
    do { \
	    CHECK_OVERFLOW_OP((a).r,-,(b).r)\
	    CHECK_OVERFLOW_OP((a).i,-,(b).i)\
	    (res).r=(a).r-(b).r;  (res).i=(a).i-(b).i; \
    }while(0)
#define C_ADDTO( res , a)\
    do { \
	    CHECK_OVERFLOW_OP((res).r,+,(a).r)\
	    CHECK_OVERFLOW_OP((res).i,+,(a).i)\
	    (res).r += (a).r;  (res).i += (a).i;\
    }while(0)

#define C_SUBFROM( res , a)\
    do {\
	    CHECK_OVERFLOW_OP((res).r,-,(a).r)\
	    CHECK_OVERFLOW_OP((res).i,-,(a).i)\
	    (res).r -= (a).r;  (res).i -= (a).i; \
    }while(0)


#ifdef FIXED_POINT
#  define KISS_FFT_COS(phase)  floor(.5+SAMP_MAX * cos (phase))
#  define KISS_FFT_SIN(phase)  floor(.5+SAMP_MAX * sin (phase))
#  define HALF_OF(x) ((x)>>1)
#elif defined(USE_SIMD)
#  define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
#  define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
#  define HALF_OF(x) ((x)*_mm_set1_ps(.5))
#else
#  define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
#  define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
#  define HALF_OF(x) ((x)*.5)
#endif

#define  kf_cexp(x,phase) \
	do{ \
		(x)->r = KISS_FFT_COS(phase);\
		(x)->i = KISS_FFT_SIN(phase);\
	}while(0)


/* a debugging function */
#define pcpx(c)\
    fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) )


#ifdef KISS_FFT_USE_ALLOCA
// define this to allow use of alloca instead of malloc for temporary buffers
// Temporary buffers are used in two case:
// 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5
// 2. "in-place" FFTs.  Notice the quotes, since kissfft does not really do an in-place transform.
#include <alloca.h>
#define  KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes)
#define  KISS_FFT_TMP_FREE(ptr)
#else
#define  KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes)
#define  KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr)
#endif
Added jni/libdmtx/test/multi_test/dmtx.c.


>
1
#include "../../dmtx.c"
Added jni/libdmtx/test/multi_test/dmtxaccel.c.
















































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxaccel.c
 */

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <assert.h>
#include "../../dmtx.h"
#include "multi_test.h"

/**
 *
 *
 */
DmtxAccel *
AccelCreate(DmtxSobel *sobel)
{
   int sWidth, sHeight;
   int vWidth, vHeight;
   int hWidth, hHeight;
   DmtxAccel *accel;

   accel = (DmtxAccel *)calloc(1, sizeof(DmtxAccel));
   if(accel == NULL)
      return NULL;

   sWidth = dmtxValueGridGetWidth(sobel->v);
   sHeight = dmtxValueGridGetHeight(sobel->v);

   vWidth = sWidth - 1;
   vHeight = sHeight;

   hWidth = sWidth;
   hHeight = sHeight - 1;

   accel->vv = dmtxValueGridCreate(vWidth, vHeight, DmtxEdgeVertical, sobel->v);
   accel->vb = dmtxValueGridCreate(vWidth, vHeight, DmtxEdgeVertical, sobel->b);
   accel->vs = dmtxValueGridCreate(vWidth, vHeight, DmtxEdgeVertical, sobel->s);
   accel->hb = dmtxValueGridCreate(hWidth, hHeight, DmtxEdgeHorizontal, sobel->b);
   accel->hh = dmtxValueGridCreate(hWidth, hHeight, DmtxEdgeHorizontal, sobel->h);
   accel->hs = dmtxValueGridCreate(hWidth, hHeight, DmtxEdgeHorizontal, sobel->s);

   if(accel->vv == NULL || accel->vb == NULL || accel->vs == NULL ||
         accel->hb == NULL || accel->hh == NULL || accel->hs == NULL)
   {
      AccelDestroy(&accel);
      return NULL;
   }

   return accel;
}

/**
 *
 *
 */
DmtxPassFail
AccelDestroy(DmtxAccel **accel)
{
   if(accel == NULL || *accel == NULL)
      return DmtxFail;

   dmtxValueGridDestroy(&((*accel)->vs));
   dmtxValueGridDestroy(&((*accel)->hs));
   dmtxValueGridDestroy(&((*accel)->hh));
   dmtxValueGridDestroy(&((*accel)->hb));
   dmtxValueGridDestroy(&((*accel)->vb));
   dmtxValueGridDestroy(&((*accel)->vv));

   free(*accel);
   *accel = NULL;

   return DmtxPass;
}

#define RETURN_FAIL_IF(c) if(c) { return DmtxFail; }

/**
 *
 *
 */
DmtxPassFail
AccelPopulate(DmtxDecode2 *dec)
{
   DmtxAccel *accel;

   assert(dec != NULL && dec->accel != NULL);

   accel = dec->accel;

   RETURN_FAIL_IF(AccelPopulateLocal(accel->vv) == DmtxFail);
   RETURN_FAIL_IF(AccelPopulateLocal(accel->vb) == DmtxFail);
   RETURN_FAIL_IF(AccelPopulateLocal(accel->hb) == DmtxFail);
   RETURN_FAIL_IF(AccelPopulateLocal(accel->hh) == DmtxFail);
   RETURN_FAIL_IF(AccelPopulateLocal(accel->hs) == DmtxFail);
   RETURN_FAIL_IF(AccelPopulateLocal(accel->vs) == DmtxFail);

   dec->fn.dmtxValueGridCallback(accel->vv, 4);
   dec->fn.dmtxValueGridCallback(accel->vb, 5);
   dec->fn.dmtxValueGridCallback(accel->hb, 7);
   dec->fn.dmtxValueGridCallback(accel->hh, 8);
   dec->fn.dmtxValueGridCallback(accel->hs, 9);
   dec->fn.dmtxValueGridCallback(accel->vs, 6);

   return DmtxPass;
}

#undef RETURN_FAIL_IF

/**
 *
 *
 */
DmtxPassFail
AccelPopulateLocal(DmtxValueGrid *acc)
{
   int sWidth, sHeight;
   int aWidth, aHeight;
   int sIdx, sIdxNext, sInc, aIdx;
   int x, y;
   DmtxValueGrid *sob;

   sob = acc->ref;

   sWidth = dmtxValueGridGetWidth(sob);
   sHeight = dmtxValueGridGetHeight(sob);

   switch(acc->type) {
      case DmtxEdgeVertical:
         aWidth = sWidth - 1;
         aHeight = sHeight;
         sInc = 1;
         break;

      case DmtxEdgeHorizontal:
         aWidth = sWidth;
         aHeight = sHeight - 1;
         sInc = sWidth;
         break;

      default:
         return DmtxFail;
   }

   for(y = 0; y < aHeight; y++)
   {
      sIdx = y * sWidth;
      aIdx = y * aWidth;

      for(x = 0; x < aWidth; x++)
      {
         sIdxNext = sIdx + sInc;
         acc->value[aIdx] = sob->value[sIdxNext] - sob->value[sIdx];
         aIdx++;
         sIdx++;
      }
   }

   return DmtxPass;
}
Added jni/libdmtx/test/multi_test/dmtxdecode2.c.


















































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxdecode2.c
 */

#include <math.h>
#include <assert.h>
#include "../../dmtx.h"
#include "multi_test.h"

/**
 *
 *
 */
DmtxDecode2 *
dmtxDecode2Create(DmtxImage *img)
{
   DmtxDecode2 *dec;

   dec = (DmtxDecode2 *)calloc(1, sizeof(DmtxDecode2));
   if(dec == NULL)
      return NULL;

   PopulateVanishBounds(dec);

   return dec;
}

/**
 *
 *
 */
DmtxPassFail
dmtxDecode2Destroy(DmtxDecode2 **dec)
{
   if(dec == NULL || *dec == NULL)
      return DmtxFail;

   decode2ReleaseCacheMemory(*dec);

   free(*dec);
   *dec = NULL;

   return DmtxPass;
}

#define RETURN_FAIL_IF(c) \
   if(c) { \
      decode2ReleaseCacheMemory(dec); \
      return DmtxFail; \
   }

/**
 *
 *
 */
void
PopulateVanishBounds(DmtxDecode2 *dec)
{
   int d, phi;

   for(phi = 0; phi < 128; phi++)
      for(d = 0; d < 64; d++)
         dec->corners[d][phi] = GetVanishCorners(d, phi);
}

/**
 *
 *
 */
DmtxVanishCorners
GetVanishCorners(int d, int phi)
{
   DmtxVanishCorners vBound;
   DmtxVectorPair locs, dirs;
   int zone;
   int dFull, phiFull;
   double l, phiRad, bucketRad;
   DmtxVector2 v;

   dFull = d - 32;
   phiFull = (dFull < 0) ? phi + 128 : phi;
   assert(phiFull >= 0 && phiFull < 256);
   phiRad = phi * (M_PI/128.0);

   /* Infinity */
   if(dFull == 0)
   {
      zone = GetZone(phiFull, NULL);
      locs = GetZoneCornerLocs(zone);

      dirs.a.X = dirs.b.X = cos(phiRad); /* XXX does phiRad point in this direction, or right angle? */
      dirs.a.Y = dirs.b.Y = sin(phiRad);
   }
   else
   {
      bucketRad = abs(dFull) * (M_PI/96.0);
      l = 32/tan(bucketRad);
      zone = GetZone(phiFull, &l);
      locs = GetZoneCornerLocs(zone);

      v.X = l * cos(phiRad);
      v.Y = l * sin(phiRad); /* XXX remember phiRad may not point in direction you think */

      dmtxVector2Sub(&dirs.a, &v, &locs.a);
      dmtxVector2Sub(&dirs.b, &v, &locs.b);

      dmtxVector2Norm(&dirs.a); /* I think this is necessary */
      dmtxVector2Norm(&dirs.b);
   }

   vBound.zone = zone;
   vBound.lineA.p = locs.a;
   vBound.lineA.v = dirs.a;
   vBound.lineB.p = locs.b;
   vBound.lineB.v = dirs.b;

   return vBound;
}

/**
 *
 *
 */
int
GetZone(int phiFull, double *distance)
{
   int zone0 = 0;
   int zone1, zone2;
   double phiRad, xComp, yComp;

   if(phiFull < 32 || phiFull >= 224)
      zone1 = DmtxOctantTop;
   else if(phiFull < 96)
      zone1 = DmtxOctantLeft;
   else if(phiFull < 160)
      zone1 = DmtxOctantBottom;
   else
      zone1 = DmtxOctantRight;

   /* Orthagonal directions */
   if(phiFull == 0 || phiFull == 64 || phiFull == 128 || phiFull == 196)
      return (distance != NULL && *distance < 32.0) ? zone0 : zone1;

   if(phiFull < 64)
      zone2 = DmtxOctantTopLeft;
   else if(phiFull < 128)
      zone2 = DmtxOctantBottomLeft;
   else if(phiFull < 192)
      zone2 = DmtxOctantBottomRight;
   else
      zone2 = DmtxOctantTopRight;

   /* Non-orthagonal vanishing point at infinity */
   if(distance == NULL)
      return zone2;

   /* Must be a finite non-orthagonal vanishing point */
   phiRad = phiFull * (M_PI/128.0);
   xComp = fabs(32.0/cos(phiRad)); /* remember phiRad may not point in direction you think */
   yComp = fabs(32.0/sin(phiRad));

   if(*distance > max(xComp,yComp))
      return zone2;
   else if(*distance > min(xComp,yComp))
      return zone1;

   return zone0;
}

/**
 *
 *
 */
DmtxVectorPair
GetZoneCornerLocs(DmtxOctantType zone)
{
   const DmtxVector2 p00 = { 0.0, 0.0 }; /* should be { -32.0, -32.0 } ? */
   const DmtxVector2 p10 = { 1.0, 0.0 };
   const DmtxVector2 p11 = { 1.0, 1.0 };
   const DmtxVector2 p01 = { 0.0, 1.0 };
   DmtxVectorPair locs;

   switch(zone)
   {
      case DmtxOctantTop:
         locs.a = p11;
         locs.b = p01;
         break;
      case DmtxOctantLeft:
         locs.a = p01;
         locs.b = p00;
         break;
      case DmtxOctantBottom:
         locs.a = p00;
         locs.b = p10;
         break;
      case DmtxOctantRight:
         locs.a = p10;
         locs.b = p11;
         break;
      case DmtxOctantTopLeft:
      case DmtxOctantBottomRight:
         locs.a = p00;
         locs.b = p11;
         break;
      case DmtxOctantBottomLeft:
      case DmtxOctantTopRight:
      default: /* XXX this feels wrong */
         locs.a = p10;
         locs.b = p01;
         break;
   }

   return locs;
}

/**
 *
 *
 */
DmtxPassFail
dmtxDecode2SetImage(DmtxDecode2 *dec, DmtxImage *img)
{
   if(dec == NULL)
      return DmtxFail;

   dec->image = img;

   /* XXX decide here how big and how small to scale the image, and what level to go to */
   /*     store it in the decode struct */

   /* Free existing buffers if sized incorrectly */
   /* if(buffers are allocated but sized incorrectly) */
   RETURN_FAIL_IF(decode2ReleaseCacheMemory(dec) == DmtxFail);

   /* Allocate new buffers if necessary */
   /* if(buffers are not allocated) */
   dec->sobel = SobelCreate(dec->image);
   RETURN_FAIL_IF(dec->sobel == NULL);

   dec->accel = AccelCreate(dec->sobel);
   RETURN_FAIL_IF(dec->accel == NULL);

   dec->hough = HoughCreate(1,1);
   RETURN_FAIL_IF(dec->hough == NULL);

   /* Necessary to zero out buffers? */

   RETURN_FAIL_IF(SobelPopulate(dec) == DmtxFail);
   RETURN_FAIL_IF(AccelPopulate(dec) == DmtxFail);
   RETURN_FAIL_IF(HoughPopulate(dec) == DmtxFail);

   return DmtxPass;
}

#undef RETURN_FAIL_IF

/**
 *
 *
 */
DmtxPassFail
decode2ReleaseCacheMemory(DmtxDecode2 *dec)
{
   if(dec == NULL)
      return DmtxFail;

   HoughDestroy(&(dec->hough));
   AccelDestroy(&(dec->accel));
   SobelDestroy(&(dec->sobel));

   return DmtxPass;
}
Added jni/libdmtx/test/multi_test/dmtxhough.c.




























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxhough.c
 */

#include <string.h>
#include <assert.h>
#include <math.h>
#include "multi_test.h"

/**
 *
 *
 */
DmtxHough *
HoughCreate(int cols, int rows)
{
   DmtxHough *hough;

   hough = (DmtxHough *)calloc(1, sizeof(DmtxHough));
   if(hough == NULL)
      return NULL;

   hough->cols = cols;
   hough->rows = rows;
   hough->count = hough->rows * hough->cols;
   hough->line = (DmtxHoughLocal *)calloc(hough->count, sizeof(DmtxHoughLocal));
   hough->maxima = (DmtxHoughLocal *)calloc(hough->count, sizeof(DmtxHoughLocal));
   hough->vanish = (DmtxHoughLocal *)calloc(hough->count, sizeof(DmtxHoughLocal));

   if(hough->line == NULL || hough->maxima == NULL || hough->vanish == NULL)
   {
      HoughDestroy(&hough);
      return NULL;
   }

   return hough;
}

/**
 *
 *
 */
DmtxPassFail
HoughDestroy(DmtxHough **grid)
{
   if(grid == NULL || *grid == NULL)
      return DmtxFail;

   if((*grid)->vanish != NULL)
      free((*grid)->vanish);

   if((*grid)->maxima != NULL)
      free((*grid)->maxima);

   if((*grid)->line != NULL)
      free((*grid)->line);

   free(*grid);
   *grid = NULL;

   return DmtxPass;
}

#define RETURN_FAIL_IF(c) \
   if(c) { \
      HoughDestroy(&(dec->hough)); \
      return DmtxFail; \
   }

/**
 *
 *
 */
DmtxPassFail
HoughPopulate(DmtxDecode2 *dec)
{
   int row, col, idx;
   DmtxHoughLocal *line, *maxima, *vanish;

   assert(dec->hough != NULL);

   for(row = 0; row < dec->hough->rows; row++)
   {
      for(col = 0; col < dec->hough->cols; col++)
      {
         idx = 0; /* will eventually be [hCol * width + hRol]; */

         line = &(dec->hough->line[idx]);
         maxima = &(dec->hough->maxima[idx]);
         vanish = &(dec->hough->vanish[idx]);

         RETURN_FAIL_IF(LineHoughAccumulate(line, dec) == DmtxFail);
         dec->fn.dmtxHoughLocalCallback(line, 0);

         RETURN_FAIL_IF(MaximaHoughAccumulate(maxima, line, dec) == DmtxFail);
         dec->fn.dmtxHoughLocalCallback(maxima, 1);

         RETURN_FAIL_IF(VanishHoughAccumulate(vanish, maxima) == DmtxFail);
         dec->fn.dmtxHoughLocalCallback(vanish, 2);
      }
   }

   return DmtxPass;
}

#undef RETURN_FAIL_IF

/**
 * Similar to HoughPopulate(), except starts from hough instead of sobel
 */
/*
HoughMerge()
{
   DmtxScanProgress newProgress;
   DmtxHough oldGrid, newGrid;

   oldGrid = dec->hough;

   // Merges raw hough grid into next larger grid
   newCols = (oldGrid->cols + 1)/2;
   newRows = (oldGrid->rows + 1)/2;
   newGrid = HoughCreate(newCols, newRows);
   if(newGrid == NULL)
      return DmtxFail;

   for(each new local)
      merge together info from appropriate old locals

   dec->hough = newGrid;

   // Destroy original hough data
   HoughDestroy(&(dec->hough));

   return DmtxPass;
}
*/

/**
 *
 *
 */
DmtxPassFail
LineHoughAccumulate(DmtxHoughLocal *lhRegion, DmtxDecode2 *dec)
{
   int rRow, rCol;
   int iRow, iCol;
   int iWidth, iHeight;
   int phi;
   ZeroCrossing vvZXing, vbZXing, hbZXing, hhZXing, hsZXing, vsZXing;
   DmtxAccel *accel;

   memset(lhRegion, 0x00, sizeof(DmtxHoughLocal));

   assert(dec != NULL && dec->accel != NULL);
   accel = dec->accel;

   /* Global coordinate system */
   iWidth = dmtxImageGetProp(dec->image, DmtxPropWidth);
   iHeight = dmtxImageGetProp(dec->image, DmtxPropHeight);

   lhRegion->xOrigin = gState.localOffsetX;
   lhRegion->yOrigin = gState.localOffsetY;

   /* calculate dOffset ? */

   for(rRow = 0; rRow < 64; rRow++)
   {
      iRow = lhRegion->yOrigin + rRow;

      if(iRow >= iHeight)
         continue;

      for(rCol = 0; rCol < 64; rCol++)
      {
         iCol = lhRegion->xOrigin + rCol;

         if(iCol >= iWidth)
            continue;

         vvZXing = GetZeroCrossing(accel->vv, iCol, iRow);
         vbZXing = GetZeroCrossing(accel->vb, iCol, iRow);
         hbZXing = GetZeroCrossing(accel->hb, iCol, iRow);
         hhZXing = GetZeroCrossing(accel->hh, iCol, iRow);
         hsZXing = GetZeroCrossing(accel->hs, iCol, iRow);
         vsZXing = GetZeroCrossing(accel->vs, iCol, iRow);

         if(vvZXing.mag > 0)
         {
            if(gState.displayEdge == 1)
               dec->fn.zeroCrossingCallback(vvZXing, 0);

            for(phi = 0; phi < 16; phi++)
               HoughLocalAccumulateEdge(lhRegion, phi, vvZXing);
            for(phi = 112; phi < 128; phi++)
               HoughLocalAccumulateEdge(lhRegion, phi, vvZXing);
         }

         if(vbZXing.mag > 0)
         {
            if(gState.displayEdge == 2)
               dec->fn.zeroCrossingCallback(vbZXing, 0);

            for(phi = 16; phi < 32; phi++)
               HoughLocalAccumulateEdge(lhRegion, phi, vbZXing);
         }

         if(hbZXing.mag > 0)
         {
            if(gState.displayEdge == 3)
               dec->fn.zeroCrossingCallback(hbZXing, 0);

            for(phi = 32; phi < 48; phi++)
               HoughLocalAccumulateEdge(lhRegion, phi, hbZXing);
         }

         if(hhZXing.mag > 0)
         {
            if(gState.displayEdge == 4)
               dec->fn.zeroCrossingCallback(hhZXing, 0);

            for(phi = 48; phi < 80; phi++)
               HoughLocalAccumulateEdge(lhRegion, phi, hhZXing);
         }

         if(hsZXing.mag > 0)
         {
            if(gState.displayEdge == 5)
               dec->fn.zeroCrossingCallback(hsZXing, 0);

            for(phi = 80; phi < 96; phi++)
               HoughLocalAccumulateEdge(lhRegion, phi, hsZXing);
         }

         if(vsZXing.mag > 0)
         {
            if(gState.displayEdge == 6)
               dec->fn.zeroCrossingCallback(vsZXing, 0);

            for(phi = 96; phi < 112; phi++)
               HoughLocalAccumulateEdge(lhRegion, phi, vsZXing);
         }
      }
   }

   return DmtxPass;
}

/**
 *
 *
 *
 */
DmtxPassFail
MaximaHoughAccumulate(DmtxHoughLocal *mhRegion, DmtxHoughLocal *lhRegion, DmtxDecode2 *dec)
{
   int phi, d;

   for(phi = 0; phi < 128; phi++)
      for(d = 0; d < 64; d++)
         mhRegion->bucket[d][phi] = GetMaximaWeight(lhRegion, phi, d);

   return DmtxPass;
}

/**
 *
 *
 */
int
GetMaximaWeight(DmtxHoughLocal *line, int phi, int d)
{
   int val, valDn, valUp, valDnDn, valUpUp;
   int weight;

   val = line->bucket[d][phi];
   valDn = (d >= 1) ? line->bucket[d - 1][phi] : 0;
   valUp = (d <= 62) ? line->bucket[d + 1][phi] : 0;

   /* Line is outranked by immediate neigbor in same direction (not a maxima) */
   if(valDn > val || valUp > val)
      return 0;

   valDnDn = (d >= 2) ? line->bucket[d - 2][phi] : 0;
   valUpUp = (d <= 61) ? line->bucket[d + 2][phi] : 0;

/* weight = (6 * val) - 2 * (valUp + valDn) - (valUpUp + valDnDn); */
/* weight = (5 * val) - 2 * (valUp + valDn) - (valUpUp + valDnDn); */
   weight = (5 * val) - (valUp + valDn) - 2 * (valUpUp + valDnDn);
/* weight = (3 * val) - (valUp + valDn + valUpUp + valDnDn); */
/* weight = (3 * val) - 2 * (valUp + valDn); */

   return (weight > 0) ? weight : 0;
}

/**
 *
 *
 */
DmtxPassFail
VanishHoughAccumulate(DmtxHoughLocal *vanish, DmtxHoughLocal *line)
{
   int i, d, phi, val;
   int dLine, phiLine;
   int phi128, phiBeg, phiEnd;
   int dPrev;

   for(dLine = 0; dLine < 64; dLine++)
   {
      for(phiLine = 0; phiLine < 128; phiLine++)
      {
         val = line->bucket[dLine][phiLine];
         if(val == 0)
            continue;

         phiBeg = phiLine - 20;
         phiEnd = phiLine + 20;
         dPrev = DmtxUndefined;

         for(phi = phiBeg; phi <= phiEnd; phi++)
         {
            phi128 = ((phi + 128) & 0x7f);

            d = GetVanishBucket(phi128, phiLine, dLine);
            if(d == DmtxUndefined)
               continue;

            /* Flip current d value if opposite range from phiLine */
            if(phi < 0 || phi > 127)
               d = 63 - d;

            /* Flip previous d value if crossing max phi */
            if(dPrev != DmtxUndefined && phi128 == 0)
               dPrev = 63 - dPrev;

            if(dPrev == DmtxUndefined || dPrev == d)
            {
               vanish->bucket[d][phi128] += val;
            }
            else if(dPrev < d)
            {
               for(i = dPrev + 1; i <= d; i++)
                  vanish->bucket[i][phi128] += val;
            }
            else
            {
               for(i = dPrev - 1; i >= d; i--)
                  vanish->bucket[i][phi128] += val;
            }

            dPrev = d;
         }
      }
   }

   return DmtxPass;
}

/**
 *
 *
 */
int
GetVanishBucket(int phiBucket, int phiCompare, int dCompare)
{
   int bucket;
   int phiDelta;
   double d, u, x;
   double bucketRad, phiDeltaRad, phiCompareRad;
   double bucketF;

   if(phiBucket == phiCompare)
      return 32; /* Infinity */

   phiDelta = phiCompare - phiBucket;
   if(phiDelta < -64)
      phiDelta += 128;
   else if(phiDelta > 64)
      phiDelta -= 128;

   phiCompareRad = phiCompare * (M_PI/128.0);
   phiDeltaRad = phiDelta * (M_PI/128.0);

   d = UncompactOffset(dCompare, phiCompare, 64);
   u = 32.0 * (cos(phiCompareRad) + sin(phiCompareRad));
   x = fabs((d - u)/sin(phiDeltaRad));

   if(x < 0.0001)
      return DmtxUndefined;

   bucketRad = atan(32.0/x);
   assert(bucketRad > 0.0);

   /* map 0 -> pi/2 to 0 -> 64 */
   bucketF = bucketRad * (96.0/M_PI);
   bucket = (bucketF > 0.0) ? (int)(bucketF + 0.5) : (int)(bucketF - 0.5);

   if(phiDelta * (d - u) < 0.0)
      bucket = -bucket;

   bucket += 32;

   if(bucket < 0)
      bucket = DmtxUndefined;
   else if(bucket > 63)
      bucket = DmtxUndefined;

   return bucket;
}

/**
 *
 *
 */
ZeroCrossing
GetZeroCrossing(DmtxValueGrid *accel, int iCol, int iRow)
{
   int aInc, aIdx, aIdxNext;
   int aRow, aCol;
   int aWidth, aHeight;
   int aHere, aNext, aPrev;
   double smidge;
   const ZeroCrossing emptyEdge = { 0, 0, 0, 0.0, 0.0 };
   ZeroCrossing edge;

   assert(accel->type == DmtxEdgeVertical || accel->type == DmtxEdgeHorizontal);

   aWidth = dmtxValueGridGetWidth(accel);
   aHeight = dmtxValueGridGetHeight(accel);

   /* XXX add better bounds checking of aIdxNext now that we're comparing diagonals */

   if(accel->type == DmtxEdgeVertical)
   {
      aRow = iRow - 1;
      aCol = iCol - 2;
      aInc = 1;
   }
   else { /* DmtxEdgeHorizontal */
      aRow = iRow - 2;
      aCol = iCol - 1;
      aInc = aWidth;
   }

   aIdx = aRow * aWidth + aCol;
   aIdxNext = aIdx + aInc;
   aHere = accel->value[aIdx];
   aNext = accel->value[aIdxNext];

   edge = emptyEdge;

   if(OPPOSITE_SIGNS(aHere, aNext))
   {
      /* Zero crossing: Neighbors with opposite signs [-10,+10] */
      smidge = abs(aHere/(aHere - aNext));
      edge = SetZeroCrossingFromIndex(accel, iCol, iRow, smidge);
   }
   else if(aHere == 0 && aNext != 0)
   {

      if(!(accel->type == DmtxEdgeVertical && aCol == 0) &&
            !(accel->type == DmtxEdgeHorizontal && aRow == 0))
      {
         aPrev = accel->value[aIdx-aInc];
         if(OPPOSITE_SIGNS(aPrev, aNext))
         {
            /* Zero crossing: Opposite signs separated by zero [-10,0,+10] */
            smidge = 0.0;
            edge = SetZeroCrossingFromIndex(accel, iCol, iRow, smidge);
         }
      }
   }

   return edge;
}

/**
 * 0 < smidge < 1
 *
 */
ZeroCrossing
SetZeroCrossingFromIndex(DmtxValueGrid *accel, int iCol, int iRow, double smidge)
{
   int sCol, sRow, sIdx;
   ZeroCrossing edge;
   DmtxValueGrid *sobel = accel->ref;

   edge.iCol = iCol;
   edge.iRow = iRow;

   if(accel->type == DmtxEdgeVertical)
   {
      edge.x = (double)iCol + smidge;
      edge.y = (double)iRow + 0.5;
   }
   else /* DmtxEdgeHorizontal */
   {
      edge.x = (double)iCol + 0.5;
      edge.y = (double)iRow + smidge;
   }

   sRow = iRow - 1;
   sCol = iCol - 1;

   if(sCol < 0 || sCol >= sobel->width || sRow < 0 || sRow >= sobel->height)
   {
      /* Sobel location out of bounds */
      edge.mag = 0;
   }
   else
   {
      /* Use Sobel value that falls directly between 2 accel locations */
      sIdx = sRow * dmtxValueGridGetWidth(sobel) + sCol;
      edge.mag = abs(sobel->value[sIdx]);
   }

   return edge;
}

/**
 *
 *
 */
DmtxPassFail
HoughLocalAccumulateEdge(DmtxHoughLocal *line, int phi, ZeroCrossing edge)
{
   double d;
   int dInt;

   d = HoughGetLocalOffset(edge.x - line->xOrigin, edge.y - line->yOrigin, phi);
   dInt = (int)d;

   assert(dInt >= 0 && dInt < 64);
   assert(phi >= 0 && phi < 128);

   line->bucket[dInt][phi] += edge.mag;

   return DmtxPass;
}

/**
 *
 *
 */
double
HoughGetLocalOffset(double xLoc, double yLoc, int phi)
{
   double phiRad, sinPhi, cosPhi;
   double scale, d;

   phiRad = (phi * M_PI)/128.0;
   sinPhi = sin(phiRad);
   cosPhi = cos(phiRad);

   if(phi <= 64)
   {
      scale = 1.0 / (sinPhi + cosPhi);
      d = (xLoc * cosPhi + yLoc * sinPhi) * scale;
   }
   else
   {
      scale = 1.0 / (sinPhi - cosPhi);
      d = ((xLoc * cosPhi + yLoc * sinPhi) - (cosPhi * 64.0)) * scale;
   }

   return d;
}
Added jni/libdmtx/test/multi_test/dmtxregion2.c.




















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxregion2.c
 */

#include <string.h>
#include <math.h>
#include <assert.h>
#include "../../dmtx.h"
#include "multi_test.h"
#include "kiss_fftr.h"

#define RETURN_FAIL_IF(c) if(c) { return DmtxFail; }

/*
struct Deskew {
   DmtxMatrix3 fit2raw;
   DmtxMatrix3 raw2fit;
}

struct Timing {
   double shift;
   double period;
}

struct AlignmentGrid {
   Deskew align;
   Timing vTiming;
   Timing hTiming;
}
*/

/**
 *
 *
 */
DmtxPassFail
dmtxRegion2FindNext(DmtxDecode2 *dec)
{
   int i, j;
   int phiDiff, phiDiffTmp;
   DmtxBoolean regionFound;
   DmtxPassFail passFail;
   VanishPointSort vPoints;
   DmtxOrient orient;

   vPoints = dmtxFindVanishPoints(dec->hough->vanish);
   dec->fn.vanishPointCallback(&vPoints, 0);

   for(i = 0, regionFound = DmtxFalse; i < vPoints.count && regionFound == DmtxFalse; i++)
   {
      for(j = i + 1; j < vPoints.count; j++)
      {
         phiDiffTmp = abs(vPoints.bucket[i].phi - vPoints.bucket[j].phi);
         phiDiff = (phiDiffTmp < 64) ? phiDiffTmp : 128 - phiDiffTmp;

         /* Reject angle combinations that are too close */
         if(phiDiff < 36)
            continue;

         /* Build oriented (but still untimed) grid from vanish points */
         passFail = OrientRegion(&orient, vPoints.bucket[i], vPoints.bucket[j], dec);
         if(passFail == DmtxFail)
            continue;

         /* Build timed grid from untimed grid and line hough */
/*       align = CalibrateRegion(region, orient, lHough, &passFail);
         if(passFail == DmtxFail)
            continue;
*/
/*
         // timings = dmtxFindGridTiming(dec->hough->line, &vPoints);

         err = dmtxBuildGridFromTimings(&grid, timings.timing[i], timings.timing[j]);
         if(err == DmtxFail)
            continue; // Keep trying

         dec->fn.timingCallback(&timings.timing[i], &timings.timing[j], 1);

         // Hack together raw2fitFull and fit2rawFull outside since we need app data
         AddFullTransforms(&grid);

         err = dmtxFindRegionWithinGrid(&region, &grid, &houghCache, dec, fn);
         regionFound = (err == DmtxPass) ? DmtxTrue : DmtxFalse;

         if(regionFound == DmtxTrue) {
            region.sizeIdx = dmtxGetSizeIdx(region.width, region.height);
            if(region.sizeIdx >= DmtxSymbol10x10 && region.sizeIdx <= DmtxSymbol16x48)
               dmtxDecodeSymbol(&region, dec);
         }

         regionFound = DmtxTrue; // break out of outer loop
         break; // break out of inner loop
*/
      }
   }

   return DmtxPass;
}

/**
 *
 *
 */
DmtxPassFail
OrientRegion(DmtxOrient *orient, DmtxHoughBucket v0, DmtxHoughBucket v1, DmtxDecode2 *dec)
{
   DmtxRay2 v0a, v0b, v1a, v1b;

   v0a = dec->corners[v0.d][v0.phi].lineA;
   v0b = dec->corners[v0.d][v0.phi].lineB;
   v1a = dec->corners[v1.d][v1.phi].lineA;
   v1b = dec->corners[v1.d][v1.phi].lineB;
/*
   RegionFromSides(v0a, v0b, v1a, v1b);
*/
   return DmtxPass;
}

/**
 *
 *
 */
/*
DmtxPassFail
CalibrateRegion(DmtxOrient *orient)
{
input:  orientation (transformation matrix)
        hough line cache

output: timed alignment grid

description:
  fourier transform receives evenly spaced samples to be taken in both directions (v and h)
    -> tranforms into frequency space
    -> major frequency emerges
  determine shift as post-processing step (can't remember how I did it before at the moment)

  need to interpolate values between true locations in line hough because
    "evenly spaced" describes positions in the normalized fitted region whereas
    the hough values are aligned along raw image coordinates

  step size should be determined based on desired fft dimensions (maybe 64
    steps?) ... check what we did for poc

steps:
   for each step 0-63 upward along Y axis
      xFit = 0
      yFit = 1-63
      xRaw,yRaw = VMult(fit2raw,xFit,yFit)
      lineFit = (xRaw - 0, yRaw - 0) (duh)
      phi = lineFit angle (something like atan2)
      d = vector2Mag(lineFit)
      interpolate hough[d][phi] and add to fft
      that was easy

   return DmtxPass;
}
*/

/**
 * Future structure of dmtxRegion2FindNext() (after getting orientation and timing working again)
 *
 * TODO:
 * o Is there a way to name HoughGridPopulate() and HoughGridMerge() to show they are sister functions?
 *
 * hough lines, hough line maxima, and hough vanish can be calculated for entire image at once
 * for each local:
 *    for each combination of vpoint pairs:
 *       step outward
 *          if step takes us into adjacent local
 *              add maxima from adjacent local into existing vpoint hough accumulator
 *              rescan for updated vpoints (using original centerline, adding only portion of region?)
 *              get new timing (?)
 *              continue stepping path where we left off?
 *
 * progress:
 *    level
 *    row
 *    col
 *    vanish point combo (?)
 */
/*
dmtxRegion2FindNext(DmtxDecode2 *dec)
{
   if(starting new level other than the first)
      HoughGridMerge();

   // for each new local
   while(dec->localIdx < dec->localCount)
   {
      // each valid combination of vanish points
      for(dec->vPointIdx < 28)
      {
         vPointI = xyz;
         vPointJ = xyz;

         while(perimeter condition not met)
         {
            stepOutward()

            if(first step in new local, including first)
            {
               add new region to central vanish hough
               update vanish points (shouldn't move too far)
               record that new local was added to stats
               redo timing
            }

            test perimeter for known strip patterns
            if(perimeter says that barcode region is found) {
               save current progress ("?")
               return region;
            }
         }
      }
   }

   return NULL;
}
*/

/**
 *
 *
 */
double
UncompactOffset(double compactedOffset, int phiIdx, int extent)
{
   double phiRad;
   double scale;
   double posMax, negMax;

   phiRad = M_PI * phiIdx / 128.0;

   if(phiIdx < 64) {
      posMax = extent * (cos(phiRad) + sin(phiRad));
      negMax = 0.0;
   }
   else {
      posMax = extent * sin(phiRad);
      negMax = extent * cos(phiRad);
   }

   assert(extent > 0);
   scale = (posMax - negMax) / extent;

   return (compactedOffset * scale) + negMax;
}

/**
 *
 *
 */
void
AddToVanishPointSort(VanishPointSort *sort, DmtxHoughBucket bucket)
{
   int i, startHere;
   int phiDiff, phiDiffTmp;
   DmtxBoolean isFull;
   DmtxHoughBucket *lastBucket;

   isFull = (sort->count == ANGLE_SORT_MAX_COUNT) ? DmtxTrue : DmtxFalse;
   lastBucket = &(sort->bucket[ANGLE_SORT_MAX_COUNT - 1]);

   /* Array is full and incoming bucket is already weakest */
   if(isFull && bucket.val < lastBucket->val)
      return;

   startHere = DmtxUndefined;

   /* If sort already has entry near this angle then either:
    *   a) Overwrite the old one without shifting if stronger
    *   b) Reject the new one completely if weaker
    */
   for(i = 0; i < sort->count; i++)
   {
      phiDiffTmp = abs(bucket.phi - sort->bucket[i].phi);
      phiDiff = (phiDiffTmp < 64) ? phiDiffTmp : 128 - phiDiffTmp;

      if(phiDiff < 10)
      {
         /* Similar angle is already represented with stronger magnitude */
         if(bucket.val < sort->bucket[i].val)
         {
            return;
         }
         /* Found similar-but-weaker angle that will be overwritten */
         else
         {
            sort->bucket[i] = bucket;
            startHere = i;
            break;
         }
      }
   }

   if(startHere == DmtxUndefined)
   {
      if(isFull)
         *lastBucket = bucket;
      else
         sort->bucket[sort->count++] = bucket;

      startHere = sort->count - 1;
   }

   /* Shift weak entries downward */
   for(i = startHere; i > 0; i--)
   {
      if(bucket.val > sort->bucket[i-1].val)
      {
         sort->bucket[i] = sort->bucket[i-1];
         sort->bucket[i-1] = bucket;
      }
      else
      {
         break;
      }
   }
}

/**
 *
 *
 */
VanishPointSort
dmtxFindVanishPoints(DmtxHoughLocal *vHough)
{
   DmtxHoughBucket bucket;
   VanishPointSort sort;

   memset(&sort, 0x00, sizeof(VanishPointSort));

   for(bucket.phi = 0; bucket.phi < 128; bucket.phi++)
   {
      for(bucket.d = 0; bucket.d < 64; bucket.d++)
      {
         bucket.val = vHough->bucket[bucket.d][bucket.phi];
         AddToVanishPointSort(&sort, bucket);
      }
   }

   return sort;
}

/**
 *
 *
 */
void
AddToMaximaSort(HoughMaximaSort *sort, int maximaMag)
{
   int i;

   /* If new entry would be weakest (or only) one in list, then append */
   if(sort->count == 0 || maximaMag < sort->mag[sort->count - 1]) {
      if(sort->count + 1 < MAXIMA_SORT_MAX_COUNT)
         sort->mag[sort->count++] = maximaMag;
      return;
   }

   /* Otherwise shift the weaker entries downward */
   for(i = sort->count - 1; i >= 0; i--) {
      if(maximaMag > sort->mag[i]) {
         if(i + 1 < MAXIMA_SORT_MAX_COUNT)
            sort->mag[i+1] = sort->mag[i];
         sort->mag[i] = maximaMag;
      }
   }

   if(sort->count < MAXIMA_SORT_MAX_COUNT)
      sort->count++;
}

/**
 * Return sum of top 8 maximum points (hmmm)
 * btw, can we skip this step entirely?
 */
DmtxHoughBucket
GetAngleSumAtPhi(DmtxHoughLocal *line, int phi)
{
   int i, d;
   int prev, here, next;
   DmtxHoughBucket bucket;
   HoughMaximaSort sort;

   memset(&sort, 0x00, sizeof(HoughMaximaSort));

   /* Handle last condition separately; one sided comparison */
   prev = line->bucket[62][phi];
   here = line->bucket[63][phi];
   if(here > prev)
      AddToMaximaSort(&sort, here);

   /* Handle first condition separately; one sided comparison */
   here = line->bucket[0][phi];
   next = line->bucket[1][phi];
   if(here > next)
      AddToMaximaSort(&sort, here);

   /* Handle remaining conditions as two sided comparisons */
   for(d = 2; d < 64; d++)
   {
      prev = here;
      here = next;
      next = line->bucket[d][phi];

      if(here > 0 && here >= prev && here >= next)
         AddToMaximaSort(&sort, here);
   }

   bucket.d = 0;
   bucket.phi = phi;
   bucket.val = 0;
   for(i = 0; i < 8; i++)
      bucket.val += sort.mag[i];

   return bucket;
}

/**
 *
 *
 */
void
AddToTimingSort(DmtxTimingSort *sort, Timing timing)
{
   int i;

   if(timing.mag < 1.0) /* XXX or some minimum threshold */
      return;

   /* If new entry would be weakest (or only) one in list, then append */
   if(sort->count == 0 || timing.mag < sort->timing[sort->count - 1].mag) {
      if(sort->count + 1 < TIMING_SORT_MAX_COUNT)
         sort->timing[sort->count++] = timing;
      return;
   }

   /* Otherwise shift the weaker entries downward */
   for(i = sort->count - 1; i >= 0; i--) {
      if(timing.mag > sort->timing[i].mag) {
         if(i + 1 < TIMING_SORT_MAX_COUNT)
            sort->timing[i+1] = sort->timing[i];
         sort->timing[i] = timing;
      }
   }

   if(sort->count < TIMING_SORT_MAX_COUNT)
      sort->count++;
}

/**
 *
 *
 */
DmtxTimingSort
dmtxFindGridTiming(DmtxHoughLocal *line, VanishPointSort *vPoints)
{
   int x, y, fitMag, fitMax, fitOff, attempts, iter;
   int i, vSortIdx, phi;
   kiss_fftr_cfg   cfg = NULL;
   kiss_fft_scalar rin[NFFT];
   kiss_fft_cpx    sout[NFFT/2+1];
   kiss_fft_scalar mag[NFFT/2+1];
   int maxIdx;
   Timing timing;
   DmtxTimingSort timings;

   memset(&timings, 0x00, sizeof(DmtxTimingSort));

   for(vSortIdx = 0; vSortIdx < vPoints->count; vSortIdx++) {

      phi = vPoints->bucket[vSortIdx].phi;

      /* Load FFT input array */
      for(i = 0; i < NFFT; i++) {
         rin[i] = (i < 64) ? line->bucket[i][phi] : 0;
      }

      /* Execute FFT */
      memset(sout, 0x00, sizeof(kiss_fft_cpx) * (NFFT/2 + 1));
      cfg = kiss_fftr_alloc(NFFT, 0, 0, 0);
      kiss_fftr(cfg, rin, sout);
      free(cfg);

      /* Select best result */
      maxIdx = NFFT/9-1;
      for(i = 0; i < NFFT/9-1; i++)
         mag[i] = 0.0;
      for(i = NFFT/9-1; i < NFFT/2+1; i++) {
         mag[i] = sout[i].r * sout[i].r + sout[i].i * sout[i].i;
         if(mag[i] > mag[maxIdx])
            maxIdx = i;
      }

      timing.phi = phi;
      timing.period = NFFT / (double)maxIdx;
      timing.mag = mag[maxIdx];

      /* Find best offset */
      fitOff = fitMax = 0;
      attempts = (int)timing.period + 1;
      for(x = 0; x < attempts; x++) {
         fitMag = 0;
         for(iter = 0; ; iter++) {
            y = x + (int)(iter * timing.period);
            if(y >= 64)
               break;
            fitMag += line->bucket[y][timing.phi];
         }
         if(x == 0 || fitMag > fitMax) {
            fitMax = fitMag;
            fitOff = x;
         }
      }
      timing.shift = fitOff;

      AddToTimingSort(&timings, timing);
   }

   return timings;
}

/**
 *
 *
 */
DmtxRay2
HoughCompactToRay(int phi, double d)
{
   double phiRad;
   double dScaled;
   DmtxRay2 rStart, rLine;

   memset(&rStart, 0x00, sizeof(DmtxRay2));
   memset(&rLine, 0x00, sizeof(DmtxRay2));

   rStart.p.X = rStart.p.Y = 0.0;

   phiRad = phi * M_PI/128.0;

   rStart.v.X = cos(phiRad);
   rStart.v.Y = sin(phiRad);

   rLine.v.X = -rStart.v.Y;
   rLine.v.Y = rStart.v.X;

   dScaled = UncompactOffset(d, phi, LOCAL_SIZE);

   dmtxPointAlongRay2(&(rLine.p), &rStart, dScaled);

   return rLine;
}

/**
 *
 *
 *
 */
DmtxPassFail
dmtxBuildGridFromTimings(AlignmentGrid *grid, Timing vp0, Timing vp1)
{
   RegionLines rl0, rl1, *flat, *steep;
   DmtxVector2 p00, p10, p11, p01;
   DmtxMatrix3 fit2raw, raw2fit, mScale;

   /* (1) -- later compare all possible combinations for strongest pair */
   rl0.timing = vp0;
   rl0.gridCount = (int)((64.0 - vp0.shift)/vp0.period);
   rl0.dA = vp0.shift;
   rl0.dB = vp0.shift + vp0.period * rl0.gridCount; /* doesn't work but whatever */

   rl1.timing = vp1;
   rl1.gridCount = (int)((64.0 - vp1.shift)/vp1.period);
   rl1.dA = vp1.shift;
   rl1.dB = vp1.shift + vp1.period * rl1.gridCount; /* doesn't work but whatever */

   /* flat[0] is the bottom flat line */
   /* flat[1] is the top flat line */
   /* steep[0] is the left steep line */
   /* steep[1] is the right line */

   /* Line with angle closest to horizontal is flatest */
   if(abs(64 - rl0.timing.phi) < abs(64 - rl1.timing.phi)) {
      flat = &rl0;
      steep = &rl1;
   }
   else {
      flat = &rl1;
      steep = &rl0;
   }

   flat->line[0] = HoughCompactToRay(flat->timing.phi, flat->dA);
   flat->line[1] = HoughCompactToRay(flat->timing.phi, flat->dB);

   if(steep->timing.phi < 64) {
      steep->line[0] = HoughCompactToRay(steep->timing.phi, steep->dA);
      steep->line[1] = HoughCompactToRay(steep->timing.phi, steep->dB);
   }
   else {
      steep->line[0] = HoughCompactToRay(steep->timing.phi, steep->dB);
      steep->line[1] = HoughCompactToRay(steep->timing.phi, steep->dA);
   }

   RETURN_FAIL_IF(dmtxRay2Intersect(&p00, &(flat->line[0]), &(steep->line[0])) == DmtxFail);
   RETURN_FAIL_IF(dmtxRay2Intersect(&p10, &(flat->line[0]), &(steep->line[1])) == DmtxFail);
   RETURN_FAIL_IF(dmtxRay2Intersect(&p11, &(flat->line[1]), &(steep->line[1])) == DmtxFail);
   RETURN_FAIL_IF(dmtxRay2Intersect(&p01, &(flat->line[1]), &(steep->line[0])) == DmtxFail);
   RETURN_FAIL_IF(RegionUpdateCorners(fit2raw, raw2fit, p00, p10, p11, p01) == DmtxFail);

   grid->rowCount = flat->gridCount;
   grid->colCount = steep->gridCount;

   /* raw2fit: Final transformation fits single origin module */
   dmtxMatrix3Identity(mScale);
   dmtxMatrix3Multiply(grid->raw2fitActive, raw2fit, mScale);

   /* fit2raw: Abstract away display nuances of multi_test application */
   dmtxMatrix3Identity(mScale);
   dmtxMatrix3Multiply(grid->fit2rawActive, mScale, fit2raw);

   return DmtxPass;
}

/**
 *
 *
 */
StripStats
GenStripPatternStats(unsigned char *strip, int stripLength, int startState, int contrast)
{
   int i, jumpAmount, jumpThreshold;
   int finderLow, finderHigh, timingLow, timingHigh;
   int surpriseCount, jumpCount, contrastSum;
   int newState, currentState;
   StripStats stats;

   assert(startState == MODULE_HIGH || startState == MODULE_LOW);

   jumpThreshold = (contrast*40)/100;
   finderLow = finderHigh = timingLow = timingHigh = 0;
   surpriseCount = jumpCount = contrastSum = 0;
   currentState = startState;
   memset(&stats, 0x00, sizeof(StripStats));

   for(i = 0; i < stripLength; i++) {

      if(i > 0) {
         jumpAmount = strip[i] - strip[i-1];

         /* Tally jump statistics if occurred */
         if(abs(jumpAmount) > jumpThreshold) {
            jumpCount++;
            contrastSum += abs(jumpAmount);
            newState = (jumpAmount > 0) ? MODULE_HIGH : MODULE_LOW;

            /* Surprise! We jumped but landed in the same state */
            if(newState == currentState)
               surpriseCount++;
            else
               currentState = newState;
         }
      }

      /* Increment appropriate finder pattern */
      if(currentState == MODULE_HIGH)
         finderHigh++;
      else
         finderLow++;

      /* Increment appropriate timing pattern */
      if(currentState ^ (i & 0x01))
         timingHigh++;
      else
         timingLow++;
   }

   stats.jumps = jumpCount;
   stats.surprises = surpriseCount;
   stats.finderErrors = (finderHigh < finderLow) ? finderHigh : finderLow;
   stats.timingErrors = (timingHigh < timingLow) ? timingHigh : timingLow;

   if(jumpCount > 0) {
      stats.contrast = (int)((double)contrastSum/jumpCount + 0.5);
      stats.finderBest = (finderHigh > finderLow) ? MODULE_HIGH : MODULE_LOW;
      stats.timingBest = (timingHigh > timingLow) ? MODULE_HIGH : MODULE_LOW;
   }
   else {
      stats.contrast = 0;
      stats.finderBest = MODULE_UNKNOWN;
      stats.timingBest = MODULE_UNKNOWN;
   }

   return stats;
}

/**
 *
 *
 */
DmtxPassFail
dmtxFindRegionWithinGrid(GridRegion *region, AlignmentGrid *grid, DmtxHoughLocal *line, DmtxDecode *dec, DmtxCallbacks *fn)
{
   int goodCount;
   int finderSides;
   DmtxDirection sideDir;
   DmtxBarType innerType, outerType;
   GridRegion regGrow;

   memset(&regGrow, 0x00, sizeof(GridRegion));

   regGrow.grid = *grid; /* Capture local copy of grid for tweaking */
   regGrow.x = regGrow.grid.colCount / 2;
   regGrow.y = regGrow.grid.rowCount / 2;
   regGrow.width = 2;
   regGrow.height = 2;
   regGrow.sizeIdx = DmtxUndefined;
   regGrow.onColor = regGrow.offColor = 0;
   regGrow.contrast = 20; /* low initial value */

   /* Assume the starting region will be far enough away from any side that
    * the expansion rules won't need to work at the very smallest sizes */

   /* Grow region */
   finderSides = DmtxDirNone;
   for(goodCount = 0, sideDir = DmtxDirDown; goodCount < 4; sideDir = RotateCW(sideDir)) {
      if(regGrow.width > 26 || regGrow.height > 26)
         return DmtxFail;

      innerType = TestSideForPattern(&regGrow, dec->image, sideDir, 0);
      outerType = TestSideForPattern(&regGrow, dec->image, sideDir, 1);

      /**
       * Make smarter ... maybe:
       * 1) Check that next-farther out strips are consistent (easy)
       * 2) Check that the colors are all consistent (not as easy)
       */

      if(innerType == DmtxBarNone || outerType == DmtxBarNone) {
/*       RegionExpand(&regGrow, sideDir, line, fn); */
         finderSides = DmtxDirNone;
         goodCount = 0;
      }
      else {
         if(innerType == DmtxBarFinder)
            finderSides |= sideDir;

         goodCount++;
      }

/*    fn->perimeterCallback(&regGrow, sideDir, innerType); */
   }

   regGrow.finderSides = finderSides;
   *region = regGrow;

   return DmtxPass;
}

/**
 *
 *
 */
int dmtxReadModuleColor(DmtxImage *img, AlignmentGrid *grid, int symbolRow,
      int symbolCol, int colorPlane)
{
   int err;
   int i;
   int color, colorTmp;
   double sampleX[] = { 0.5, 0.4, 0.5, 0.6, 0.5 };
   double sampleY[] = { 0.5, 0.5, 0.4, 0.5, 0.6 };
   DmtxVector2 p;

   color = 0;
   for(i = 0; i < 5; i++) {

      p.X = (1.0/grid->colCount) * (symbolCol + sampleX[i]);
      p.Y = (1.0/grid->rowCount) * (symbolRow + sampleY[i]);

      dmtxMatrix3VMultiplyBy(&p, grid->fit2rawFull);

      /* Should use dmtxDecodeGetPixelValue() later to properly handle pixel skipping */
      err = dmtxImageGetPixelValue(img, p.X, p.Y, colorPlane, &colorTmp);
      if(err == DmtxFail)
         return 0;

      color += colorTmp;
   }

   return color/5;
}

/**
 *
 *
 */
DmtxBarType
TestSideForPattern(GridRegion *region, DmtxImage *img, DmtxDirection side, int offset)
{
   int i;
   int col, colBeg;
   int row, rowBeg;
   int extent;
   unsigned char colorStrip[26] = { 0 };
   StripStats *stats, statsHigh, statsLow;

   assert(region->width <= 26 && region->height <= 26);
   assert(side == DmtxDirUp || side == DmtxDirLeft ||
         side == DmtxDirDown || side == DmtxDirRight);

   /* Note opposite meaning (DmtxDirUp means "top", extent is horizontal) */
   extent = (side & DmtxDirVertical) ? region->width : region->height;
   if(extent < 3)
      return DmtxBarNone;

   switch(side) {
      case DmtxDirUp:
         colBeg = region->x;
         rowBeg = (region->y + region->height - 1) + offset;
         break;
      case DmtxDirLeft:
         colBeg = region->x - offset;
         rowBeg = region->y;
         break;
      case DmtxDirDown:
         colBeg = region->x;
         rowBeg = region->y - offset;
         break;
      case DmtxDirRight:
         colBeg = (region->x + region->width - 1) + offset;
         rowBeg = region->y;
         break;
      default:
         return DmtxUndefined;
   }

   /* Sample and hold colors at each module along both inner and outer edges */
   col = colBeg;
   row = rowBeg;

   for(i = 0; i < extent; i++) {
      colorStrip[i] = dmtxReadModuleColor(img, &(region->grid), row, col, 0);

      if(side & DmtxDirVertical)
         col++;
      else
         row++;
   }

   statsHigh = GenStripPatternStats(colorStrip, extent, MODULE_HIGH, region->contrast);
   statsLow = GenStripPatternStats(colorStrip, extent, MODULE_LOW, region->contrast);
   stats = (statsHigh.surprises > statsLow.surprises) ? &statsLow : &statsHigh;

   if(stats->contrast > region->contrast) {
      region->contrast = stats->contrast;
   }

   if(stats->finderErrors < stats->timingErrors) {
      if(stats->finderErrors < 2) {
         return DmtxBarFinder;
      }
   }
   else if(stats->finderErrors > stats->timingErrors) {
      if(stats->timingErrors < 2) {
         return DmtxBarTiming;
      }
   }

   return DmtxBarNone;
}

#define DmtxAlmostZero          0.000001

/**
 *
 *
 */
DmtxPassFail
Vector2Norm(DmtxVector2 *v)
{
   double mag;

   mag = dmtxVector2Mag(v);

   if(mag <= DmtxAlmostZero)
      return DmtxFail;

   dmtxVector2ScaleBy(v, 1/mag);

   return DmtxTrue;
}

/**
 *
 *
 */
DmtxPassFail
RayFromPoints(DmtxRay2 *ray, DmtxVector2 p0, DmtxVector2 p1)
{
   DmtxRay2 r;

   r.tMin = 0.0;
   r.tMax = 1.0;
   r.p = p0;

   dmtxVector2Sub(&r.v, &p1, &p0);
   RETURN_FAIL_IF(Vector2Norm(&r.v) == DmtxFail);

   *ray = r;

   return DmtxPass;
}

/**
 * Not a generic function. Notice that it uses fit2rawActive.
 *
 */
DmtxPassFail
dmtxRegionToSides(GridRegion *region, DmtxRegionSides *regionSides)
{
   DmtxVector2 p00, p10, p11, p01;
   DmtxRegionSides rs;

   p00.X = p01.X = region->x * (1.0/region->grid.colCount);
   p10.X = p11.X = (region->x + region->width) * (1.0/region->grid.colCount);
   p00.Y = p10.Y = region->y * (1.0/region->grid.rowCount);
   p01.Y = p11.Y = (region->y + region->height) * (1.0/region->grid.rowCount);

   dmtxMatrix3VMultiplyBy(&p00, region->grid.fit2rawActive);
   dmtxMatrix3VMultiplyBy(&p10, region->grid.fit2rawActive);
   dmtxMatrix3VMultiplyBy(&p11, region->grid.fit2rawActive);
   dmtxMatrix3VMultiplyBy(&p01, region->grid.fit2rawActive);

   RETURN_FAIL_IF(RayFromPoints(&rs.bottom, p00, p10) == DmtxFail);
   RETURN_FAIL_IF(RayFromPoints(&rs.right, p10, p11) == DmtxFail);
   RETURN_FAIL_IF(RayFromPoints(&rs.top, p11, p01) == DmtxFail);
   RETURN_FAIL_IF(RayFromPoints(&rs.left, p01, p00) == DmtxFail);

   *regionSides = rs;

   return DmtxPass;
}

/**
 *
 *
 */
DmtxPassFail
dmtxRegionUpdateFromSides(GridRegion *region, DmtxRegionSides regionSides)
{
   DmtxVector2 p00, p10, p11, p01;

   RETURN_FAIL_IF(dmtxRay2Intersect(&p00, &(regionSides.left), &(regionSides.bottom)) == DmtxFail);
   RETURN_FAIL_IF(dmtxRay2Intersect(&p10, &(regionSides.bottom), &(regionSides.right)) == DmtxFail);
   RETURN_FAIL_IF(dmtxRay2Intersect(&p11, &(regionSides.right), &(regionSides.top)) == DmtxFail);
   RETURN_FAIL_IF(dmtxRay2Intersect(&p01, &(regionSides.top), &(regionSides.left)) == DmtxFail);

   RETURN_FAIL_IF(RegionUpdateCorners(region->grid.fit2rawActive, region->grid.raw2fitActive, p00, p10, p11, p01) == DmtxFail);
   /* need to update fit2rawFull and raw2fitFull here too? */

   return DmtxPass;
}

/**
 *
 *
 */
DmtxPassFail
RegionExpand(GridRegion *region, DmtxDirection sideDir, DmtxHoughLocal *line, DmtxCallbacks *fn)
{
   DmtxRegionSides regionSides;
   DmtxRay2 *sideRay;

   switch(sideDir) {
      case DmtxDirDown:
         region->y--;
         region->height++;
         sideRay = &(regionSides.bottom);
         break;
      case DmtxDirUp:
         region->height++;
         sideRay = &(regionSides.top);
         break;
      case DmtxDirLeft:
         region->x--;
         region->width++;
         sideRay = &(regionSides.left);
         break;
      case DmtxDirRight:
         region->width++;
         sideRay = &(regionSides.right);
         break;
      default:
         return DmtxFail;
   }

   return DmtxPass;
}

/**
 *
 *
 */
int
dmtxGetSizeIdx(int a, int b)
{
   int i, rows, cols;
   const int totalSymbolSizes = 30; /* is there a better way to determine this? */

   for(i = 0; i < totalSymbolSizes; i++) {
      rows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, i);
      cols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, i);

      if((rows == a && cols == b) || (rows == b && cols == a))
         return i;
   }

   return DmtxUndefined;
}

/**
 *
 *
 */
DmtxPassFail
RegionUpdateCorners(DmtxMatrix3 fit2raw, DmtxMatrix3 raw2fit, DmtxVector2 p00,
      DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01)
{
/* double xMax, yMax; */
   double tx, ty, phi, shx, scx, scy, skx, sky;
   double dimOT, dimOR, dimTX, dimRX; /* , ratio; */
   DmtxVector2 vOT, vOR, vTX, vRX, vTmp;
   DmtxMatrix3 m, mtxy, mphi, mshx, mscx, mscy, mscxy, msky, mskx;

/* xMax = (double)(dmtxDecodeGetProp(dec, DmtxPropWidth) - 1);
   yMax = (double)(dmtxDecodeGetProp(dec, DmtxPropHeight) - 1);

   if(p00.X < 0.0 || p00.Y < 0.0 || p00.X > xMax || p00.Y > yMax ||
         p01.X < 0.0 || p01.Y < 0.0 || p01.X > xMax || p01.Y > yMax ||
         p10.X < 0.0 || p10.Y < 0.0 || p10.X > xMax || p10.Y > yMax)
      return DmtxFail; */
   dimOT = dmtxVector2Mag(dmtxVector2Sub(&vOT, &p01, &p00)); /* XXX could use MagSquared() */
   dimOR = dmtxVector2Mag(dmtxVector2Sub(&vOR, &p10, &p00));
   dimTX = dmtxVector2Mag(dmtxVector2Sub(&vTX, &p11, &p01));
   dimRX = dmtxVector2Mag(dmtxVector2Sub(&vRX, &p11, &p10));

   /* Verify that sides are reasonably long */
/* if(dimOT <= 8.0 || dimOR <= 8.0 || dimTX <= 8.0 || dimRX <= 8.0)
      return DmtxFail; */

   /* Verify that the 4 corners define a reasonably fat quadrilateral */
/* ratio = dimOT / dimRX;
   if(ratio <= 0.5 || ratio >= 2.0)
      return DmtxFail; */

/* ratio = dimOR / dimTX;
   if(ratio <= 0.5 || ratio >= 2.0)
      return DmtxFail; */

   /* Verify this is not a bowtie shape */
/*
   if(dmtxVector2Cross(&vOR, &vRX) <= 0.0 ||
         dmtxVector2Cross(&vOT, &vTX) >= 0.0)
      return DmtxFail; */

/* if(RightAngleTrueness(p00, p10, p11, M_PI_2) <= dec->squareDevn)
      return DmtxFail;
   if(RightAngleTrueness(p10, p11, p01, M_PI_2) <= dec->squareDevn)
      return DmtxFail; */

   /* Calculate values needed for transformations */
   tx = -1 * p00.X;
   ty = -1 * p00.Y;
   dmtxMatrix3Translate(mtxy, tx, ty);

   phi = atan2(vOT.X, vOT.Y);
   dmtxMatrix3Rotate(mphi, phi);
   dmtxMatrix3Multiply(m, mtxy, mphi);

   dmtxMatrix3VMultiply(&vTmp, &p10, m);
   shx = -vTmp.Y / vTmp.X;
   dmtxMatrix3Shear(mshx, 0.0, shx);
   dmtxMatrix3MultiplyBy(m, mshx);

   scx = 1.0/vTmp.X;
   dmtxMatrix3Scale(mscx, scx, 1.0);
   dmtxMatrix3MultiplyBy(m, mscx);

   dmtxMatrix3VMultiply(&vTmp, &p11, m);
   scy = 1.0/vTmp.Y;
   dmtxMatrix3Scale(mscy, 1.0, scy);
   dmtxMatrix3MultiplyBy(m, mscy);

   dmtxMatrix3VMultiply(&vTmp, &p11, m);
   skx = vTmp.X;
   dmtxMatrix3LineSkewSide(mskx, 1.0, skx, 1.0);
   dmtxMatrix3MultiplyBy(m, mskx);

   dmtxMatrix3VMultiply(&vTmp, &p01, m);
   sky = vTmp.Y;
   dmtxMatrix3LineSkewTop(msky, sky, 1.0, 1.0);
   dmtxMatrix3Multiply(raw2fit, m, msky);

   /* Create inverse matrix by reverse (avoid straight matrix inversion) */
   dmtxMatrix3LineSkewTopInv(msky, sky, 1.0, 1.0);
   dmtxMatrix3LineSkewSideInv(mskx, 1.0, skx, 1.0);
   dmtxMatrix3Multiply(m, msky, mskx);

   dmtxMatrix3Scale(mscxy, 1.0/scx, 1.0/scy);
   dmtxMatrix3MultiplyBy(m, mscxy);

   dmtxMatrix3Shear(mshx, 0.0, -shx);
   dmtxMatrix3MultiplyBy(m, mshx);

   dmtxMatrix3Rotate(mphi, -phi);
   dmtxMatrix3MultiplyBy(m, mphi);

   dmtxMatrix3Translate(mtxy, -tx, -ty);
   dmtxMatrix3Multiply(fit2raw, m, mtxy);

   return DmtxPass;
}

/**
 *
 *
 */
DmtxPassFail
dmtxDecodeSymbol(GridRegion *region, DmtxDecode *dec)
{
   static int prefix = 0;
   int onColor, offColor;
   DmtxVector2 p00, p10, p11, p01;
   DmtxRegion reg;
   DmtxMessage *msg;

   /* Since we now hold 2 adjacent timing bars, find colors */
   RETURN_FAIL_IF(GetOnOffColors(region, dec, &onColor, &offColor) == DmtxFail);

   p00.X = p01.X = region->x * (1.0/region->grid.colCount);
   p10.X = p11.X = (region->x + region->width) * (1.0/region->grid.colCount);
   p00.Y = p10.Y = region->y * (1.0/region->grid.rowCount);
   p01.Y = p11.Y = (region->y + region->height) * (1.0/region->grid.rowCount);

   dmtxMatrix3VMultiplyBy(&p00, region->grid.fit2rawFull);
   dmtxMatrix3VMultiplyBy(&p10, region->grid.fit2rawFull);
   dmtxMatrix3VMultiplyBy(&p11, region->grid.fit2rawFull);
   dmtxMatrix3VMultiplyBy(&p01, region->grid.fit2rawFull);

   /* Update DmtxRegion with detected corners */
   switch(region->finderSides) {
      case (DmtxDirLeft | DmtxDirDown):
         RETURN_FAIL_IF(dmtxRegionUpdateCorners(dec, &reg, p00, p10, p11, p01) == DmtxFail);
         break;
      case (DmtxDirDown | DmtxDirRight):
         RETURN_FAIL_IF(dmtxRegionUpdateCorners(dec, &reg, p10, p11, p01, p00) == DmtxFail);
         break;
      case (DmtxDirRight | DmtxDirUp):
         RETURN_FAIL_IF(dmtxRegionUpdateCorners(dec, &reg, p11, p01, p00, p10) == DmtxFail);
         break;
      case (DmtxDirUp | DmtxDirLeft):
         RETURN_FAIL_IF(dmtxRegionUpdateCorners(dec, &reg, p01, p00, p10, p11) == DmtxFail);
         break;
      default:
         return DmtxFail;
   }

   /* Populate old-style region */
   reg.flowBegin.plane = 0; /* or 1, or 2 (0 = red, 1 = green, etc...) */
   reg.onColor = onColor;
   reg.offColor = offColor;
   reg.sizeIdx = region->sizeIdx;
   reg.symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, region->sizeIdx);
   reg.symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, region->sizeIdx);
   reg.mappingRows = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixRows, region->sizeIdx);
   reg.mappingCols = dmtxGetSymbolAttribute(DmtxSymAttribMappingMatrixCols, region->sizeIdx);

   msg = dmtxDecodeMatrixRegion(dec, &reg, DmtxUndefined);
   if(msg == NULL)
      return DmtxFail;

   fprintf(stdout, "%d: ", prefix);
   prefix = (prefix == 9) ? 0 : prefix + 1;
   fwrite(msg->output, sizeof(char), msg->outputIdx, stdout);
   fputc('\n', stdout);
   fflush(stdout);

   return DmtxPass;
}

/**
 *
 *
 */
DmtxPassFail
GetOnOffColors(GridRegion *region, const DmtxDecode *dec, int *onColor, int *offColor)
{
   int colBeg, rowBeg;
   DmtxDirection d0, d1;
   ColorTally t0, t1;

   /* add assertion to guarantee 2 adjancent timing bars */

   /* Start tally at intersection of timing bars */
   colBeg = (region->finderSides & DmtxDirLeft) ? region->x + region->width - 1 : region->x;
   rowBeg = (region->finderSides & DmtxDirDown) ? region->y + region->height - 1 : region->y;

   switch(region->finderSides) {
      case (DmtxDirLeft | DmtxDirDown):
         d0 = DmtxDirLeft;
         d1 = DmtxDirDown;
         break;
      case (DmtxDirDown | DmtxDirRight):
         d0 = DmtxDirDown;
         d1 = DmtxDirRight;
         break;
      case (DmtxDirRight | DmtxDirUp):
         d0 = DmtxDirRight;
         d1 = DmtxDirUp;
         break;
      case (DmtxDirUp | DmtxDirLeft):
         d0 = DmtxDirUp;
         d1 = DmtxDirLeft;
         break;
      default:
         return DmtxFail;
   }

   t0 = GetTimingColors(region, dec, colBeg, rowBeg, d0);
   t1 = GetTimingColors(region, dec, colBeg, rowBeg, d1);

   if(t0.evnCount + t1.evnCount == 0 || t0.oddCount + t1.oddCount == 0)
      return DmtxFail;

   *onColor = (t0.oddColor + t1.oddColor)/(t0.oddCount + t1.oddCount);
   *offColor = (t0.evnColor + t1.evnColor)/(t0.evnCount + t1.evnCount);

   return DmtxPass;
}

/**
 *
 *
 */
ColorTally
GetTimingColors(GridRegion *region, const DmtxDecode *dec, int colBeg, int rowBeg,
      DmtxDirection dir)
{
   int i, row, col, extent;
   int sample;
   ColorTally colors;

   colors.evnColor = 0;
   colors.evnCount = 0;

   colors.oddColor = 0;
   colors.oddCount = 0;

   /* Note opposite meaning (DmtxDirUp means "top", extent is horizontal) */
   extent = (dir & DmtxDirVertical) ? region->width : region->height;

   col = colBeg;
   row = rowBeg;
   for(i = 0; i < extent; i++) {
      sample = dmtxReadModuleColor(dec->image, &(region->grid), row, col, 0);

      if(i & 0x01) {
         colors.oddColor += sample;
         colors.oddCount++;
      }
      else {
         colors.evnColor += sample;
         colors.evnCount++;
      }

      switch(dir) {
         case DmtxDirUp:
            row++;
            break;
         case DmtxDirLeft:
            col--;
            break;
         case DmtxDirDown:
            row--;
            break;
         case DmtxDirRight:
            col++;
            break;
         default:
            return colors; /* XXX should be an error condition */
      }
   }

    /* consider having PerimeterEdgeTest() call this function when ready? */

   return colors;
}
Added jni/libdmtx/test/multi_test/dmtxsobel.c.


























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxsobel.c
 */

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <assert.h>
#include "../../dmtx.h"
#include "multi_test.h"

/**
 *
 *
 */
DmtxSobel *
SobelCreate(DmtxImage *img)
{
   int sWidth, sHeight;
   DmtxSobel *sobel;

   sobel = (DmtxSobel *)calloc(1, sizeof(DmtxSobel));
   if(sobel == NULL)
      return NULL;

   sWidth = dmtxImageGetProp(img, DmtxPropWidth) - 2;
   sHeight = dmtxImageGetProp(img, DmtxPropHeight) - 2;

   sobel->v = dmtxValueGridCreate(sWidth, sHeight, DmtxEdgeVertical, NULL);
   sobel->b = dmtxValueGridCreate(sWidth, sHeight, DmtxEdgeBackslash, NULL);
   sobel->h = dmtxValueGridCreate(sWidth, sHeight, DmtxEdgeHorizontal, NULL);
   sobel->s = dmtxValueGridCreate(sWidth, sHeight, DmtxEdgeSlash, NULL);

   if(sobel->v == NULL || sobel->b == NULL || sobel->h == NULL || sobel->s == NULL)
   {
      SobelDestroy(&sobel);
      return NULL;
   }

   return sobel;
}

/**
 *
 *
 */
DmtxPassFail
SobelDestroy(DmtxSobel **sobel)
{
   if(sobel == NULL || *sobel == NULL)
      return DmtxFail;

   dmtxValueGridDestroy(&((*sobel)->s));
   dmtxValueGridDestroy(&((*sobel)->h));
   dmtxValueGridDestroy(&((*sobel)->b));
   dmtxValueGridDestroy(&((*sobel)->v));

   free(*sobel);
   *sobel = NULL;

   return DmtxPass;
}

/**
 * 3x3 Sobel Kernel
 *
 */
DmtxPassFail
SobelPopulate(DmtxDecode2 *dec)
{
   int bytesPerPixel, rowSizeBytes, colorPlane;
   int sx, sy;
   int py, pOffset;
   int vMag, bMag, hMag, sMag;
   int colorLoLf, colorLoMd, colorLoRt;
   int colorMdRt, colorHiRt, colorHiMd;
   int colorHiLf, colorMdLf, colorMdMd;
   int idx;
   int sWidth, sHeight;
   DmtxSobel *sobel = dec->sobel;
   DmtxImage *img = dec->image;

   assert(dec != NULL);

   sobel = dec->sobel;
   img = dec->image;

   assert(sobel != NULL && img != NULL);

   sWidth = dmtxImageGetProp(img, DmtxPropWidth) - 2;
   sHeight = dmtxImageGetProp(img, DmtxPropHeight) - 2;

   rowSizeBytes = dmtxImageGetProp(img, DmtxPropRowSizeBytes);
   bytesPerPixel = dmtxImageGetProp(img, DmtxPropBytesPerPixel);
   colorPlane = 1; /* XXX need to make some decisions here */

   for(sy = 0; sy < sHeight; sy++)
   {
      py = sHeight - sy;

      pOffset = py * rowSizeBytes + colorPlane;
      colorHiLf = img->pxl[pOffset - rowSizeBytes];
      colorMdLf = img->pxl[pOffset];
      colorLoLf = img->pxl[pOffset + rowSizeBytes];

      pOffset += bytesPerPixel;
      colorHiMd = img->pxl[pOffset - rowSizeBytes];
      colorMdMd = img->pxl[pOffset];
      colorLoMd = img->pxl[pOffset + rowSizeBytes];

      pOffset += bytesPerPixel;
      colorHiRt = img->pxl[pOffset - rowSizeBytes];
      colorMdRt = img->pxl[pOffset];
      colorLoRt = img->pxl[pOffset + rowSizeBytes];

      for(sx = 0; sx < sWidth; sx++)
      {
         /**
          *  -1  0  1
          *  -2  0  2
          *  -1  0  1
          */
         vMag  = colorHiRt;
         vMag += colorMdRt * 2;
         vMag += colorLoRt;
         vMag -= colorHiLf;
         vMag -= colorMdLf * 2;
         vMag -= colorLoLf;

         /**
          *   0  1  2
          *  -1  0  1
          *  -2 -1  0
          */
         bMag  = colorMdLf;
         bMag += colorLoLf * 2;
         bMag += colorLoMd;
         bMag -= colorMdRt;
         bMag -= colorHiRt * 2;
         bMag -= colorHiMd;

         /**
          *   1  2  1
          *   0  0  0
          *  -1 -2 -1
          */
         hMag  = colorHiLf;
         hMag += colorHiMd * 2;
         hMag += colorHiRt;
         hMag -= colorLoLf;
         hMag -= colorLoMd * 2;
         hMag -= colorLoRt;

         /**
          *  -2 -1  0
          *  -1  0  1
          *   0  1  2
          */
         sMag  = colorLoMd;
         sMag += colorLoRt * 2;
         sMag += colorMdRt;
         sMag -= colorHiMd;
         sMag -= colorHiLf * 2;
         sMag -= colorMdLf;

         /**
          * If implementing these operations using MMX, can load 2
          * registers with 4 doubleword values and subtract (PSUBD).
          */

         idx = sy * sWidth + sx;
         sobel->v->value[idx] = vMag;
         sobel->b->value[idx] = bMag;
         sobel->h->value[idx] = hMag;
         sobel->s->value[idx] = sMag;

         colorHiLf = colorHiMd;
         colorMdLf = colorMdMd;
         colorLoLf = colorLoMd;

         colorHiMd = colorHiRt;
         colorMdMd = colorMdRt;
         colorLoMd = colorLoRt;

         pOffset += bytesPerPixel;
         colorHiRt = img->pxl[pOffset - rowSizeBytes];
         colorMdRt = img->pxl[pOffset];
         colorLoRt = img->pxl[pOffset + rowSizeBytes];
      }
   }

   dec->fn.dmtxValueGridCallback(sobel->v, 0);
   dec->fn.dmtxValueGridCallback(sobel->b, 1);
   dec->fn.dmtxValueGridCallback(sobel->h, 2);
   dec->fn.dmtxValueGridCallback(sobel->s, 3);

   return DmtxPass;
}
Added jni/libdmtx/test/multi_test/dmtxvaluegrid.c.




























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file dmtxvaluegrid.c
 */

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <assert.h>
#include "../../dmtx.h"
#include "multi_test.h"

/**
 *
 *
 */
DmtxValueGrid *
dmtxValueGridCreate(int width, int height, int type, DmtxValueGrid *ref)
{
   DmtxValueGrid *valueGrid;

   valueGrid = (DmtxValueGrid *)calloc(1, sizeof(DmtxValueGrid));
   if(valueGrid == NULL)
      return NULL;

   valueGrid->width = width;
   valueGrid->height = height;
   valueGrid->type = type;
   valueGrid->ref = ref;

   valueGrid->value = (int *)malloc(width * height * sizeof(int));
   if(valueGrid->value == NULL)
   {
      dmtxValueGridDestroy(&valueGrid);
      return NULL;
   }

   return valueGrid;
}

/**
 *
 *
 */
DmtxPassFail
dmtxValueGridDestroy(DmtxValueGrid **valueGrid)
{
   if(valueGrid == NULL || *valueGrid == NULL)
      return DmtxFail;

   if((*valueGrid)->value != NULL)
      free((*valueGrid)->value);

   free(*valueGrid);
   *valueGrid = NULL;

   return DmtxPass;
}

/**
 *
 *
 */
int
dmtxValueGridGetWidth(DmtxValueGrid *valueGrid)
{
   if(valueGrid == NULL)
      return DmtxUndefined;

   return valueGrid->width;
}

/**
 *
 *
 */
int
dmtxValueGridGetHeight(DmtxValueGrid *valueGrid)
{
   if(valueGrid == NULL)
      return DmtxUndefined;

   return valueGrid->height;
}

/**
 *
 *
 */
int
dmtxValueGridGetValue(DmtxValueGrid *valueGrid, int x, int y)
{
   int idx;

   if(valueGrid == NULL)
      return DmtxUndefined;

   if(x < 0 || x >= valueGrid->width || y < 0 || y >= valueGrid->height)
      return 0;

   idx = y * valueGrid->width + x;

   return valueGrid->value[idx];
}
Added jni/libdmtx/test/multi_test/kiss_fft.c.












































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
/*
Copyright (c) 2003-2010, Mark Borgerding

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


#include "_kiss_fft_guts.h"
/* The guts header contains all the multiplication and addition macros that are defined for
 fixed or floating point complex numbers.  It also delares the kf_ internal functions.
 */

static void kf_bfly2(
        kiss_fft_cpx * Fout,
        const size_t fstride,
        const kiss_fft_cfg st,
        int m
        )
{
    kiss_fft_cpx * Fout2;
    kiss_fft_cpx * tw1 = st->twiddles;
    kiss_fft_cpx t;
    Fout2 = Fout + m;
    do{
        C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2);

        C_MUL (t,  *Fout2 , *tw1);
        tw1 += fstride;
        C_SUB( *Fout2 ,  *Fout , t );
        C_ADDTO( *Fout ,  t );
        ++Fout2;
        ++Fout;
    }while (--m);
}

static void kf_bfly4(
        kiss_fft_cpx * Fout,
        const size_t fstride,
        const kiss_fft_cfg st,
        const size_t m
        )
{
    kiss_fft_cpx *tw1,*tw2,*tw3;
    kiss_fft_cpx scratch[6];
    size_t k=m;
    const size_t m2=2*m;
    const size_t m3=3*m;


    tw3 = tw2 = tw1 = st->twiddles;

    do {
        C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4);

        C_MUL(scratch[0],Fout[m] , *tw1 );
        C_MUL(scratch[1],Fout[m2] , *tw2 );
        C_MUL(scratch[2],Fout[m3] , *tw3 );

        C_SUB( scratch[5] , *Fout, scratch[1] );
        C_ADDTO(*Fout, scratch[1]);
        C_ADD( scratch[3] , scratch[0] , scratch[2] );
        C_SUB( scratch[4] , scratch[0] , scratch[2] );
        C_SUB( Fout[m2], *Fout, scratch[3] );
        tw1 += fstride;
        tw2 += fstride*2;
        tw3 += fstride*3;
        C_ADDTO( *Fout , scratch[3] );

        if(st->inverse) {
            Fout[m].r = scratch[5].r - scratch[4].i;
            Fout[m].i = scratch[5].i + scratch[4].r;
            Fout[m3].r = scratch[5].r + scratch[4].i;
            Fout[m3].i = scratch[5].i - scratch[4].r;
        }else{
            Fout[m].r = scratch[5].r + scratch[4].i;
            Fout[m].i = scratch[5].i - scratch[4].r;
            Fout[m3].r = scratch[5].r - scratch[4].i;
            Fout[m3].i = scratch[5].i + scratch[4].r;
        }
        ++Fout;
    }while(--k);
}

static void kf_bfly3(
         kiss_fft_cpx * Fout,
         const size_t fstride,
         const kiss_fft_cfg st,
         size_t m
         )
{
     size_t k=m;
     const size_t m2 = 2*m;
     kiss_fft_cpx *tw1,*tw2;
     kiss_fft_cpx scratch[5];
     kiss_fft_cpx epi3;
     epi3 = st->twiddles[fstride*m];

     tw1=tw2=st->twiddles;

     do{
         C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);

         C_MUL(scratch[1],Fout[m] , *tw1);
         C_MUL(scratch[2],Fout[m2] , *tw2);

         C_ADD(scratch[3],scratch[1],scratch[2]);
         C_SUB(scratch[0],scratch[1],scratch[2]);
         tw1 += fstride;
         tw2 += fstride*2;

         Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
         Fout[m].i = Fout->i - HALF_OF(scratch[3].i);

         C_MULBYSCALAR( scratch[0] , epi3.i );

         C_ADDTO(*Fout,scratch[3]);

         Fout[m2].r = Fout[m].r + scratch[0].i;
         Fout[m2].i = Fout[m].i - scratch[0].r;

         Fout[m].r -= scratch[0].i;
         Fout[m].i += scratch[0].r;

         ++Fout;
     }while(--k);
}

static void kf_bfly5(
        kiss_fft_cpx * Fout,
        const size_t fstride,
        const kiss_fft_cfg st,
        int m
        )
{
    kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
    int u;
    kiss_fft_cpx scratch[13];
    kiss_fft_cpx * twiddles = st->twiddles;
    kiss_fft_cpx *tw;
    kiss_fft_cpx ya,yb;
    ya = twiddles[fstride*m];
    yb = twiddles[fstride*2*m];

    Fout0=Fout;
    Fout1=Fout0+m;
    Fout2=Fout0+2*m;
    Fout3=Fout0+3*m;
    Fout4=Fout0+4*m;

    tw=st->twiddles;
    for ( u=0; u<m; ++u ) {
        C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
        scratch[0] = *Fout0;

        C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
        C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
        C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
        C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);

        C_ADD( scratch[7],scratch[1],scratch[4]);
        C_SUB( scratch[10],scratch[1],scratch[4]);
        C_ADD( scratch[8],scratch[2],scratch[3]);
        C_SUB( scratch[9],scratch[2],scratch[3]);

        Fout0->r += scratch[7].r + scratch[8].r;
        Fout0->i += scratch[7].i + scratch[8].i;

        scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
        scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);

        scratch[6].r =  S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
        scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);

        C_SUB(*Fout1,scratch[5],scratch[6]);
        C_ADD(*Fout4,scratch[5],scratch[6]);

        scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
        scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
        scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
        scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);

        C_ADD(*Fout2,scratch[11],scratch[12]);
        C_SUB(*Fout3,scratch[11],scratch[12]);

        ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
    }
}

/* perform the butterfly for one stage of a mixed radix FFT */
static void kf_bfly_generic(
        kiss_fft_cpx * Fout,
        const size_t fstride,
        const kiss_fft_cfg st,
        int m,
        int p
        )
{
    int u,k,q1,q;
    kiss_fft_cpx * twiddles = st->twiddles;
    kiss_fft_cpx t;
    int Norig = st->nfft;

    kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p);

    for ( u=0; u<m; ++u ) {
        k=u;
        for ( q1=0 ; q1<p ; ++q1 ) {
            scratch[q1] = Fout[ k  ];
            C_FIXDIV(scratch[q1],p);
            k += m;
        }

        k=u;
        for ( q1=0 ; q1<p ; ++q1 ) {
            int twidx=0;
            Fout[ k ] = scratch[0];
            for (q=1;q<p;++q ) {
                twidx += fstride * k;
                if (twidx>=Norig) twidx-=Norig;
                C_MUL(t,scratch[q] , twiddles[twidx] );
                C_ADDTO( Fout[ k ] ,t);
            }
            k += m;
        }
    }
    KISS_FFT_TMP_FREE(scratch);
}

static
void kf_work(
        kiss_fft_cpx * Fout,
        const kiss_fft_cpx * f,
        const size_t fstride,
        int in_stride,
        int * factors,
        const kiss_fft_cfg st
        )
{
    kiss_fft_cpx * Fout_beg=Fout;
    const int p=*factors++; /* the radix  */
    const int m=*factors++; /* stage's fft length/p */
    const kiss_fft_cpx * Fout_end = Fout + p*m;

#ifdef _OPENMP
/*
    // use openmp extensions at the
    // top-level (not recursive)
*/
    if (fstride==1 && p<=5)
    {
        int k;

/*
        // execute the p different work units in different threads
*/
#       pragma omp parallel for
        for (k=0;k<p;++k)
            kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st);
/*
        // all threads have joined by this point
*/

        switch (p) {
            case 2: kf_bfly2(Fout,fstride,st,m); break;
            case 3: kf_bfly3(Fout,fstride,st,m); break;
            case 4: kf_bfly4(Fout,fstride,st,m); break;
            case 5: kf_bfly5(Fout,fstride,st,m); break;
            default: kf_bfly_generic(Fout,fstride,st,m,p); break;
        }
        return;
    }
#endif

    if (m==1) {
        do{
            *Fout = *f;
            f += fstride*in_stride;
        }while(++Fout != Fout_end );
    }else{
        do{
/*
            // recursive call:
            // DFT of size m*p performed by doing
            // p instances of smaller DFTs of size m,
            // each one takes a decimated version of the input
*/
            kf_work( Fout , f, fstride*p, in_stride, factors,st);
            f += fstride*in_stride;
        }while( (Fout += m) != Fout_end );
    }

    Fout=Fout_beg;

/*
    // recombine the p smaller DFTs
*/
    switch (p) {
        case 2: kf_bfly2(Fout,fstride,st,m); break;
        case 3: kf_bfly3(Fout,fstride,st,m); break;
        case 4: kf_bfly4(Fout,fstride,st,m); break;
        case 5: kf_bfly5(Fout,fstride,st,m); break;
        default: kf_bfly_generic(Fout,fstride,st,m,p); break;
    }
}

/*  facbuf is populated by p1,m1,p2,m2, ...
    where
    p[i] * m[i] = m[i-1]
    m0 = n                  */
static
void kf_factor(int n,int * facbuf)
{
    int p=4;
    double floor_sqrt;
    floor_sqrt = floor( sqrt((double)n) );

    /*factor out powers of 4, powers of 2, then any remaining primes */
    do {
        while (n % p) {
            switch (p) {
                case 4: p = 2; break;
                case 2: p = 3; break;
                default: p += 2; break;
            }
            if (p > floor_sqrt)
                p = n;          /* no more factors, skip to end */
        }
        n /= p;
        *facbuf++ = p;
        *facbuf++ = n;
    } while (n > 1);
}

/*
 *
 * User-callable function to allocate all necessary storage space for the fft.
 *
 * The return value is a contiguous block of memory, allocated with malloc.  As such,
 * It can be freed with free(), rather than a kiss_fft-specific function.
 * */
kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
{
    kiss_fft_cfg st=NULL;
    size_t memneeded = sizeof(struct kiss_fft_state)
        + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/

    if ( lenmem==NULL ) {
        st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
    }else{
        if (mem != NULL && *lenmem >= memneeded)
            st = (kiss_fft_cfg)mem;
        *lenmem = memneeded;
    }
    if (st) {
        int i;
        st->nfft=nfft;
        st->inverse = inverse_fft;

        for (i=0;i<nfft;++i) {
            const double pi=3.141592653589793238462643383279502884197169399375105820974944;
            double phase = -2*pi*i / nfft;
            if (st->inverse)
                phase *= -1;
            kf_cexp(st->twiddles+i, phase );
        }

        kf_factor(nfft,st->factors);
    }
    return st;
}


void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
{
    if (fin == fout) {
/*
        //NOTE: this is not really an in-place FFT algorithm.
        //It just performs an out-of-place FFT into a temp buffer
*/
        kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft);
        kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
        memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
        KISS_FFT_TMP_FREE(tmpbuf);
    }else{
        kf_work( fout, fin, 1,in_stride, st->factors,st );
    }
}

void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
{
    kiss_fft_stride(cfg,fin,fout,1);
}


void kiss_fft_cleanup(void)
{
/*
    // nothing needed any more
*/
}

int kiss_fft_next_fast_size(int n)
{
    while(1) {
        int m=n;
        while ( (m%2) == 0 ) m/=2;
        while ( (m%3) == 0 ) m/=3;
        while ( (m%5) == 0 ) m/=5;
        if (m<=1)
            break; /* n is completely factorable by twos, threes, and fives */
        n++;
    }
    return n;
}
Added jni/libdmtx/test/multi_test/kiss_fft.h.


























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#ifndef KISS_FFT_H
#define KISS_FFT_H

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <malloc.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 ATTENTION!
 If you would like a :
 -- a utility that will handle the caching of fft objects
 -- real-only (no imaginary time component ) FFT
 -- a multi-dimensional FFT
 -- a command-line utility to perform ffts
 -- a command-line utility to perform fast-convolution filtering

 Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
  in the tools/ directory.
*/

#ifdef USE_SIMD
# include <xmmintrin.h>
# define kiss_fft_scalar __m128
#define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16)
#define KISS_FFT_FREE _mm_free
#else
#define KISS_FFT_MALLOC malloc
#define KISS_FFT_FREE free
#endif


#ifdef FIXED_POINT
#include <sys/types.h>
# if (FIXED_POINT == 32)
#  define kiss_fft_scalar int32_t
# else
#  define kiss_fft_scalar int16_t
# endif
#else
# ifndef kiss_fft_scalar
/*  default is float */
#   define kiss_fft_scalar float
# endif
#endif

typedef struct {
    kiss_fft_scalar r;
    kiss_fft_scalar i;
}kiss_fft_cpx;

typedef struct kiss_fft_state* kiss_fft_cfg;

/*
 *  kiss_fft_alloc
 *
 *  Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
 *
 *  typical usage:      kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
 *
 *  The return value from fft_alloc is a cfg buffer used internally
 *  by the fft routine or NULL.
 *
 *  If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
 *  The returned value should be free()d when done to avoid memory leaks.
 *
 *  The state can be placed in a user supplied buffer 'mem':
 *  If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
 *      then the function places the cfg in mem and the size used in *lenmem
 *      and returns mem.
 *
 *  If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
 *      then the function returns NULL and places the minimum cfg
 *      buffer size in *lenmem.
 * */

kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);

/*
 * kiss_fft(cfg,in_out_buf)
 *
 * Perform an FFT on a complex input buffer.
 * for a forward FFT,
 * fin should be  f[0] , f[1] , ... ,f[nfft-1]
 * fout will be   F[0] , F[1] , ... ,F[nfft-1]
 * Note that each element is complex and can be accessed like
    f[k].r and f[k].i
 * */
void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);

/*
 A more generic version of the above function. It reads its input from every Nth sample.
 * */
void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);

/* If kiss_fft_alloc allocated a buffer, it is one contiguous
   buffer and can be simply free()d when no longer needed*/
#define kiss_fft_free free

/*
 Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
 your compiler output to call this before you exit.
*/
void kiss_fft_cleanup(void);


/*
 * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
 */
int kiss_fft_next_fast_size(int n);

/* for real ffts, we need an even size */
#define kiss_fftr_next_fast_size_real(n) \
        (kiss_fft_next_fast_size( ((n)+1)>>1)<<1)

#ifdef __cplusplus
}
#endif

#endif
Added jni/libdmtx/test/multi_test/kiss_fftr.c.






























































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
Copyright (c) 2003-2004, Mark Borgerding

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "kiss_fftr.h"
#include "_kiss_fft_guts.h"

struct kiss_fftr_state{
    kiss_fft_cfg substate;
    kiss_fft_cpx * tmpbuf;
    kiss_fft_cpx * super_twiddles;
#ifdef USE_SIMD
    void * pad;
#endif
};

kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
{
    int i;
    kiss_fftr_cfg st = NULL;
    size_t subsize, memneeded;

    if (nfft & 1) {
        fprintf(stderr,"Real FFT optimization must be even.\n");
        return NULL;
    }
    nfft >>= 1;

    kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
    memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2);

    if (lenmem == NULL) {
        st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
    } else {
        if (*lenmem >= memneeded)
            st = (kiss_fftr_cfg) mem;
        *lenmem = memneeded;
    }
    if (!st)
        return NULL;

    st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
    st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
    st->super_twiddles = st->tmpbuf + nfft;
    kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);

    for (i = 0; i < nfft/2; ++i) {
        double phase =
            -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5);
        if (inverse_fft)
            phase *= -1;
        kf_cexp (st->super_twiddles+i,phase);
    }
    return st;
}

void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
{
    /* input buffer timedata is stored row-wise */
    int k,ncfft;
    kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;

    if ( st->substate->inverse) {
        fprintf(stderr,"kiss fft usage error: improper alloc\n");
        exit(1);
    }

    ncfft = st->substate->nfft;

    /*perform the parallel fft of two real signals packed in real,imag*/
    kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
    /* The real part of the DC element of the frequency spectrum in st->tmpbuf
     * contains the sum of the even-numbered elements of the input time sequence
     * The imag part is the sum of the odd-numbered elements
     *
     * The sum of tdc.r and tdc.i is the sum of the input time sequence.
     *      yielding DC of input time sequence
     * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
     *      yielding Nyquist bin of input time sequence
     */

    tdc.r = st->tmpbuf[0].r;
    tdc.i = st->tmpbuf[0].i;
    C_FIXDIV(tdc,2);
    CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
    CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
    freqdata[0].r = tdc.r + tdc.i;
    freqdata[ncfft].r = tdc.r - tdc.i;
#ifdef USE_SIMD
    freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
#else
    freqdata[ncfft].i = freqdata[0].i = 0;
#endif

    for ( k=1;k <= ncfft/2 ; ++k ) {
        fpk    = st->tmpbuf[k];
        fpnk.r =   st->tmpbuf[ncfft-k].r;
        fpnk.i = - st->tmpbuf[ncfft-k].i;
        C_FIXDIV(fpk,2);
        C_FIXDIV(fpnk,2);

        C_ADD( f1k, fpk , fpnk );
        C_SUB( f2k, fpk , fpnk );
        C_MUL( tw , f2k , st->super_twiddles[k-1]);

        freqdata[k].r = HALF_OF(f1k.r + tw.r);
        freqdata[k].i = HALF_OF(f1k.i + tw.i);
        freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
        freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
    }
}

void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
{
    /* input buffer timedata is stored row-wise */
    int k, ncfft;

    if (st->substate->inverse == 0) {
        fprintf (stderr, "kiss fft usage error: improper alloc\n");
        exit (1);
    }

    ncfft = st->substate->nfft;

    st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
    st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
    C_FIXDIV(st->tmpbuf[0],2);

    for (k = 1; k <= ncfft / 2; ++k) {
        kiss_fft_cpx fk, fnkc, fek, fok, tmp;
        fk = freqdata[k];
        fnkc.r = freqdata[ncfft - k].r;
        fnkc.i = -freqdata[ncfft - k].i;
        C_FIXDIV( fk , 2 );
        C_FIXDIV( fnkc , 2 );

        C_ADD (fek, fk, fnkc);
        C_SUB (tmp, fk, fnkc);
        C_MUL (fok, tmp, st->super_twiddles[k-1]);
        C_ADD (st->tmpbuf[k],     fek, fok);
        C_SUB (st->tmpbuf[ncfft - k], fek, fok);
#ifdef USE_SIMD
        st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
#else
        st->tmpbuf[ncfft - k].i *= -1;
#endif
    }
    kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
}
Added jni/libdmtx/test/multi_test/kiss_fftr.h.




























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#ifndef KISS_FTR_H
#define KISS_FTR_H

#include "kiss_fft.h"
#ifdef __cplusplus
extern "C" {
#endif


/*

 Real optimized version can save about 45% cpu time vs. complex fft of a real seq.



 */

typedef struct kiss_fftr_state *kiss_fftr_cfg;


kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
/*
 nfft must be even

 If you don't care to allocate space, use mem = lenmem = NULL
*/


void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
/*
 input timedata has nfft scalar points
 output freqdata has nfft/2+1 complex points
*/

void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
/*
 input freqdata has  nfft/2+1 complex points
 output timedata has nfft scalar points
*/

#define kiss_fftr_free free

#ifdef __cplusplus
}
#endif
#endif
Added jni/libdmtx/test/multi_test/multi_test.c.






































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file multi_test.c
 */

/**
 * This "multi_test" program is for experimental algorithms. Please
 * consider this code to be untested, unoptimized, and even unstable.
 * If something works here it will make its way into libdmtx "proper"
 * only after being properly written, tuned, and tested.
 */

/**
 * PLAN
 *   x [ done ] Tapered bucket calculation (4 wks)
 *   / [12-Jan] Build orientation from new vanish point info (2 wks)
 *   o [19-Jan] FFT for grid alignment (1 wk)
 *   o [26-Jan] Save scan progress between calls (1 wk)
 *   o [02-Feb] Outward stepping (1 wk)
 *   o [16-Feb] All grid locations (not just one) (2 wks)
 *   o [02-Mar] Region spanning hough alignment (2 wks)
 *   o [16-Mar] Multiscale hough (2 wks)
 *   o [30-Mar] Integrate w/ libdmtx proper as experimental option (2 wks)
 *   o [06-Apr] Release 0.7.4 (1 wk)
 *   o [ next ] Bug fixes and site changes
 *
 * TODO
 *   x Eliminate maxima candidates based on all 8 neighbors
 *   x Populate maxima weight as sum of center and all 8 neighbors (?)
 *   x Add interpolation to skipped d values on steep vanish points
 *   x Tweak shaped bucket weighting to not overcount parallel condition
 *   x Display local maxima
 *   x Create better method of isolating true maxima
 *   o Create mechanism to save scan progress between calls
 *   o Work on nonlinearity of hough points presented by dot peen symbols
 */

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "../../dmtx.h"
#include "multi_test.h"

AppState gState;

int
main(int argc, char *argv[])
{
   UserOptions        opt;
   SDL_Event          event;
   SDL_Rect           imageLoc;
   Uint32             bgColorB;
   DmtxDecode        *dec;
   DmtxDecode2       *dec2;
   SDL_Rect           clipRect;

   if(HandleArgs(&opt, &argc, &argv) == DmtxFail) {
      exit(1);
   }

   gState = InitAppState();

   /* Load image */
   gState.picture = IMG_Load(opt.imagePath);
   if(gState.picture == NULL) {
      fprintf(stderr, "Unable to load image \"%s\": %s\n", opt.imagePath, SDL_GetError());
      exit(1);
   }

   atexit(SDL_Quit);

   /* Initialize SDL library */
   if(SDL_Init(SDL_INIT_VIDEO) < 0) {
      fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError());
      exit(2);
   }

   gState.screen = SetWindowSize(gState.windowWidth, gState.windowHeight);

   NudgeImage(CTRL_COL1_X, gState.picture->w, &(gState.imageLocX));
   NudgeImage(gState.windowHeight, gState.picture->h, &(gState.imageLocY));

   bgColorB = SDL_MapRGBA(gState.screen->format, 100, 100, 100, 255);

   /* Create surface to hold image pixels to be scanned */
   gState.local = SDL_CreateRGBSurface(SDL_SWSURFACE, LOCAL_SIZE, LOCAL_SIZE, 32, 0, 0, 0, 0);
   gState.imgActive = dmtxImageCreate(gState.local->pixels, gState.local->w, gState.local->h, DmtxPack32bppXRGB);
   assert(gState.imgActive != NULL);

   /* Create another surface for scaling purposes */
   gState.localTmp = SDL_CreateRGBSurface(SDL_SWSURFACE, LOCAL_SIZE, LOCAL_SIZE, 32, 0, 0, 0, 0);

   gState.imgFull = CreateDmtxImage(gState.picture);
   assert(gState.imgFull != NULL);

   gState.dmtxImage = CreateDmtxImage(gState.picture);
   assert(gState.dmtxImage != NULL);

   dec = dmtxDecodeCreate(gState.imgFull, 1);
   assert(dec != NULL);

   dec2 = dmtxDecode2Create();
   assert(dec2 != NULL);

/* dmtxDecode2SetScale(dec2); */

   /* Set up callback functions */
   dec2->fn.dmtxValueGridCallback = ValueGridCallback;
   dec2->fn.zeroCrossingCallback = ZeroCrossingCallback;
   dec2->fn.dmtxHoughLocalCallback = HoughLocalCallback;
   dec2->fn.vanishPointCallback = VanishPointCallback;
   dec2->fn.timingCallback = TimingCallback;
   dec2->fn.gridCallback = GridCallback;
   dec2->fn.perimeterCallback = PerimeterCallback;

   for(;;) {
      SDL_Delay(10);

      while(SDL_PollEvent(&event))
         HandleEvent(&event, &gState, gState.picture, &gState.screen);

      if(gState.quit == DmtxTrue)
         break;

      imageLoc.x = gState.imageLocX;
      imageLoc.y = gState.imageLocY;

      captureLocalPortion(gState.local, gState.localTmp, gState.picture, gState.screen, &gState, imageLoc);

      /* Start with blank canvas */
      SDL_FillRect(gState.screen, NULL, bgColorB);

      /* Draw image to main canvas area */
      clipRect.w = CTRL_COL1_X - 1;
      clipRect.h = gState.windowHeight;
      clipRect.x = 0;
      clipRect.y = 0;
      SDL_SetClipRect(gState.screen, &clipRect);
      SDL_BlitSurface(gState.picture, NULL, gState.screen, &imageLoc);
      SDL_SetClipRect(gState.screen, NULL);

      DrawActiveBorder(gState.screen, gState.activeExtent);

      ShowActiveRegion(gState.screen, gState.local);

      SDL_LockSurface(gState.local);
      if(dmtxDecode2SetImage(dec2, gState.dmtxImage) == DmtxFail)
         break;

      dmtxRegion2FindNext(dec2);
      SDL_UnlockSurface(gState.local);

      /* Dump FFT results */
      if(gState.printValues == DmtxTrue)
         gState.printValues = DmtxFalse;

      SDL_Flip(gState.screen);
   }

   SDL_FreeSurface(gState.localTmp);
   SDL_FreeSurface(gState.local);

   dmtxDecode2Destroy(&dec2);
   dmtxDecodeDestroy(&dec);
   dmtxImageDestroy(&gState.dmtxImage);
   dmtxImageDestroy(&gState.imgFull);
   dmtxImageDestroy(&gState.imgActive);

   exit(0);
}

/**
 *
 *
 */
DmtxPassFail
HandleArgs(UserOptions *opt, int *argcp, char **argvp[])
{
   memset(opt, 0x00, sizeof(UserOptions));

   if(*argcp < 2) {
      fprintf(stdout, "Argument required\n");
      return DmtxFail;
   }
   else {
      opt->imagePath = (*argvp)[1];
   }

   return DmtxPass;
}

/**
 *
 *
 */
AppState
InitAppState(void)
{
   AppState state;

   memset(&state, 0x00, sizeof(AppState));

   state.picture = NULL;
   state.windowWidth = 640;
   state.windowHeight = 518;
   state.activeExtent = 64;
   state.imgActive = NULL;
   state.imgFull = NULL;
   state.autoNudge = DmtxFalse;
   state.displayEdge = 0;
   state.displayVanish = DmtxFalse;
   state.displayTiming = DmtxTrue;
   state.printValues = DmtxFalse;
   state.imageLocX = 0;
   state.imageLocY = 0;
   state.imageOffsetX = 0;
   state.imageOffsetY = 0;
   state.localOffsetX = 0;
   state.localOffsetY = 0;
   state.leftButton = SDL_RELEASED;
   state.rightButton = SDL_RELEASED;
   state.pointerX = 0;
   state.pointerY = 0;
   state.quit = DmtxFalse;
   state.screen = NULL;
   state.local = NULL;
   state.localTmp = NULL;

   return state;
}

/**
 *
 *
 */
DmtxImage *
CreateDmtxImage(SDL_Surface *sdlImage)
{
   DmtxPackOrder packOrder;
   DmtxImage *dmtxImage = NULL;

   switch(sdlImage->format->BytesPerPixel) {
      case 1:
         packOrder = DmtxPack8bppK;
         break;
      case 3:
         packOrder = DmtxPack24bppRGB;
         break;
      case 4:
         packOrder = DmtxPack32bppXRGB;
         break;
      default:
         return NULL;
   }

   dmtxImage = dmtxImageCreate(sdlImage->pixels, sdlImage->w, sdlImage->h, packOrder);
   if(dmtxImage == NULL)
      return NULL;

   if(sdlImage->format->BytesPerPixel > 1) {
      dmtxImageSetProp(dmtxImage, DmtxPropRowPadBytes, sdlImage->pitch -
            (sdlImage->w * sdlImage->format->BytesPerPixel));
   }

   return dmtxImage;
}

/**
 *
 *
 */
void AddFullTransforms(AlignmentGrid *grid)
{
   DmtxMatrix3 mTranslate, mScale, mTmp;

   if(gState.activeExtent == 64) {
      dmtxMatrix3Translate(mTranslate, gState.imageLocX - 288, 518 - (227 +
            gState.imageLocY + gState.picture->h));
      dmtxMatrix3Multiply(grid->raw2fitFull, mTranslate, grid->raw2fitActive); /* not tested */
   }
   else {
      dmtxMatrix3Scale(mScale, 2.0, 2.0);
      dmtxMatrix3Multiply(mTmp, mScale, grid->raw2fitActive);
      dmtxMatrix3Copy(grid->raw2fitActive, mTmp);

      dmtxMatrix3Translate(mTranslate, gState.imageLocX - 304, 518 - (243 +
            gState.imageLocY + gState.picture->h));
      dmtxMatrix3Multiply(grid->raw2fitFull, mTranslate, grid->raw2fitActive); /* not tested */
   }

   if(gState.activeExtent == 64) {
      dmtxMatrix3Translate(mTranslate, 288 - gState.imageLocX, 227 +
            gState.imageLocY + gState.picture->h - 518);
   }
   else {
      dmtxMatrix3Scale(mScale, 0.5, 0.5);
      dmtxMatrix3Multiply(mTmp, grid->fit2rawActive, mScale);
      dmtxMatrix3Copy(grid->fit2rawActive, mTmp);

      dmtxMatrix3Translate(mTranslate, 304 - gState.imageLocX, 243 +
            gState.imageLocY + gState.picture->h - 518);
   }
   dmtxMatrix3Multiply(grid->fit2rawFull, grid->fit2rawActive, mTranslate);
}

void
captureLocalPortion(SDL_Surface *local, SDL_Surface *localTmp,
      SDL_Surface *picture, SDL_Surface *screen, AppState *state, SDL_Rect imageLoc)
{
   int      i, j;
   Uint32   bgColorK;
   SDL_Rect clipRect;

   bgColorK = SDL_MapRGBA(screen->format, 0, 0, 0, 255);

   /* Capture portion of image that falls within highlighted region */
   /* Use blitsurface if 1:1, otherwise scale */
   SDL_FillRect(local, NULL, bgColorK);
   if(state->activeExtent == 64) {
      clipRect.x = state->localOffsetX;
      clipRect.y = picture->h - (state->localOffsetY + 64) - 1;
      clipRect.w = LOCAL_SIZE;
      clipRect.h = LOCAL_SIZE;
      SDL_BlitSurface(picture, &clipRect, local, NULL);
   }
   else if(state->activeExtent == 32) {
      Uint8 localBpp;
      Uint8 *writePixel, *readTL, *readTR, *readBL, *readBR;

      /* first blit, then expand */
      clipRect.x = (screen->w - state->activeExtent)/2 - imageLoc.x;
      clipRect.y = (screen->h - state->activeExtent)/2 - imageLoc.y;
      clipRect.w = LOCAL_SIZE;
      clipRect.h = LOCAL_SIZE;
      SDL_BlitSurface(picture, &clipRect, localTmp, NULL);

      localBpp = local->format->BytesPerPixel;
      SDL_LockSurface(local);
      SDL_LockSurface(localTmp);
      for(i = 0; i < 64; i++) {
         for(j = 0; j < 64; j++) {
            readTL = (Uint8 *)localTmp->pixels + ((i/2) * 64 + (j/2)) * localBpp;
            readTR = readTL + localBpp;
            readBL = readTL + (64 * localBpp);
            readBR = readBL + localBpp;
            writePixel = (Uint8 *)local->pixels + ((i * 64 + j) * localBpp);

            /* memcpy(writePixel, readTL, localBpp); nearest neighbor */
            if(!(i & 0x01) && !(j & 0x01)) {
               memcpy(writePixel, readTL, localBpp);
            }
            else if((i & 0x01) && !(j & 0x01)) {
               writePixel[0] = ((Uint16)readTL[0] + (Uint16)readBL[0])/2;
               writePixel[1] = ((Uint16)readTL[1] + (Uint16)readBL[1])/2;
               writePixel[2] = ((Uint16)readTL[2] + (Uint16)readBL[2])/2;
               writePixel[3] = ((Uint16)readTL[3] + (Uint16)readBL[3])/2;
            }
            else if(!(i & 0x01) && (j & 0x01)) {
               writePixel[0] = ((Uint16)readTL[0] + (Uint16)readTR[0])/2;
               writePixel[1] = ((Uint16)readTL[1] + (Uint16)readTR[1])/2;
               writePixel[2] = ((Uint16)readTL[2] + (Uint16)readTR[2])/2;
               writePixel[3] = ((Uint16)readTL[3] + (Uint16)readTR[3])/2;
            }
            else {
               writePixel[0] = ((Uint16)readTL[0] + (Uint16)readTR[0] +
                     (Uint16)readBL[0] + (Uint16)readBR[0])/4;
               writePixel[1] = ((Uint16)readTL[1] + (Uint16)readTR[1] +
                     (Uint16)readBL[1] + (Uint16)readBR[1])/4;
               writePixel[2] = ((Uint16)readTL[2] + (Uint16)readTR[2] +
                     (Uint16)readBL[2] + (Uint16)readBR[2])/4;
               writePixel[3] = ((Uint16)readTL[3] + (Uint16)readTR[3] +
                     (Uint16)readBL[3] + (Uint16)readBR[3])/4;
            }
         }
      }
      SDL_UnlockSurface(localTmp);
      SDL_UnlockSurface(local);
   }
}

/**
 *
 *
 */
SDL_Surface *
SetWindowSize(int windowWidth, int windowHeight)
{
   SDL_Surface *screen;

   screen = SDL_SetVideoMode(windowWidth, windowHeight, 32,
         SDL_HWSURFACE | SDL_DOUBLEBUF); /* | SDL_RESIZABLE); */

   if(screen == NULL) {
      fprintf(stderr, "Couldn't set %dx%dx32 video mode: %s\n", windowWidth,
            windowHeight, SDL_GetError());
      exit(1);
   }

   return screen;
}

/**
 *
 *
 */
DmtxPassFail
HandleEvent(SDL_Event *event, AppState *state, SDL_Surface *picture, SDL_Surface **screen)
{
   int nudgeRequired = DmtxFalse;

   switch(event->type) {
      case SDL_KEYDOWN:
         switch(event->key.keysym.sym) {
            case SDLK_ESCAPE:
               state->quit = DmtxTrue;
               break;
            case SDLK_0:
               state->displayEdge = 0;
               break;
            case SDLK_1:
               state->displayEdge = 1;
               break;
            case SDLK_2:
               state->displayEdge = 2;
               break;
            case SDLK_3:
               state->displayEdge = 3;
               break;
            case SDLK_4:
               state->displayEdge = 4;
               break;
            case SDLK_5:
               state->displayEdge = 5;
               break;
            case SDLK_6:
               state->displayEdge = 6;
               break;
            case SDLK_l:
               fprintf(stdout, "Image Location: (%d, %d)\n", state->imageLocX,  state->imageLocY);
               break;
            case SDLK_n:
               state->autoNudge = (state->autoNudge == DmtxTrue) ? DmtxFalse : DmtxTrue;
               fprintf(stdout, "autoNudge %s\n", (state->autoNudge == DmtxTrue) ? "ON" : "OFF");
               break;
            case SDLK_p:
               state->printValues = (state->printValues == DmtxTrue) ? DmtxFalse : DmtxTrue;
               break;
            case SDLK_t:
               state->displayTiming = (state->displayTiming == DmtxTrue) ? DmtxFalse : DmtxTrue;
               break;
            case SDLK_v:
               state->displayVanish = (state->displayVanish == DmtxTrue) ? DmtxFalse : DmtxTrue;
               break;
            case SDLK_UP:
               state->imageLocY--;
               nudgeRequired = DmtxTrue;
               break;
            case SDLK_DOWN:
               state->imageLocY++;
               nudgeRequired = DmtxTrue;
               break;
            case SDLK_RIGHT:
               state->imageLocX++;
               nudgeRequired = DmtxTrue;
               break;
            case SDLK_LEFT:
               state->imageLocX--;
               nudgeRequired = DmtxTrue;
               break;
            default:
               break;
         }
         break;

      case SDL_MOUSEBUTTONDOWN:
         switch(event->button.button) {
            case SDL_BUTTON_LEFT:
               state->leftButton = event->button.state;
               break;
            case SDL_BUTTON_RIGHT:
               state->rightButton = event->button.state;
               break;
            case SDL_BUTTON_WHEELDOWN:
               if(state->activeExtent > 32)
                  state->activeExtent /= 2;
               break;
            case SDL_BUTTON_WHEELUP:
               if(state->activeExtent < 64)
                  state->activeExtent *= 2;
               break;
         }
         break;

      case SDL_MOUSEBUTTONUP:
         switch(event->button.button) {
            case SDL_BUTTON_LEFT:
               state->leftButton = event->button.state;
               break;
            case SDL_BUTTON_RIGHT:
               state->rightButton = event->button.state;
               break;
         }
         break;

      case SDL_MOUSEMOTION:
         state->pointerX = event->motion.x;
         state->pointerY = event->motion.y;

         if(state->leftButton == SDL_PRESSED) {
            state->imageLocX += event->motion.xrel;
            state->imageLocY += event->motion.yrel;
            nudgeRequired = DmtxTrue;
         }
         break;

      case SDL_QUIT:
         state->quit = DmtxTrue;
         break;

      case SDL_VIDEORESIZE:
         state->windowWidth = event->resize.w;
         state->windowHeight = event->resize.h;
         *screen = SetWindowSize(state->windowWidth, state->windowHeight);
         nudgeRequired = DmtxTrue;
         break;

      default:
         break;
   }

   if(nudgeRequired == DmtxTrue) {
      NudgeImage(CTRL_COL1_X, picture->w, &(state->imageLocX));
      NudgeImage(state->windowHeight, picture->h, &(state->imageLocY));
   }

   /* Offset from bottom left corner of screen to bottom left corner of image */
   state->imageOffsetX = state->imageLocX;
   state->imageOffsetY = (state->screen->h - state->picture->h) - state->imageLocY;

   /* Location of active area relative to bottom left corner of picture */
   if(gState.activeExtent == 64)
   {
      state->localOffsetX = 158 - state->imageOffsetX;
      state->localOffsetY = 227 - state->imageOffsetY;
   }
   else
   {
      state->localOffsetX = 174 - state->imageOffsetX;
      state->localOffsetY = 243 - state->imageOffsetY;
   }

   return DmtxPass;
}

/**
 *
 *
 */
DmtxPassFail
NudgeImage(int windowExtent, int pictureExtent, Sint16 *imageLoc)
{
   int minReveal = 16;

   if(*imageLoc < minReveal - pictureExtent)
      *imageLoc = minReveal - pictureExtent;
   else if(*imageLoc > windowExtent - minReveal)
      *imageLoc = windowExtent - minReveal;

   return DmtxPass;
}
Added jni/libdmtx/test/multi_test/multi_test.h.
















































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file multi_test.h
 */

#include <SDL/SDL.h>
#include "../../dmtx.h"

#define max(N,M) ((N > M) ? N : M)
#define min(N,M) ((N < M) ? N : M)
#define OPPOSITE_SIGNS(a,b) (a != 0 && b != 0 && ((a > 0) != (b > 0)))

#define LOCAL_SIZE            64
#define MAXIMA_SORT_MAX_COUNT  8
#define ANGLE_SORT_MAX_COUNT   8
#define TIMING_SORT_MAX_COUNT  8

#define NFFT                  64 /* FFT input size */
#define HOUGH_D_EXTENT        64
#define HOUGH_PHI_EXTENT     128

/* Layout constants */
#define CTRL_COL1_X          380
#define CTRL_COL2_X          445
#define CTRL_COL3_X          510
#define CTRL_COL4_X          575
#define CTRL_ROW1_Y            0
#define CTRL_ROW2_Y           65
#define CTRL_ROW3_Y          130
#define CTRL_ROW4_Y          195
#define CTRL_ROW5_Y          260
#define CTRL_ROW6_Y          325
#define CTRL_ROW7_Y          390

#define MODULE_LOW             0
#define MODULE_HIGH            1
#define MODULE_UNKNOWN         2

#define RotateCCW(N) ((N < 8) ? (N << 1) : 1)
#define RotateCW(N)  ((N > 1) ? (N >> 1) : 8)

typedef struct UserOptions_struct {
   const char *imagePath;
} UserOptions;

typedef struct AppState_struct {
   int         windowWidth;
   int         windowHeight;
   int         activeExtent;
   DmtxImage   *imgActive;
   DmtxImage   *imgFull;
   DmtxImage   *dmtxImage;
   DmtxBoolean autoNudge;
   int         displayEdge;
   DmtxBoolean displayVanish;
   DmtxBoolean displayTiming;
   DmtxBoolean displayZXings;
   DmtxBoolean printValues;
   Sint16      imageLocX;
   Sint16      imageLocY;
   Sint16      imageOffsetX; /* X offset of right-handed image origin from screen origin */
   Sint16      imageOffsetY; /* Y offset of right-handed image origin from screen origin */
   Sint16      localOffsetX; /* X offset of active area */
   Sint16      localOffsetY; /* Y offset of active area */
   Uint8       leftButton;
   Uint8       rightButton;
   Uint16      pointerX;
   Uint16      pointerY;
   DmtxBoolean quit;
   SDL_Surface *picture;
   SDL_Surface *screen;
   SDL_Surface *local;
   SDL_Surface *localTmp;
} AppState;

typedef enum {
   DmtxEdgeVertical,
   DmtxEdgeBackslash,
   DmtxEdgeHorizontal,
   DmtxEdgeSlash
} DmtxEdgeType;

typedef enum {
   DmtxOctantTop         = 0x01,
   DmtxOctantLeft        = 0x01 << 1,
   DmtxOctantBottom      = 0x01 << 2,
   DmtxOctantRight       = 0x01 << 3,
   DmtxOctantTopLeft     = (DmtxOctantTop | DmtxOctantLeft),
   DmtxOctantBottomLeft  = (DmtxOctantBottom | DmtxOctantLeft),
   DmtxOctantBottomRight = (DmtxOctantBottom | DmtxOctantRight),
   DmtxOctantTopRight    = (DmtxOctantTop | DmtxOctantRight)
} DmtxOctantType;

typedef struct DmtxValueGrid_struct DmtxValueGrid;
struct DmtxValueGrid_struct {
   int width;
   int height;
   int type;
   int *value;
   DmtxValueGrid *ref;
};

typedef struct DmtxSobel_struct DmtxSobel;
struct DmtxSobel_struct {
   DmtxValueGrid *v;
   DmtxValueGrid *b;
   DmtxValueGrid *h;
   DmtxValueGrid *s;
};

typedef struct DmtxAccel_struct DmtxAccel;
struct DmtxAccel_struct {
   DmtxValueGrid *vv;
   DmtxValueGrid *vb;
   DmtxValueGrid *hb;
   DmtxValueGrid *hh;
   DmtxValueGrid *hs;
   DmtxValueGrid *vs;
};

struct ZeroCrossing_struct {
   int iCol;
   int iRow;
   int mag;
   double x;
   double y;
};
typedef struct ZeroCrossing_struct ZeroCrossing;

typedef struct DmtxHoughBucket_struct DmtxHoughBucket;
struct DmtxHoughBucket_struct {
   int phi;
   int d;
   int val;
};

typedef struct DmtxHoughLocal_struct DmtxHoughLocal;
struct DmtxHoughLocal_struct {
   int xOrigin;
   int yOrigin;
   int dOrigin[128];
   int bucket[64][128]; /* [rows][cols] */ /* later change to 65 */
};

typedef struct DmtxHough_struct DmtxHough;
struct DmtxHough_struct {
   int rows;
   int cols;
   int count;
   DmtxHoughLocal *line;
   DmtxHoughLocal *maxima;
   DmtxHoughLocal *vanish;
};

typedef struct HoughMaximaSort_struct {
   int count;
   int mag[MAXIMA_SORT_MAX_COUNT];
} HoughMaximaSort;

typedef struct VanishPointSort_struct {
   int count;
   DmtxHoughBucket bucket[ANGLE_SORT_MAX_COUNT];
} VanishPointSort;

typedef struct Timing_struct {
   int phi;
   double shift;
   double period;
   double mag;
} Timing;

struct DmtxTimingSort_struct {
   int count;
   Timing timing[TIMING_SORT_MAX_COUNT];
};
typedef struct DmtxTimingSort_struct DmtxTimingSort;

typedef struct DmtxOrient_struct DmtxOrient;
struct DmtxOrient_struct {
/* add supporting values used to build tranformation matrices here */
   DmtxMatrix3 raw2fitLocal;
   DmtxMatrix3 raw2fit;
   DmtxMatrix3 fit2rawLocal;
   DmtxMatrix3 fit2raw;
};

typedef struct AlignmentGrid_struct {
   int rowCount;
   int colCount;
   DmtxMatrix3 raw2fitActive;
   DmtxMatrix3 raw2fitFull;
   DmtxMatrix3 fit2rawActive;
   DmtxMatrix3 fit2rawFull;
} AlignmentGrid;

typedef struct GridRegion_struct {
   AlignmentGrid grid;
   int x;
   int y;
   int width;
   int height;
   int sizeIdx;
   int onColor;
   int offColor;
   int finderSides;
   int contrast;
} GridRegion;

typedef struct RegionLines_struct {
   int gridCount;
   Timing timing;
   double dA, dB;
   DmtxRay2 line[2];
} RegionLines;

struct DmtxRegionSides_struct {
   DmtxRay2 top;
   DmtxRay2 left;
   DmtxRay2 bottom;
   DmtxRay2 right;
};
typedef struct DmtxRegionSides_struct DmtxRegionSides;

/* All values in GridRegionGrowth should be negative because list
 * is combined with the positive values of DmtxSymbolSize enum */
typedef enum {
   GridRegionGrowthUp       = -5,
   GridRegionGrowthLeft     = -4,
   GridRegionGrowthDown     = -3,
   GridRegionGrowthRight    = -2,
   GridRegionGrowthError    = -1
} GridRegionGrowth;

typedef enum {
   DmtxBarNone     = 0x00,
   DmtxBarTiming   = 0x01 << 0,
   DmtxBarFinder   = 0x01 << 1,
   DmtxBarInterior = 0x01 << 2,
   DmtxBarExterior = 0x01 << 3
} DmtxBarType;

/* Only used internally */
typedef struct ColorTally_struct {
   int evnCount;
   int oddCount;
   int evnColor;
   int oddColor;
} ColorTally;

struct StripStats_struct {
   int jumps;
   int surprises;
   int finderErrors;
   int timingErrors;
   int contrast;
   int finderBest;
   int timingBest;
};
typedef struct StripStats_struct StripStats;

struct DmtxCallbacks_struct {
   void (*dmtxValueGridCallback)(DmtxValueGrid *, int);
   void (*zeroCrossingCallback)(ZeroCrossing, int);
   void (*dmtxHoughLocalCallback)(DmtxHoughLocal *, int);
   void (*vanishPointCallback)(VanishPointSort *, int);
   void (*timingCallback)(Timing *, Timing *, int);
   void (*gridCallback)(AlignmentGrid *, int);
   void (*perimeterCallback)(GridRegion *, DmtxDirection, DmtxBarType);
};
typedef struct DmtxCallbacks_struct DmtxCallbacks;

typedef struct DmtxVectorPair_struct DmtxVectorPair;
struct DmtxVectorPair_struct {
   DmtxVector2 a;
   DmtxVector2 b;
};

typedef struct DmtxVanishCorners_struct DmtxVanishCorners;
struct DmtxVanishCorners_struct {
   unsigned char zone;
   DmtxRay2 lineA; /* XXX consider switching to DmtxVectorPair later? */
   DmtxRay2 lineB;
};

struct DmtxDecode2_struct {
   DmtxImage     *image;
   DmtxSobel     *sobel;
   DmtxAccel     *accel;
   DmtxHough     *hough;
   DmtxVanishCorners corners[64][128]; /* XXX temporary location */
   DmtxCallbacks  fn;
};
typedef struct DmtxDecode2_struct DmtxDecode2;

/* Application level functions */
DmtxPassFail HandleArgs(UserOptions *opt, int *argcp, char **argvp[]);
AppState InitAppState(void);
DmtxImage *CreateDmtxImage(SDL_Surface *sdlImage);
void AddFullTransforms(AlignmentGrid *grid);
SDL_Surface *SetWindowSize(int windowWidth, int windowHeight);
void captureLocalPortion(SDL_Surface *local, SDL_Surface *localTmp,
      SDL_Surface *picture, SDL_Surface *screen, AppState *state, SDL_Rect imageLoc);
DmtxPassFail HandleEvent(SDL_Event *event, AppState *state,
      SDL_Surface *picture, SDL_Surface **screen);
DmtxPassFail NudgeImage(int windowExtent, int pictureExtent, Sint16 *imageLoc);
/*static void WriteDiagnosticImage(DmtxDecode *dec, char *imagePath);*/

/* Image processing functions */
DmtxPassFail dmtxRegion2FindNext(DmtxDecode2 *dec);
DmtxPassFail OrientRegion(DmtxOrient *orient, DmtxHoughBucket v0, DmtxHoughBucket v1, DmtxDecode2 *dec);
double UncompactOffset(double d, int phiIdx, int extent);
void AddToVanishPointSort(VanishPointSort *sort, DmtxHoughBucket bucket);
VanishPointSort dmtxFindVanishPoints(DmtxHoughLocal *vHough);
void AddToMaximaSort(HoughMaximaSort *sort, int maximaMag);
DmtxHoughBucket GetAngleSumAtPhi(DmtxHoughLocal *local, int phi);
void AddToTimingSort(DmtxTimingSort *sort, Timing timing);
DmtxTimingSort dmtxFindGridTiming(DmtxHoughLocal *local, VanishPointSort *sort);
DmtxRay2 HoughCompactToRay(int phi, double d);
DmtxPassFail dmtxBuildGridFromTimings(AlignmentGrid *grid, Timing vp0, Timing vp1);
StripStats GenStripPatternStats(unsigned char *strip, int stripLength, int startState, int contrast);
GridRegion NudgeStripLimits(GridRegion *region, DmtxDirection side, int nudgeStyle);

DmtxPassFail dmtxFindRegionWithinGrid(GridRegion *region, AlignmentGrid *grid, DmtxHoughLocal *local, DmtxDecode *dec, DmtxCallbacks *fn);
int dmtxReadModuleColor(DmtxImage *img, AlignmentGrid *grid, int symbolRow, int symbolCol, int colorPlane);
DmtxBarType TestSideForPattern(GridRegion *region, DmtxImage *img, DmtxDirection side, int offset);
DmtxPassFail RegionExpand(GridRegion *region, DmtxDirection dir, DmtxHoughLocal *local, DmtxCallbacks *fn);
int dmtxGetSizeIdx(int a, int b);
DmtxPassFail RegionUpdateCorners(DmtxMatrix3 fit2raw, DmtxMatrix3 raw2fit, DmtxVector2 p00, DmtxVector2 p10, DmtxVector2 p11, DmtxVector2 p01);
DmtxPassFail dmtxDecodeSymbol(GridRegion *region, DmtxDecode *dec);
DmtxPassFail GetOnOffColors(GridRegion *region, const DmtxDecode *dec, int *onColor, int *offColor);
ColorTally GetTimingColors(GridRegion *region, const DmtxDecode *dec, int colBeg, int rowBeg, DmtxDirection dir);

/* Process visualization functions */
void ValueGridCallback(DmtxValueGrid *valueGrid, int id);
void ZeroCrossingCallback(ZeroCrossing zXing, int id);
void HoughLocalCallback(DmtxHoughLocal *hough, int id);
void VanishPointCallback(VanishPointSort *vPoints, int id);
void TimingCallback(Timing *timing0, Timing *timing1, int id);
void GridCallback(AlignmentGrid *grid, int id);
void PerimeterCallback(GridRegion *region, DmtxDirection side, DmtxBarType type);

void BlitSobelGrid(SDL_Surface *screen, DmtxValueGrid *cache, int x, int y, int screenY, int screenX);
void BlitHoughLocal(SDL_Surface *screen, DmtxHoughLocal *hough, int screenY, int screenX);
void ShowActiveRegion(SDL_Surface *screen, SDL_Surface *active);
void BlitActiveRegion(SDL_Surface *screen, SDL_Surface *active, int zoom, int screenY, int screenX);
Uint32 GetPixel(SDL_Surface *surface, int x, int y);
void PutPixel(SDL_Surface *surface, int x, int y, Uint32 color);
int RayIntersect(double *t, DmtxRay2 p0, DmtxRay2 p1);
int IntersectBox(DmtxRay2 ray, DmtxVector2 bb0, DmtxVector2 bb1, DmtxVector2 *p0, DmtxVector2 *p1);
void DrawActiveBorder(SDL_Surface *screen, int activeExtent);
void DrawLine(SDL_Surface *screen, int baseExtent, int screenX, int screenY, int phi, double d, int displayScale, Uint32 color);
void DrawVanishingPoints(SDL_Surface *screen, VanishPointSort *sort, int screenY, int screenX);
void DrawTimingDots(SDL_Surface *screen, Timing *timing, int screenY, int screenX);
void DrawNormalizedRegion(SDL_Surface *screen, DmtxImage *img, AlignmentGrid *grid, AppState *state, int screenY, int screenX);
Sint16 Clamp(Sint16 x, Sint16 xMin, Sint16 extent);
void DrawSymbolPreview(SDL_Surface *screen, DmtxImage *img, AlignmentGrid *grid, AppState *state, int screenY, int screenX);
void DrawPerimeterPatterns(SDL_Surface *screen, GridRegion *region, AppState *state, DmtxDirection side, DmtxBarType type);
void DrawPerimeterSide(SDL_Surface *screen, int x00, int y00, int x11, int y11, int dispModExtent, DmtxDirection side, DmtxBarType type);

/* dmtxvaluegrid.c */
DmtxValueGrid *dmtxValueGridCreate(int width, int height, int type, DmtxValueGrid *ref);
DmtxPassFail dmtxValueGridDestroy(DmtxValueGrid **valueGrid);
int dmtxValueGridGetWidth(DmtxValueGrid *valueGrid);
int dmtxValueGridGetHeight(DmtxValueGrid *valueGrid);
int dmtxValueGridGetValue(DmtxValueGrid *valueGrid, int x, int y);

/* dmtxsobel.c */
DmtxSobel *SobelCreate(DmtxImage *img);
DmtxPassFail SobelDestroy(DmtxSobel **sobel);
DmtxPassFail SobelPopulate(DmtxDecode2 *dec);

DmtxAccel *AccelCreate(DmtxSobel *sobel);
DmtxPassFail AccelDestroy(DmtxAccel **accel);
DmtxPassFail AccelPopulate(DmtxDecode2 *dec);
DmtxPassFail AccelPopulateLocal(DmtxValueGrid *acc);

/* dmtxdecode2.c */
DmtxDecode2 *dmtxDecode2Create();
DmtxPassFail dmtxDecode2Destroy(DmtxDecode2 **dec);
void PopulateVanishBounds(DmtxDecode2 *dec);
DmtxVanishCorners GetVanishCorners(int d, int phi);
int GetZone(int phiFull, double *distance);
DmtxVectorPair GetZoneCornerLocs(DmtxOctantType zone);
DmtxPassFail dmtxDecode2SetImage(DmtxDecode2 *dec, DmtxImage *img);
DmtxPassFail decode2ReleaseCacheMemory(DmtxDecode2 *dec);

/* dmtxhough.c */
DmtxHough *HoughCreate(int cols, int rows);
DmtxPassFail HoughDestroy(DmtxHough **grid);
DmtxPassFail HoughPopulate(DmtxDecode2 *dec);
DmtxPassFail LineHoughAccumulate(DmtxHoughLocal *lhRegion, DmtxDecode2 *dec);
DmtxPassFail MaximaHoughAccumulate(DmtxHoughLocal *mhRegion, DmtxHoughLocal *lhRegion, DmtxDecode2 *dec);
int GetMaximaWeight(DmtxHoughLocal *lhRegion, int phi, int d);
DmtxPassFail VanishHoughAccumulate(DmtxHoughLocal *lhRegion, DmtxHoughLocal *vhRegion);
int GetVanishBucket(int phiBucket, int phiCompare, int dCompare);
ZeroCrossing GetZeroCrossing(DmtxValueGrid *accel, int iCol, int iRow);
ZeroCrossing SetZeroCrossingFromIndex(DmtxValueGrid *accel, int aCol, int aRow, double smidg);
DmtxPassFail HoughLocalAccumulateEdge(DmtxHoughLocal *local, int phi, ZeroCrossing edge);
double HoughGetLocalOffset(double xLoc, double yLoc, int phi);

extern AppState gState;
Added jni/libdmtx/test/multi_test/visualize.c.


































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2010 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file visualize.c
 */

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_gfxPrimitives.h>
#include <SDL/SDL_rotozoom.h>
#include "../../dmtx.h"
#include "multi_test.h"

void ValueGridCallback(DmtxValueGrid *valueGrid, int id)
{
   int x, y;
   int imageFlipY;
   int imageHeight;

   imageHeight = dmtxImageGetProp(gState.dmtxImage, DmtxPropHeight);
   imageFlipY = gState.screen->h - (gState.imageLocY + imageHeight) - 1;

   x = gState.localOffsetX - 1; /* not sure why it needs -1 to align */
   y = gState.localOffsetY;

   switch(id) {
      case 0:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW2_Y, CTRL_COL1_X);
         break;
      case 1:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW2_Y, CTRL_COL2_X);
         break;
      case 2:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW2_Y, CTRL_COL3_X);
         break;
      case 3:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW2_Y, CTRL_COL4_X);
         break;
      case 4:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW3_Y, CTRL_COL1_X);
         break;
      case 5:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW3_Y, CTRL_COL2_X);
         break;
      case 6:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW3_Y, CTRL_COL4_X);
         break;
      case 7:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW4_Y, CTRL_COL2_X);
         break;
      case 8:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW4_Y, CTRL_COL3_X);
         break;
      case 9:
         BlitSobelGrid(gState.screen, valueGrid, x, y, CTRL_ROW4_Y, CTRL_COL4_X);
         break;
      default:
         break;
   }
}

void ZeroCrossingCallback(ZeroCrossing zXing, int id)
{
   int xInt, yInt;

   if(zXing.mag < 50)
      return;

   xInt = gState.imageOffsetX + (int)zXing.x;
   yInt = gState.screen->h - (gState.imageOffsetY + (int)zXing.y) - 1;

   if(xInt < 0 || xInt > CTRL_COL1_X - 2 || yInt < 0 || yInt > gState.screen->h - 1)
      return;

   switch(id) {
      case 0:
         PutPixel(gState.screen, xInt, yInt, 0x00ff0000);
         break;
      default:
         break;
   }
}

void HoughLocalCallback(DmtxHoughLocal *hough, int id)
{
   switch(id) {
      case 0:
         BlitHoughLocal(gState.screen, hough, CTRL_ROW5_Y, CTRL_COL1_X + 1);
         break;
      case 1:
         BlitHoughLocal(gState.screen, hough, CTRL_ROW6_Y, CTRL_COL1_X + 1);
         break;
      case 2:
         BlitHoughLocal(gState.screen, hough, CTRL_ROW7_Y, CTRL_COL1_X + 1);
         break;
   }
}

void VanishPointCallback(VanishPointSort *vPoints, int id)
{
   if(gState.displayVanish == DmtxFalse)
      return;

   DrawVanishingPoints(gState.screen, vPoints, CTRL_ROW7_Y, CTRL_COL1_X + 1);
}

void TimingCallback(Timing *timing0, Timing *timing1, int id)
{
   int i;
   int rowNum;

   rowNum = (id == 0) ? CTRL_ROW6_Y : CTRL_ROW5_Y;

   /* Should this be called before, as soon as local is captured? */
   BlitActiveRegion(gState.screen, gState.local, 2, CTRL_ROW5_Y, CTRL_COL3_X);

   if(gState.displayTiming == DmtxFalse)
      return;

   /* Draw timed and untimed region lines */
   if(gState.displayTiming == DmtxTrue) {
      DrawTimingDots(gState.screen, timing0, rowNum, CTRL_COL1_X);
      DrawTimingDots(gState.screen, timing1, rowNum, CTRL_COL1_X);

      for(i = -64; i <= 64; i++) {
         DrawLine(gState.screen, 64, CTRL_COL3_X, CTRL_ROW5_Y, timing0->phi,
               timing0->shift + (timing0->period * i), 2, 0xff0000ff);
         DrawLine(gState.screen, 64, CTRL_COL3_X, CTRL_ROW5_Y, timing1->phi,
               timing1->shift + (timing1->period * i), 2, 0xff0000ff);
      }
   }
}

void GridCallback(AlignmentGrid *grid, int id)
{
   switch(id) {
      case 0:
         DrawSymbolPreview(gState.screen, gState.imgFull, grid, &gState,
               CTRL_ROW5_Y, CTRL_COL1_X + 1);
         break;
      case 1:
         DrawNormalizedRegion(gState.screen, gState.imgFull, grid, &gState,
               CTRL_ROW5_Y, CTRL_COL3_X);
         break;
   }
}

void PerimeterCallback(GridRegion *region, DmtxDirection side, DmtxBarType type)
{
   DrawPerimeterPatterns(gState.screen, region, &gState, side, type);
}

/******************************************************************************/

void ShowActiveRegion(SDL_Surface *screen, SDL_Surface *active)
{
   BlitActiveRegion(screen, active, 1, CTRL_ROW1_Y, CTRL_COL1_X);
   BlitActiveRegion(screen, active, 1, CTRL_ROW1_Y, CTRL_COL2_X);
   BlitActiveRegion(screen, active, 1, CTRL_ROW1_Y, CTRL_COL3_X);
   BlitActiveRegion(screen, active, 1, CTRL_ROW1_Y, CTRL_COL4_X);
}

/**
 *
 *
 */
void BlitActiveRegion(SDL_Surface *screen, SDL_Surface *active, int zoom, int screenY, int screenX)
{
   SDL_Surface *src;
   SDL_Rect clipRect;

   clipRect.w = LOCAL_SIZE;
   clipRect.h = LOCAL_SIZE;
   clipRect.x = screenX;
   clipRect.y = screenY;

   if(zoom == 1) {
      SDL_BlitSurface(active, NULL, screen, &clipRect);
   }
   else {
      /* DO NOT USE SMOOTHING OPTION -- distorts symbol proportions */
      src = zoomSurface(active, 2.0, 2.0, 0 /* smoothing */);
      SDL_BlitSurface(src, NULL, screen, &clipRect);
      SDL_FreeSurface(src);
   }
}

/**
 *
 *
 */
void BlitSobelGrid(SDL_Surface *screen, DmtxValueGrid *cache, int x, int y, int screenY, int screenX)
{
   int row, col;
   unsigned char rgb[3];
   int width, height;
   int offset;
   int flow;
   unsigned char pixbuf[12288]; /* 64 * 64 * 3 */
   int maxFlowMag = 1020;

   SDL_Surface *surface;
   SDL_Rect clipRect;
   Uint32 rmask, gmask, bmask, amask;

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
   rmask = 0xff000000;
   gmask = 0x00ff0000;
   bmask = 0x0000ff00;
   amask = 0x000000ff;
#else
   rmask = 0x000000ff;
   gmask = 0x0000ff00;
   bmask = 0x00ff0000;
   amask = 0xff000000;
#endif

   width = height = 64;

   for(row = 0; row < 64; row++)
   {
      for(col = 0; col < 64; col++)
      {
         flow = dmtxValueGridGetValue(cache, col + x, row + y);
         if(flow > 0) {
            rgb[0] = 0;
            rgb[1] = (int)((abs(flow) * 254.0)/maxFlowMag + 0.5);
            rgb[2] = 0;
         }
         else {
            rgb[0] = (int)((abs(flow) * 254.0)/maxFlowMag + 0.5);
            rgb[1] = 0;
            rgb[2] = 0;
         }

         offset = ((height - row - 1) * width + col) * 3;
         pixbuf[offset] = rgb[0];
         pixbuf[offset+1] = rgb[1];
         pixbuf[offset+2] = rgb[2];
      }
   }

   clipRect.w = LOCAL_SIZE;
   clipRect.h = LOCAL_SIZE;
   clipRect.x = screenX;
   clipRect.y = screenY;

   surface = SDL_CreateRGBSurfaceFrom(pixbuf, width, height, 24, width * 3,
         rmask, gmask, bmask, 0);

   SDL_BlitSurface(surface, NULL, screen, &clipRect);
   SDL_FreeSurface(surface);
}

/**
 *
 *
 */
void BlitHoughLocal(SDL_Surface *screen, DmtxHoughLocal *hough, int screenY, int screenX)
{
   int row, col;
   int width, height;
   int maxVal;
   int rgb[3];
   unsigned int cache;
   int offset;
   unsigned char pixbuf[24576]; /* 128 * 64 * 3 */
   SDL_Surface *surface;
   SDL_Rect clipRect;
   Uint32 rmask, gmask, bmask, amask;

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
   rmask = 0xff000000;
   gmask = 0x00ff0000;
   bmask = 0x0000ff00;
   amask = 0x000000ff;
#else
   rmask = 0x000000ff;
   gmask = 0x0000ff00;
   bmask = 0x00ff0000;
   amask = 0xff000000;
#endif

   width = 128;
   height = LOCAL_SIZE;

   maxVal = 0;
   for(row = 0; row < height; row++)
   {
      for(col = 0; col < width; col++)
      {
         if(hough->bucket[row][col] > maxVal)
            maxVal = hough->bucket[row][col];
      }
   }

   for(row = 0; row < height; row++)
   {
      for(col = 0; col < width; col++)
      {
         cache = hough->bucket[row][col];

         rgb[0] = rgb[1] = rgb[2] = (int)((cache * 254.0)/maxVal + 0.5);

         offset = ((height - row - 1) * width + col) * 3;
         pixbuf[offset] = rgb[0];
         pixbuf[offset+1] = rgb[1];
         pixbuf[offset+2] = rgb[2];
      }
   }

   clipRect.w = width;
   clipRect.h = height;
   clipRect.x = screenX;
   clipRect.y = screenY;

   surface = SDL_CreateRGBSurfaceFrom(pixbuf, width, height, 24, width * 3,
         rmask, gmask, bmask, 0);

   SDL_BlitSurface(surface, NULL, screen, &clipRect);
   SDL_FreeSurface(surface);
}

/**
 *
 *
 */
Uint32
GetPixel(SDL_Surface *surface, int x, int y)
{
   int bpp = surface->format->BytesPerPixel;
   Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

   switch(bpp) {
      case 1:
         return *p;
      case 2:
         return *(Uint16 *)p;
      case 3:
         if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return (p[0] << 16) | (p[1] << 8) | p[2];
         else
            return p[0] | (p[1] << 8) | (p[2] << 16);
      case 4:
         return *(Uint32 *)p;
      default:
         return 0;
   }
}

void
PutPixel(SDL_Surface *surface, int x, int y, Uint32 color)
{
   int bpp = surface->format->BytesPerPixel;
   Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

   switch(bpp) {
   case 1:
      *p = color;
      break;
   case 2:
      *(Uint16 *)p = color;
      break;
   case 3:
      if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
         p[0] = (color >> 16) & 0xff;
         p[1] = (color >> 8) & 0xff;
         p[2] = color & 0xff;
      }
      else {
         p[0] = color & 0xff;
         p[1] = (color >> 8) & 0xff;
         p[2] = (color >> 16) & 0xff;
      }
      break;
   case 4:
      *(Uint32 *)p = color;
      break;
   }
}

/**
 *
 *
 */
int RayIntersect(double *t, DmtxRay2 p0, DmtxRay2 p1)
{
   double numer, denom;
   DmtxVector2 w;

   denom = dmtxVector2Cross(&(p1.v), &(p0.v));
   if(fabs(denom) <= 0.000001)
      return DmtxFail;

   dmtxVector2Sub(&w, &(p1.p), &(p0.p));
   numer = dmtxVector2Cross(&(p1.v), &w);

   *t = numer/denom;

   return DmtxTrue;
}

/**
 *
 *
 */
int IntersectBox(DmtxRay2 ray, DmtxVector2 bb0, DmtxVector2 bb1, DmtxVector2 *p0, DmtxVector2 *p1)
{
   double tTmp, xMin, xMax, yMin, yMax;
   DmtxVector2 p[2];
   int tCount = 0;
   double extent;
   DmtxRay2 rBtm, rTop, rLft, rRgt;
   DmtxVector2 unitX = { 1.0, 0.0 };
   DmtxVector2 unitY = { 0.0, 1.0 };

   if(bb0.X < bb1.X) {
      xMin = bb0.X;
      xMax = bb1.X;
   }
   else {
      xMin = bb1.X;
      xMax = bb0.X;
   }

   if(bb0.Y < bb1.Y) {
      yMin = bb0.Y;
      yMax = bb1.Y;
   }
   else {
      yMin = bb1.Y;
      yMax = bb0.Y;
   }

   extent = xMax - xMin;

   rBtm.p.X = rTop.p.X = rLft.p.X = xMin;
   rRgt.p.X = xMax;

   rBtm.p.Y = rLft.p.Y = rRgt.p.Y = yMin;
   rTop.p.Y = yMax;

   rBtm.v = rTop.v = unitX;
   rLft.v = rRgt.v = unitY;

   if(RayIntersect(&tTmp, rBtm, ray) == DmtxPass && tTmp >= 0.0 && tTmp < extent)
      dmtxPointAlongRay2(&(p[tCount++]), &rBtm, tTmp);

   if(RayIntersect(&tTmp, rTop, ray) == DmtxPass && tTmp >= 0.0 && tTmp < extent)
      dmtxPointAlongRay2(&(p[tCount++]), &rTop, tTmp);

   if(RayIntersect(&tTmp, rLft, ray) == DmtxPass && tTmp >= 0.0 && tTmp < extent)
      dmtxPointAlongRay2(&(p[tCount++]), &rLft, tTmp);

   if(RayIntersect(&tTmp, rRgt, ray) == DmtxPass && tTmp >= 0.0 && tTmp < extent)
      dmtxPointAlongRay2(&(p[tCount++]), &rRgt, tTmp);

   if(tCount != 2)
      return DmtxFail;

   *p0 = p[0];
   *p1 = p[1];

   return DmtxTrue;
}

/**
 *
 *
 */
void DrawActiveBorder(SDL_Surface *screen, int activeExtent)
{
   Sint16 x00, y00;
   Sint16 x10, y10;
   Sint16 x11, y11;
   Sint16 x01, y01;

   x01 = 158;
   y01 = 226;

   x00 = x01;
   y00 = y01 + activeExtent + 1;

   x10 = x00 + activeExtent + 1;
   y10 = y00;

   x11 = x10;
   y11 = y01;

   lineColor(screen, x00, y00, x10, y10, 0x0000ffff);
   lineColor(screen, x10, y10, x11, y11, 0x0000ffff);
   lineColor(screen, x11, y11, x01, y01, 0x0000ffff);
   lineColor(screen, x01, y01, x00, y00, 0x0000ffff);
}

/**
 *
 *
 */
void DrawLine(SDL_Surface *screen, int baseExtent, int screenX, int screenY,
      int phi, double d, int displayScale, Uint32 color)
{
   int scaledExtent;
   DmtxVector2 bb0, bb1;
   DmtxVector2 p0, p1;
   DmtxRay2 rLine;
   DmtxPixelLoc d0, d1;

   scaledExtent = baseExtent * displayScale;
   bb0.X = bb0.Y = 0.0;
   bb1.X = bb1.Y = scaledExtent - 1;

   rLine = HoughCompactToRay(phi, d);
   dmtxVector2ScaleBy(&rLine.p, (double)displayScale);

   p0.X = p0.Y = p1.X = p1.Y = 0.0;

   if(IntersectBox(rLine, bb0, bb1, &p0, &p1) == DmtxFalse)
      return;

   d0.X = (int)(p0.X + 0.5) + screenX;
   d1.X = (int)(p1.X + 0.5) + screenX;

   d0.Y = screenY + (scaledExtent - (int)(p0.Y + 0.5) - 1);
   d1.Y = screenY + (scaledExtent - (int)(p1.Y + 0.5) - 1);

   lineColor(screen, d0.X, d0.Y, d1.X, d1.Y, color);
}

/**
 *
 *
 */
void DrawVanishingPoints(SDL_Surface *screen, VanishPointSort *sort, int screenY, int screenX)
{
   int sortIdx;
   DmtxPixelLoc d0, d1;
   Uint32 rgba;

   for(sortIdx = 0; sortIdx < sort->count; sortIdx++)
   {
      d0.X = screenX + sort->bucket[sortIdx].phi - 2;
      d1.X = d0.X + 4;
      d0.Y = screenY + (63 - sort->bucket[sortIdx].d) - 2;;
      d1.Y = d0.Y + 4;

      if(sortIdx < 2)
         rgba = 0xff0000ff; /* red: strongest */
      else if(sortIdx < 4)
         rgba = 0x999900ff; /* yellow: weaker */
      else if(sortIdx < 6)
         rgba = 0x007700ff; /* green: even weaker */
      else
         rgba = 0x000077ff; /* blue: weakest */

      rectangleColor(screen, d0.X, d0.Y, d1.X, d1.Y, rgba);
   }
}

/**
 *
 *
 */
void DrawTimingDots(SDL_Surface *screen, Timing *timing, int screenY, int screenX)
{
   int i, d;

   for(i = 0; i < 64; i++) {
      d = (int)(i * timing->period + timing->shift);
      if(d >= 64)
         break;

      PutPixel(screen, screenX + timing->phi, screenY + 63 - d, 0x00ff0000);
   }
}

/**
 *
 *
 */
void DrawNormalizedRegion(SDL_Surface *screen, DmtxImage *img,
      AlignmentGrid *region, AppState *state, int screenY, int screenX)
{
   unsigned char pixbuf[49152]; /* 128 * 128 * 3 */
   unsigned char *ptrFit, *ptrRaw;
   SDL_Rect clipRect;
   SDL_Surface *surface;
   Uint32 rmask, gmask, bmask, amask;
   int x, yImage, yDmtx;
   int xRaw, yRaw;
   int extent = 128;
   int modulesToDisplay = 16;
   int dispModExtent = extent/modulesToDisplay;
   int bytesPerRow = extent * 3;
   DmtxVector2 pFit, pRaw, pRawActive, pTmp, pCtr;
   DmtxVector2 gridTest;
   int shiftX, shiftY;

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
   rmask = 0xff000000;
   gmask = 0x00ff0000;
   bmask = 0x0000ff00;
   amask = 0x000000ff;
#else
   rmask = 0x000000ff;
   gmask = 0x0000ff00;
   bmask = 0x00ff0000;
   amask = 0xff000000;
#endif

   SDL_LockSurface(state->picture);

   pTmp.X = pTmp.Y = state->activeExtent/2.0;
   dmtxMatrix3VMultiply(&pCtr, &pTmp, region->raw2fitActive);

   for(yImage = 0; yImage < extent; yImage++) {
      for(x = 0; x < extent; x++) {

         yDmtx = (extent - 1) - yImage;

         /* Adjust fitted input so unfitted center is display centered */
         pFit.X = ((x-extent/2) * (double)modulesToDisplay) /
               (region->colCount * extent) + pCtr.X;

         pFit.Y = ((yDmtx-extent/2) * (double)modulesToDisplay) /
               (region->rowCount * extent) + pCtr.Y;

         dmtxMatrix3VMultiply(&pRaw, &pFit, region->fit2rawFull);
         dmtxMatrix3VMultiply(&pRawActive, &pFit, region->fit2rawActive);

         xRaw = (pRaw.X >= 0.0) ? (int)(pRaw.X + 0.5) : (int)(pRaw.X - 0.5);
         yRaw = (pRaw.Y >= 0.0) ? (int)(pRaw.Y + 0.5) : (int)(pRaw.Y - 0.5);

         ptrFit = pixbuf + (yImage * bytesPerRow + x * 3);
         if(xRaw < 0 || xRaw >= img->width || yRaw < 0 || yRaw >= img->height) {
            ptrFit[0] = 0;
            ptrFit[1] = 0;
            ptrFit[2] = 0;
         }
         else {
            ptrRaw = (unsigned char *)img->pxl + dmtxImageGetByteOffset(img, xRaw, yRaw);

            if(pRawActive.X < 0.0 || pRawActive.X >= state->activeExtent - 1 ||
                  pRawActive.Y < 0.0 || pRawActive.Y >= state->activeExtent - 1) {
               ptrFit[0] = ptrRaw[0]/2;
               ptrFit[1] = ptrRaw[1]/2;
               ptrFit[2] = ptrRaw[2]/2;
            }
            else {
               ptrFit[0] = ptrRaw[0];
               ptrFit[1] = ptrRaw[1];
               ptrFit[2] = ptrRaw[2];
            }
         }
      }
   }

   gridTest.X = pCtr.X * region->colCount * dispModExtent;
   gridTest.X += (gridTest.X >= 0.0) ? 0.5 : -0.5;
   shiftX = (int)gridTest.X % dispModExtent;

   gridTest.Y = pCtr.Y * region->rowCount * dispModExtent;
   gridTest.Y += (gridTest.Y >= 0.0) ? 0.5 : -0.5;
   shiftY = (int)gridTest.Y % dispModExtent;

   for(yImage = 0; yImage < extent; yImage++) {

      yDmtx = (extent - 1) - yImage;

      for(x = 0; x < extent; x++) {

         if((yDmtx + shiftY) % dispModExtent != 0 &&
               (x + shiftX) % dispModExtent != 0)
            continue;

         ptrFit = pixbuf + (yImage * bytesPerRow + x * 3);

         /* If reeaally dark then add brightened grid lines */
         if(ptrFit[0] + ptrFit[1] + ptrFit[2] < 60) {
            ptrFit[0] += (255 - ptrFit[0])/8;
            ptrFit[1] += (255 - ptrFit[1])/8;
            ptrFit[2] += (255 - ptrFit[2])/8;
         }
         /* Otherwise add darkened grid lines */
         else {
            ptrFit[0] = (ptrFit[0] * 8)/10;
            ptrFit[1] = (ptrFit[1] * 8)/10;
            ptrFit[2] = (ptrFit[2] * 8)/10;
         }
      }
   }

   clipRect.w = extent;
   clipRect.h = extent;
   clipRect.x = screenX;
   clipRect.y = screenY;

   surface = SDL_CreateRGBSurfaceFrom(pixbuf, extent, extent, 24, extent * 3,
         rmask, gmask, bmask, 0);

   SDL_BlitSurface(surface, NULL, screen, &clipRect);
   SDL_FreeSurface(surface);

   SDL_UnlockSurface(state->picture);
}

/**
 *
 *
 */
Sint16 Clamp(Sint16 x, Sint16 xMin, Sint16 extent)
{
   Sint16 xMax;

   if(x < xMin)
      return xMin;

   xMax = xMin + extent - 1;
   if(x > xMax)
      return xMax;

   return x;
}

/**
 *
 *
 */
void DrawSymbolPreview(SDL_Surface *screen, DmtxImage *img, AlignmentGrid *grid,
      AppState *state, int screenY, int screenX)
{
   DmtxVector2 pTmp, pCtr;
   DmtxVector2 gridTest;
   int shiftX /*, shiftY*/;
/* int rColor, gColor, bColor, color; */
/* Sint16 x1, y1, x2, y2; */
   int extent = 128;
   int modulesToDisplay = 16;
   int dispModExtent = extent/modulesToDisplay;
/* int row, col; */
   int /*rowBeg,*/ colBeg;
   int /*rowEnd,*/ colEnd;

   SDL_LockSurface(state->picture);

   pTmp.X = pTmp.Y = state->activeExtent/2.0;
   dmtxMatrix3VMultiply(&pCtr, &pTmp, grid->raw2fitActive);

   gridTest.X = pCtr.X * grid->colCount * dispModExtent;
   gridTest.X += (gridTest.X >= 0.0) ? 0.5 : -0.5;
   shiftX = 64 - (int)gridTest.X;
   colBeg = (shiftX < 0) ? 0 : -shiftX/8 - 1;
   colEnd = max(colBeg + 17, grid->colCount);

/* something is uninitialized ... verify in cygwin
   fprintf(stdout, "colBeg:%d colEnd:%d\n", colBeg, colEnd); fflush(stdout);

   gridTest.Y = pCtr.Y * grid->rowCount * dispModExtent;
   gridTest.Y += (gridTest.Y >= 0.0) ? 0.5 : -0.5;
   shiftY = 64 - (int)gridTest.Y;
   rowBeg = (shiftY < 0) ? 0 : -shiftY/8 - 1;
   rowEnd = max(rowBeg + 17, grid->rowCount);

   for(row = rowBeg; row < rowEnd; row++) {

      y1 = row * dispModExtent + shiftY;
      y2 = y1 + dispModExtent - 1;

      y1 = (extent - 1 - y1);
      y2 = (extent - 1 - y2);

      y1 = Clamp(y1 + screenY, screenY, 128);
      y2 = Clamp(y2 + screenY, screenY, 128);

      for(col = colBeg; col < colEnd; col++) {
         rColor = dmtxReadModuleColor(img, grid, row, col, 0);
         gColor = dmtxReadModuleColor(img, grid, row, col, 1);
         bColor = dmtxReadModuleColor(img, grid, row, col, 2);
         color = (rColor << 24) | (gColor << 16) | (bColor << 8) | 0xff;

         x1 = col * dispModExtent + shiftX;
         x2 = x1 + dispModExtent - 1;

         x1 = Clamp(x1 + screenX, screenX, 128);
         x2 = Clamp(x2 + screenX, screenX, 128);

         boxColor(screen, x1, y1, x2, y2, color);
      }
   }
*/

   SDL_UnlockSurface(state->picture);
}

/**
 *
 *
 */
void DrawPerimeterPatterns(SDL_Surface *screen, GridRegion *region,
      AppState *state, DmtxDirection side, DmtxBarType type)
{
   DmtxVector2 pTmp, pCtr;
   DmtxVector2 gridTest;
   int shiftX, shiftY;
   int extent = 128;
   int modulesToDisplay = 16;
   int dispModExtent = extent/modulesToDisplay;
   Sint16 x00, y00;
   Sint16 x11, y11;

   pTmp.X = pTmp.Y = state->activeExtent/2.0;
   dmtxMatrix3VMultiply(&pCtr, &pTmp, region->grid.raw2fitActive);

   gridTest.X = pCtr.X * region->grid.colCount * dispModExtent;
   gridTest.X += (gridTest.X >= 0.0) ? 0.5 : -0.5;
   shiftX = 64 - (int)gridTest.X;

   gridTest.Y = pCtr.Y * region->grid.rowCount * dispModExtent;
   gridTest.Y += (gridTest.Y >= 0.0) ? 0.5 : -0.5;
   shiftY = 63 - (int)gridTest.Y;

   /* Calculate corner positions */
   x00 = region->x * dispModExtent + shiftX;
   y00 = region->y * dispModExtent + shiftY;
   x11 = x00 + region->width * dispModExtent;
   y11 = y00 + region->height * dispModExtent;

   DrawPerimeterSide(screen, x00, y00, x11, y11, dispModExtent, side, type);
}

/**
 *
 *
 */
void DrawPerimeterSide(SDL_Surface *screen, int x00, int y00, int x11, int y11,
      int dispModExtent, DmtxDirection side, DmtxBarType type)
{
   Sint16 xBeg, yBeg;
   Sint16 xEnd, yEnd;
   int extent = 128;
   const int screenX = CTRL_COL1_X + 1;
   const int screenY = CTRL_ROW5_Y;
   Uint32 color;

   switch(side) {
      case DmtxDirUp:
         xBeg = x00;
         xEnd = x11;
         yBeg = yEnd = y11 - dispModExtent/2;
         break;
      case DmtxDirLeft:
         yBeg = y00;
         yEnd = y11;
         xBeg = xEnd = x00 + dispModExtent/2;
         break;
      case DmtxDirDown:
         xBeg = x00;
         xEnd = x11;
         yBeg = yEnd = y00 + dispModExtent/2;
         break;
      case DmtxDirRight:
         yBeg = y00;
         yEnd = y11;
         xBeg = xEnd = x11 - dispModExtent/2;
         break;
      default:
         xBeg = x00;
         yBeg = y00;
         xEnd = x11;
         yEnd = y11;
         break;
   }

   yBeg = (extent - 1 - yBeg);
   yEnd = (extent - 1 - yEnd);

   xBeg = Clamp(xBeg + screenX, screenX, 128);
   yBeg = Clamp(yBeg + screenY, screenY, 128);

   xEnd = Clamp(xEnd + screenX, screenX, 128);
   yEnd = Clamp(yEnd + screenY, screenY, 128);

   if(type & DmtxBarFinder)
      color = 0x0000ffff;
   else if(type & DmtxBarTiming)
      color = 0xff0000ff;
   else
      color = 0x00ff00ff;

   lineColor(screen, xBeg, yBeg, xEnd, yEnd, color);
}
Added jni/libdmtx/test/rotate_test/Makefile.am.


























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
AM_CPPFLAGS = -Wshadow -Wall -pedantic -ansi

check_PROGRAMS = rotate_test

rotate_test_SOURCES = rotate_test.c callback.c display.c image.c dmtx.c

EXTRA_rotate_test_SOURCES = callback.h display.h rotate_test.h image.h

if TARGET_MACOSX
rotate_test_LDFLAGS = -lm -lpng -framework OpenGL -lSDL -lSDLmain -framework Cocoa -lpthread
else
rotate_test_LDFLAGS = -lm -lpng -lGL -lGLU -lSDL -lpthread
endif
Added jni/libdmtx/test/rotate_test/README.


















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
This test program uses OpenGL (Mesa) to simulate camera input,
and writes decoded Data Matrix streams to STDOUT.

Right-click on the window to cycle through the test images.  To
add your own images for testing, just overwrite any image in the
"rotate_test/images" directory with another 256x256 PNG file.  If
you want to add brand new images then you will have to update the
gFilename[] and gFileCount variables at the top of rotate_test.c
to include them.
Added jni/libdmtx/test/rotate_test/callback.c.




















































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file callback.c
 */

#include <stdlib.h>
#include "rotate_test.h"
#include "callback.h"
#include "display.h"
#include "image.h"
#include "dmtx.h"

#define DMTX_DISPLAY_SQUARE            1
#define DMTX_DISPLAY_POINT             2
#define DMTX_DISPLAY_CIRCLE            3

/**
 *
 *
 */
void BuildMatrixCallback2(DmtxRegion *region)
{
   int i, j;
   int offset;
   float scale = 1.0/200.0;
   DmtxVector2 point;
   DmtxMatrix3 m0, m1, mInv;
   int rgb[3];

   dmtxMatrix3Translate(m0, -(320 - 200)/2.0, -(320 - 200)/2.0);
   dmtxMatrix3Scale(m1, scale, scale);
   dmtxMatrix3Multiply(mInv, m0, m1);
   dmtxMatrix3MultiplyBy(mInv, region->fit2raw);

   glDisable(GL_TEXTURE_2D);
   glPolygonMode(GL_FRONT, GL_LINE);

   for(i = 0; i < 320; i++) {
      for(j = 0; j < 320; j++) {
         point.X = j;
         point.Y = i;
         dmtxMatrix3VMultiplyBy(&point, mInv);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 0, &rgb[0]);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 1, &rgb[1]);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 2, &rgb[2]);

         offset = (320 * i + j) * 3;
         passTwoPxl[offset + 0] = rgb[0];
         passTwoPxl[offset + 1] = rgb[1];
         passTwoPxl[offset + 2] = rgb[2];
/*       dmtxPixelFromColor3(passTwoPxl[i*320+j], &clr); */
      }
   }

   DrawPane3(NULL, passTwoPxl);

   glViewport(646, 324, 320, 320);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(-0.5, 319.5, -0.5, 319.5, -1.0, 10.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   glColor3f(0.0, 1.0, 0.0);
   glBegin(GL_QUADS);
   glVertex2f( 60.0,  60.0);
   glVertex2f(260.0,  60.0);
   glVertex2f(260.0, 260.0);
   glVertex2f( 60.0, 260.0);
   glEnd();
}

/**
 *
 *
 */
void BuildMatrixCallback3(DmtxMatrix3 mChainInv)
{
   int i, j;
   int offset;
   float scale = 1.0/100.0;
   DmtxVector2 point;
   DmtxMatrix3 m0, m1, mInv;
   int rgb[3];

   dmtxMatrix3Scale(m0, scale, scale);
   dmtxMatrix3Translate(m1, -(320 - 200)/2.0, -(320 - 200)/2.0);

   dmtxMatrix3Multiply(mInv, m1, m0);
   dmtxMatrix3MultiplyBy(mInv, mChainInv);

   glDisable(GL_TEXTURE_2D);
   glPolygonMode(GL_FRONT, GL_LINE);

   for(i = 0; i < 320; i++) {
      for(j = 0; j < 320; j++) {
         point.X = j;
         point.Y = i;
         dmtxMatrix3VMultiplyBy(&point, mInv);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 0, &rgb[0]);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 1, &rgb[1]);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 2, &rgb[2]);

         offset = (320 * i + j) * 3;
         passTwoPxl[offset + 0] = rgb[0];
         passTwoPxl[offset + 1] = rgb[1];
         passTwoPxl[offset + 2] = rgb[2];
      }
   }

   DrawPane4(NULL, passTwoPxl);

   glViewport(2, 2, 320, 320);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(-0.5, 319.5, -0.5, 319.5, -1.0, 10.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   glColor3f(0.0, 1.0, 0.0);
   glBegin(GL_QUADS);
   glVertex2f( 60.0,  60.0);
   glVertex2f(160.0,  60.0);
   glVertex2f(160.0, 160.0);
   glVertex2f( 60.0, 160.0);
/**
   glVertex2f( 60.0,  60.0);
   glVertex2f(260.0,  60.0);
   glVertex2f(260.0, 260.0);
   glVertex2f( 60.0, 260.0);
*/
   glEnd();
}

/**
 *
 *
 */
void BuildMatrixCallback4(DmtxMatrix3 mChainInv)
{
   int i, j;
   int offset;
   float scale = 1.0/200.0;
   DmtxVector2 point;
   DmtxMatrix3 m0, m1, mInv;
   int rgb[3];

   dmtxMatrix3Scale(m0, scale, scale);
   dmtxMatrix3Translate(m1, -(320 - 200)/2.0, -(320 - 200)/2.0);

   dmtxMatrix3Multiply(mInv, m1, m0);
   dmtxMatrix3MultiplyBy(mInv, mChainInv);

   glDisable(GL_TEXTURE_2D);
   glPolygonMode(GL_FRONT, GL_LINE);

   for(i = 0; i < 320; i++) {
      for(j = 0; j < 320; j++) {
         point.X = j;
         point.Y = i;
         dmtxMatrix3VMultiplyBy(&point, mInv);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 0, &rgb[0]);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 1, &rgb[1]);
         dmtxImageGetPixelValue(gImage, (int)(point.X+0.5), (int)(point.Y+0.5), 2, &rgb[2]);

         offset = (320 * i + j) * 3;
         passTwoPxl[offset + 0] = rgb[0];
         passTwoPxl[offset + 1] = rgb[1];
         passTwoPxl[offset + 2] = rgb[2];
      }
   }

   DrawPane5(NULL, passTwoPxl);

   glViewport(324, 2, 320, 320);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(-0.5, 319.5, -0.5, 319.5, -1.0, 10.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   glColor3f(0.0, 1.0, 0.0);
   glBegin(GL_QUADS);
   glVertex2f( 60.0,  60.0);
   glVertex2f(260.0,  60.0);
   glVertex2f(260.0, 260.0);
   glVertex2f( 60.0, 260.0);
   glEnd();
}

/**
 *
 *
 */
void PlotPointCallback(DmtxPixelLoc loc, int colorInt, int paneNbr, int dispType)
{
   int color;
   DmtxImage *image = NULL;
   DmtxVector2 point;

   point.X = loc.X;
   point.Y = loc.Y;

   switch(paneNbr) {
      case 1:
         glViewport(2, 324, 320, 320);
         break;
      case 2:
         glViewport(324, 324, 320, 320);
/*       image = passOnePxl; */
         break;
      case 3:
         glViewport(646, 324, 320, 320);
         break;
      case 4:
         glViewport(2, 2, 320, 320);
         break;
      case 5:
         glViewport(324, 2, 320, 320);
         break;
      case 6:
         glViewport(646, 2, 320, 320);
         break;
   }

   if(image != NULL) {
      switch(colorInt) {
         case 1:
            color = ColorRed;
            break;
         case 2:
            color = ColorGreen;
            break;
         case 3:
            color = ColorBlue;
            break;
         case 4:
            color = ColorYellow;
            break;
         default:
            color = ColorWhite;
            break;
      }

      plotPoint(image, point.Y, point.X, color);
/*    plotPoint(image, point.Y + 1, point.X - 1, color);
      plotPoint(image, point.Y + 1, point.X + 1, color);
      plotPoint(image, point.Y - 1, point.X - 1, color);
      plotPoint(image, point.Y - 1, point.X + 1, color); */
   }
   else {
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(-0.5, 319.5, -0.5, 319.5, -1.0, 10.0);
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();

      glDisable(GL_TEXTURE_2D);
      glPolygonMode(GL_FRONT, GL_LINE);

      switch(colorInt) {
         case 1:
            glColor3f(1.0, 0.0, 0.0);
            break;
         case 2:
            glColor3f(0.0, 1.0, 0.0);
            break;
         case 3:
            glColor3f(0.0, 0.0, 1.0);
            break;
         case 4:
            glColor3f(1.0, 1.0, 0.0);
            break;
         default:
            glColor3f(1.0, 1.0, 1.0);
            break;
      }

      if(dispType == DMTX_DISPLAY_SQUARE) {
         glBegin(GL_QUADS);
         glVertex2f(point.X - 3, point.Y - 3);
         glVertex2f(point.X + 3, point.Y - 3);
         glVertex2f(point.X + 3, point.Y + 3);
         glVertex2f(point.X - 3, point.Y + 3);
         glEnd();
      }
      else if(dispType == DMTX_DISPLAY_POINT) {
         int x = (int)(point.X + 0.5);
         int y = (int)(point.Y + 0.5);

         glBegin(GL_POINTS);
         glVertex2f(x, y);
         glEnd();
      }
   }
}

/**
 *
 *
 */
void XfrmPlotPointCallback(DmtxVector2 point, DmtxMatrix3 xfrm, int paneNbr, int dispType)
{
   float scale = 100.0;
   DmtxMatrix3 m, m0, m1;

   if(xfrm != NULL) {
      dmtxMatrix3Copy(m, xfrm);
   }
   else {
      dmtxMatrix3Identity(m);
   }

   dmtxMatrix3Scale(m0, scale, scale);
   dmtxMatrix3Translate(m1, (320 - 200)/2.0, (320 - 200)/2.0);
   dmtxMatrix3MultiplyBy(m, m0);
   dmtxMatrix3MultiplyBy(m, m1);

   dmtxMatrix3VMultiplyBy(&point, m);
/* PlotPointCallback(point, 3, paneNbr, dispType); */
}

/**
 *
 *
 */
void PlotModuleCallback(DmtxDecode *info, DmtxRegion *region, int row, int col, int color)
{
   int modSize, halfModsize, padSize;
/* float t; */

   /* Adjust for addition of finder bar */
   row++;
   col++;

   halfModsize = (int)(100.0 / (region->mappingCols + 2) + 0.5); /* Because 100 == 200/2 */
   modSize = 2 * halfModsize;
   padSize = (320 - ((region->mappingCols + 2) * modSize))/2;

   /* Set for 6th pane */
   DrawPaneBorder(645, 1, 322, 322);
   glRasterPos2i(1, 1);

   glPolygonMode(GL_FRONT, GL_FILL);

   /* Clamp color to extreme foreground or background color */
/* t = dmtxDistanceAlongRay3(&(region->gradient.ray), &color);
   t = (t < region->gradient.tMid) ? region->gradient.tMin : region->gradient.tMax;
   dmtxPointAlongRay3(&color, &(region->gradient.ray), t); */

   if(color == 1) {
      glColor3f(0.0, 0.0, 0.0);
   }
   else {
      glColor3f(1.0, 1.0, 1.0);
   }

   glBegin(GL_QUADS);
   glVertex2f(modSize*(col+0.5) + padSize - halfModsize, modSize*(row+0.5) + padSize - halfModsize);
   glVertex2f(modSize*(col+0.5) + padSize + halfModsize, modSize*(row+0.5) + padSize - halfModsize);
   glVertex2f(modSize*(col+0.5) + padSize + halfModsize, modSize*(row+0.5) + padSize + halfModsize);
   glVertex2f(modSize*(col+0.5) + padSize - halfModsize, modSize*(row+0.5) + padSize + halfModsize);
   glEnd();
}

/**
 *
 *
 */
void FinalCallback(DmtxDecode *decode, DmtxRegion *region)
{
   int row, col;
   int symbolRows, symbolCols;
   int moduleStatus;
/* DmtxColor3 black = { 0.0, 0.0, 0.0 };
   DmtxColor3 white = { 255.0, 255.0, 255.0 }; */

   symbolRows = dmtxGetSymbolAttribute(DmtxSymAttribSymbolRows, region->sizeIdx);
   symbolCols = dmtxGetSymbolAttribute(DmtxSymAttribSymbolCols, region->sizeIdx);

   for(row = 0; row < symbolRows; row++) {
      for(col = 0; col < symbolCols; col++) {
/*       moduleStatus = dmtxSymbolModuleStatus(message, region->sizeIdx, row, col); */
         PlotModuleCallback(decode, region, row, col, (moduleStatus & DmtxModuleOnRGB) ? 1 : 0);
      }
   }
}
Added jni/libdmtx/test/rotate_test/callback.h.
















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file callback.h
 */

#ifndef __CALLBACK_H__
#define __CALLBACK_H__

void BuildMatrixCallback2(DmtxRegion *region);
void BuildMatrixCallback3(DmtxMatrix3 region);
void BuildMatrixCallback4(DmtxMatrix3 region);
void PlotPointCallback(DmtxPixelLoc loc, int colorInt, int paneNbr, int dispType);
void XfrmPlotPointCallback(DmtxVector2 point, DmtxMatrix3 xfrm, int paneNbr, int dispType);
void FinalCallback(DmtxDecode *decode, DmtxRegion *region);
/*void PlotModuleCallback(DmtxDecode *info, DmtxRegion *region, int row, int col, DmtxColor3 color);*/

#endif
Added jni/libdmtx/test/rotate_test/display.c.
































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file display.c
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include "dmtx.h"
#include "rotate_test.h"
#include "display.h"

/**
 *
 *
 */
SDL_Surface *initDisplay(void)
{
   SDL_Surface *screen;

   SDL_Init(SDL_INIT_VIDEO);

   screen = SDL_SetVideoMode(968, 646, 16, SDL_OPENGL | SDL_RESIZABLE);
   if(!screen) {
      fprintf(stderr, "Couldn't set 968x646 GL video mode: %s\n", SDL_GetError());
      SDL_Quit();
      exit(2);
   }
   SDL_WM_SetCaption("GL Test", "GL Test");

   glClearColor(0.0, 0.0, 0.3, 1.0);

   return screen;
}

/**
 *
 *
 */
void DrawBarCode(void)
{
   glColor3f(0.95, 0.95, 0.95);
   glBegin(GL_QUADS);
   glTexCoord2d(0.0, 0.0); glVertex3f(-2.0, -2.0,  0.0);
   glTexCoord2d(1.0, 0.0); glVertex3f( 2.0, -2.0,  0.0);
   glTexCoord2d(1.0, 1.0); glVertex3f( 2.0,  2.0,  0.0);
   glTexCoord2d(0.0, 1.0); glVertex3f(-2.0,  2.0,  0.0);
   glEnd();
}

/**
 *
 *
 */
void ReshapeWindow(int width, int height)
{
   glViewport(2, 324, (GLint)320, (GLint)320);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 50.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}

/**
 *
 *
 */
void DrawBorders(SDL_Surface *screen)
{
   /* window and pane borders */
   DrawPaneBorder(  0,   0, 646, 968);

   DrawPaneBorder(  1,   1, 322, 322);
   DrawPaneBorder(323,   1, 322, 322);
   DrawPaneBorder(645,   1, 322, 322);

   DrawPaneBorder(  1, 323, 322, 322);
   DrawPaneBorder(323, 323, 322, 322);
   DrawPaneBorder(645, 323, 322, 322);
}

/**
 *
 *
 */
void DrawGeneratedImage(SDL_Surface *screen)
{
   /* rotate barcode surface */
   glViewport(2, 324, (GLint)320, (GLint)320);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 50.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glTranslatef(0.0, 0.0, -10.0);
   glPolygonMode(GL_FRONT, GL_FILL);
   glPolygonMode(GL_BACK, GL_LINE);
   glEnable(GL_TEXTURE_2D);

   glPushMatrix();
   glRotatef(view_rotx, 1.0, 0.0, 0.0);
   glRotatef(view_roty, 0.0, 1.0, 0.0);
   glRotatef(view_rotz, 0.0, 0.0, 1.0);
   glRotatef(angle, 0.0, 0.0, 1.0);
   glCallList(barcodeList);
   glPopMatrix();
}

/**
 *
 *
 */
void DrawPane2(SDL_Surface *screen, unsigned char *pxl)
{
   DrawPaneBorder(323, 323, 322, 322); /* XXX drawn twice */
   glRasterPos2i(1, 1);
   glDrawPixels(320, 320, GL_RGB, GL_UNSIGNED_BYTE, pxl);
}

/**
 *
 *
 */
void DrawPane3(SDL_Surface *screen, unsigned char *pxl)
{
   DrawPaneBorder(645, 323, 322, 322); /* XXX drawn twice */
   glRasterPos2i(1, 1);
   glDrawPixels(320, 320, GL_RGB, GL_UNSIGNED_BYTE, pxl);
}

/**
 *
 *
 */
void DrawPane4(SDL_Surface *screen, unsigned char *pxl)
{
   DrawPaneBorder(1, 1, 322, 322); /* XXX drawn twice */
   glRasterPos2i(1, 1);
   glDrawPixels(320, 320, GL_RGB, GL_UNSIGNED_BYTE, pxl);
}

/**
 *
 *
 */
void DrawPane5(SDL_Surface *screen, unsigned char *pxl)
{
   DrawPaneBorder(323, 1, 322, 322); /* XXX drawn twice */
   glRasterPos2i(1, 1);
   glDrawPixels(320, 320, GL_RGB, GL_UNSIGNED_BYTE, pxl);
}

/**
 *
 *
 */
void DrawPane6(SDL_Surface *screen, unsigned char *pxl)
{
   DrawPaneBorder(645, 1, 322, 322); /* XXX drawn twice */
   glRasterPos2i(1, 1);

   if(pxl != NULL)
      glDrawPixels(320, 320, GL_RGB, GL_UNSIGNED_BYTE, pxl);
}

/**
 *
 *
 */
void DrawPaneBorder(GLint x, GLint y, GLint h, GLint w)
{
   glDisable(GL_TEXTURE_2D);
   glColor3f(0.6, 0.6, 1.0);
   glPolygonMode(GL_FRONT, GL_LINE);
   glViewport(x, y, w, w);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(-0.5, w-0.5, -0.5, w-0.5, -1.0, 10.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();

   glBegin(GL_QUADS);
   glVertex2f(0, 0);
   glVertex2f(w-1, 0);
   glVertex2f(w-1, h-1);
   glVertex2f(0, h-1);
   glEnd();
}

/**
 *
 *
 */
int HandleEvent(SDL_Event *event, SDL_Surface *screen)
{
   int width, height;

   switch(event->type) {
      case SDL_VIDEORESIZE:
         screen = SDL_SetVideoMode(event->resize.w, event->resize.h, 16,
               SDL_OPENGL | SDL_RESIZABLE);
         if(screen) {
            ReshapeWindow(screen->w, screen->h);
         }
         else {
            /* Uh oh, we couldn't set the new video mode? */;
            return(1);
         }
         break;

      case SDL_QUIT:
         return(1);
         break;

      case SDL_MOUSEMOTION:
         view_rotx = ((event->motion.y-160)/2.0);
         view_roty = ((event->motion.x-160)/2.0);
         break;

      case SDL_KEYDOWN:
         switch(event->key.keysym.sym) {
            case SDLK_ESCAPE:
               return(1);
               break;
            default:
               break;
         }
         break;

      case SDL_MOUSEBUTTONDOWN:
         switch(event->button.button) {
            case SDL_BUTTON_RIGHT:
               free(texturePxl);
               texturePxl = (unsigned char *)loadTextureImage(&width, &height);
               break;
            case SDL_BUTTON_LEFT:
               fprintf(stdout, "left click\n");
               break;
            default:
               break;
         }
         break;
   }

   return(0);
}
Added jni/libdmtx/test/rotate_test/display.h.




































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file display.h
 */

#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>

GLfloat view_rotx, view_roty, view_rotz;
GLfloat angle;

GLuint   barcodeTexture;
GLint    barcodeList;

SDL_Surface *initDisplay(void);
void DrawBarCode(void);
void ReshapeWindow(int width, int height);
void DrawGeneratedImage(SDL_Surface *screen);
void DrawBorders(SDL_Surface *screen);
void DrawPane2(SDL_Surface *screen, unsigned char *pxl);
void DrawPane3(SDL_Surface *screen, unsigned char *pxl);
void DrawPane4(SDL_Surface *screen, unsigned char *pxl);
void DrawPane5(SDL_Surface *screen, unsigned char *pxl);
void DrawPane6(SDL_Surface *screen, unsigned char *pxl);
int HandleEvent(SDL_Event *event, SDL_Surface *screen);
void DrawPaneBorder(GLint x, GLint y, GLint h, GLint w);
Added jni/libdmtx/test/rotate_test/dmtx.c.














>
>
>
>
>
>
>
1
2
3
4
5
6
7
#define CALLBACK_POINT_PLOT(a,b,c,d) PlotPointCallback(a,b,c,d)
#define CALLBACK_POINT_XFRM(a,b,c,d) XfrmPlotPointCallback(a,b,c,d)
#define CALLBACK_MODULE(a,b,c,d,e)   PlotModuleCallback(a,b,c,d,e)
#define CALLBACK_MATRIX(a)           BuildMatrixCallback2(a)
#define CALLBACK_FINAL(a,b)          FinalCallback(a,b)

#include "../../dmtx.c"
Added jni/libdmtx/test/rotate_test/image.c.


















































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file image.c
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include <png.h>
#include "dmtx.h"
#include "rotate_test.h"
#include "image.h"

/**
 *
 *
 */
unsigned char *
loadTextureImage(int *width, int *height)
{
   unsigned char *pxl;
   int error;
   char filepath[128];

   strcpy(filepath, "images/");
   strcat(filepath, gFilename[gFileIdx]);
   fprintf(stdout, "Opening %s\n", filepath);

   pxl = loadPng(filepath, width, height);
   assert(pxl != NULL);

   gFileIdx++;
   if(gFileIdx == gFileCount)
      gFileIdx = 0;

   /* Set up texture */
   glGenTextures(1, &barcodeTexture);
   glBindTexture(GL_TEXTURE_2D, barcodeTexture);
   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

   /* Read barcode image */
   gluBuild2DMipmaps(GL_TEXTURE_2D, 3, *width, *height, GL_RGB, GL_UNSIGNED_BYTE, pxl);

   /* Create the barcode list */
   barcodeList = glGenLists(1);
   glNewList(barcodeList, GL_COMPILE);
   DrawBarCode();
   glEndList();

   return pxl;
}

/**
 *
 *
 */
unsigned char *
loadPng(char *filename, int *width, int *height)
{
   png_byte        pngHeader[8];
   FILE            *fp;
   int             headerTestSize = sizeof(pngHeader);
   int             isPng;
   int             bitDepth, color_type, interlace_type, compression_type, filter_method;
   int             row;
   png_uint_32     png_width, png_height;
   png_structp     png_ptr;
   png_infop       info_ptr;
   png_infop       end_info;
   png_bytepp      row_pointers;
   unsigned char   *pxl = NULL;

   fp = fopen(filename, "rb");
   if(!fp)
      return NULL;

   fread(pngHeader, 1, headerTestSize, fp);
   isPng = !png_sig_cmp(pngHeader, 0, headerTestSize);
   if(!isPng)
      return NULL;

   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

   if(!png_ptr)
      return NULL;

   info_ptr = png_create_info_struct(png_ptr);
   if(!info_ptr) {
      png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
      return NULL;
   }

   end_info = png_create_info_struct(png_ptr);
   if(!end_info) {
      png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
      return NULL;
   }

   if(setjmp(png_jmpbuf(png_ptr))) {
      png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
      fclose(fp);
      return NULL;
   }

   png_init_io(png_ptr, fp);
   png_set_sig_bytes(png_ptr, headerTestSize);

   png_read_info(png_ptr, info_ptr);
   png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bitDepth,
         &color_type, &interlace_type, &compression_type, &filter_method);

   png_set_strip_16(png_ptr);
   png_set_strip_alpha(png_ptr);
   png_set_packswap(png_ptr);

   if(color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_palette_to_rgb(png_ptr);

   if (color_type == PNG_COLOR_TYPE_GRAY || PNG_COLOR_TYPE_GRAY_ALPHA)
      png_set_gray_to_rgb(png_ptr);

   png_read_update_info(png_ptr, info_ptr);
   png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bitDepth,
         &color_type, &interlace_type, &compression_type, &filter_method);

   *width = (int)png_width;
   *height = (int)png_height;

   row_pointers = (png_bytepp)png_malloc(png_ptr, sizeof(png_bytep) * png_height);
   if(row_pointers == NULL) {
      fprintf(stdout, "Fatal error!\n"); fflush(stdout); /* XXX finish later */
      ; /* FatalError(1, "Error while during malloc for row_pointers"); */
   }

   for(row = 0; row < *height; row++) {
      row_pointers[row] = (png_bytep)png_malloc(png_ptr,
            png_get_rowbytes(png_ptr, info_ptr));
   }

   png_read_image(png_ptr, row_pointers);
   png_read_end(png_ptr, info_ptr);

   png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

   pxl = (unsigned char *)malloc((*width) * (*height) * 3);
   assert(pxl != NULL);

   for(row = 0; row < *height; row++) {
      memcpy(pxl + (row * (*width) * 3), row_pointers[(*height) - row - 1], (*width) * 3);
   }

   for(row = 0; row < (*height); row++) {
      png_free(png_ptr, row_pointers[row]);
   }
   png_free(png_ptr, row_pointers);

   fclose(fp);

   return pxl;
}

/**
 *
 *
 */
void plotPoint(DmtxImage *img, float rowFloat, float colFloat, int targetColor)
{
   int i, row, col;
   float xFloat, yFloat;
   int offset[4];
   int color[4];

   row = (int)rowFloat;
   col = (int)colFloat;

   xFloat = colFloat - col;
   yFloat = rowFloat - row;

   offset[0] = row * img->width + col;
   offset[1] = row * img->width + (col + 1);
   offset[2] = (row + 1) * img->width + col;
   offset[3] = (row + 1) * img->width + (col + 1);

   color[0] = clampRGB(255.0 * ((1.0 - xFloat) * (1.0 - yFloat)));
   color[1] = clampRGB(255.0 * (xFloat * (1.0 - yFloat)));
   color[2] = clampRGB(255.0 * ((1.0 - xFloat) * yFloat));
   color[3] = clampRGB(255.0 * (xFloat * yFloat));

   for(i = 0; i < 4; i++) {
      if((i == 1 || i== 3) && col + 1 > 319)
         continue;
      else if((i == 2 || i== 3) && row + 1 > 319)
         continue;

      if(targetColor & (ColorWhite | ColorRed | ColorYellow))
         img->pxl[offset[i]*3+0] = max(img->pxl[offset[i]*3+0], color[i]);

      if(targetColor & (ColorWhite | ColorGreen | ColorYellow))
         img->pxl[offset[i]*3+1] = max(img->pxl[offset[i]*3+1], color[i]);

      if(targetColor & (ColorWhite | ColorBlue))
         img->pxl[offset[i]*3+2] = max(img->pxl[offset[i]*3+2], color[i]);
   }
}

/**
 *
 *
 */
int clampRGB(float color)
{
   if(color < 0.0)
      return 0;
   else if(color > 255.0)
      return 255;
   else
      return (int)(color + 0.5);
}
Added jni/libdmtx/test/rotate_test/image.h.




































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file image.h
 */

#ifndef __IMAGE_H__
#define __IMAGE_H__

#define IMAGE_NO_ERROR  0
#define IMAGE_ERROR     1
#define IMAGE_NOT_PNG   2

typedef enum {
   ColorWhite  = 0x01 << 0,
   ColorRed    = 0x01 << 1,
   ColorGreen  = 0x01 << 2,
   ColorBlue   = 0x01 << 3,
   ColorYellow = 0x01 << 4
} ColorEnum;

/*void captureImage(DmtxImage *img, DmtxImage *imgTmp);*/
unsigned char *loadTextureImage(int *width, int *height);
unsigned char *loadPng(char *filename, int *width, int *height);
void plotPoint(DmtxImage *img, float rowFloat, float colFloat, int targetColor);
int clampRGB(float color);

#endif
Added jni/libdmtx/test/rotate_test/images/test_image01.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image02.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image03.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image04.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image05.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image06.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image07.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image08.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image09.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image10.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image11.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image12.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image13.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image14.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image15.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image16.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image17.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/images/test_image18.png.

cannot compute difference between binary files

Added jni/libdmtx/test/rotate_test/rotate_test.c.






























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file rotate_test.c
 */

#include "rotate_test.h"

#define MIN(x,y) ((x < y) ? x : y)
#define MAX(x,y) ((x > y) ? x : y)

GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0;
GLfloat angle = 0.0;

GLuint barcodeTexture;
GLint barcodeList;

DmtxImage *gImage = NULL;
unsigned char *capturePxl = NULL;
unsigned char *texturePxl = NULL;
unsigned char *passOnePxl = NULL;
unsigned char *passTwoPxl = NULL;

char *gFilename[] = { "test_image18.png"
                    , "test_image16.png"
                    , "test_image17.png"
                    , "test_image01.png"
                    , "test_image05.png"
                    , "test_image06.png"
                    , "test_image07.png"
                    , "test_image12.png"
                    , "test_image13.png"
                    , "test_image08.png"
                    , "test_image09.png"
                    , "test_image10.png"
                    , "test_image04.png"
                    , "test_image11.png"
                    , "test_image02.png"
                    , "test_image03.png"
                    , "test_image14.png"
                    , "test_image15.png" };
int gFileIdx = 0;
int gFileCount = 18;

/**
 *
 *
 */
int main(int argc, char *argv[])
{
   int             i;
   int             count;
   int             done;
   int             width, height;
   SDL_Event       event;
   SDL_Surface     *screen;
   unsigned char   outputString[1024];
   DmtxDecode      *dec;
   DmtxRegion      *reg;
   DmtxMessage     *msg;
   DmtxTime        timeout;

   /* Initialize display window */
   screen = initDisplay();

   /* Load input image to DmtxImage */
   texturePxl = loadTextureImage(&width, &height);
   assert(texturePxl != NULL);

   capturePxl = (unsigned char *)malloc(width * height * 3);
   assert(capturePxl != NULL);

   passOnePxl = (unsigned char *)malloc(width * height * 3);
   assert(passOnePxl != NULL);

   passTwoPxl = (unsigned char *)malloc(width * height * 3);
   assert(passTwoPxl != NULL);

   done = 0;
   while(!done) {

      SDL_Delay(50);

      while(SDL_PollEvent(&event))
         done = HandleEvent(&event, screen);

      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      DrawGeneratedImage(screen);

      memset(passOnePxl, 0x00, width * height * 3);
      memset(passTwoPxl, 0x00, width * height * 3);

      /* Capture screenshot of generated image */
      glReadPixels(2, 324, width, height, GL_RGB, GL_UNSIGNED_BYTE, capturePxl);
      gImage = dmtxImageCreate(capturePxl, width, height, DmtxPack24bppRGB);
      assert(gImage != NULL);

      /* Pixels from glReadPixels are Y-flipped according to libdmtx */
      dmtxImageSetProp(gImage, DmtxPropImageFlip, DmtxFlipY);

      /* Start fresh scan */
      dec = dmtxDecodeCreate(gImage, 1);
      assert(dec != NULL);

      for(;;) {
         timeout = dmtxTimeAdd(dmtxTimeNow(), 500);

         reg = dmtxRegionFindNext(dec, &timeout);
         if(reg != NULL) {
            msg = dmtxDecodeMatrixRegion(dec, reg, DmtxUndefined);
            if(msg != NULL) {
               fwrite(msg->output, sizeof(unsigned char), msg->outputIdx, stdout);
               fputc('\n', stdout);
               dmtxMessageDestroy(&msg);
            }
            dmtxRegionDestroy(&reg);
         }
         break;
      }

      dmtxDecodeDestroy(&dec);
      dmtxImageDestroy(&gImage);

      DrawBorders(screen);
/*    DrawPane2(screen, passOnePxl); */
/*    DrawPane4(screen, passTwoPxl); */

      SDL_GL_SwapBuffers();
   }

   free(passTwoPxl);
   free(passOnePxl);
   free(capturePxl);
   free(texturePxl);

   exit(0);
}
Added jni/libdmtx/test/rotate_test/rotate_test.h.
































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file rotate_test.h
 */

#ifndef __SCANDEMO_H__
#define __SCANDEMO_H__

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include "../../dmtx.h"
#include "image.h"
#include "display.h"
#include "callback.h"

#define max(X,Y) (X > Y) ? X : Y
#define min(X,Y) (X < Y) ? X : Y

extern GLfloat       view_rotx;
extern GLfloat       view_roty;
extern GLfloat       view_rotz;
extern GLfloat       angle;

extern GLuint        barcodeTexture;
extern GLint         barcodeList;

extern DmtxImage     *gImage;
extern unsigned char *capturePxl;
extern unsigned char *texturePxl;
extern unsigned char *passOnePxl;
extern unsigned char *passTwoPxl;

extern char *gFilename[];
extern int gFileIdx;
extern int gFileCount;

#endif
Added jni/libdmtx/test/simple_test/Makefile.am.
















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
AM_CPPFLAGS = -Wshadow -Wall -pedantic -ansi

check_PROGRAMS = simple_test

simple_test_SOURCES = simple_test.c
simple_test_LDFLAGS = -lm

LDADD = ../../libdmtx.la
Added jni/libdmtx/test/simple_test/simple_test.c.
























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file simple_test.c
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <dmtx.h>

int
main(int argc, char *argv[])
{
   size_t          width, height, bytesPerPixel;
   unsigned char   str[] = "30Q324343430794<OQQ";
   unsigned char  *pxl;
   DmtxEncode     *enc;
   DmtxImage      *img;
   DmtxDecode     *dec;
   DmtxRegion     *reg;
   DmtxMessage    *msg;

   fprintf(stdout, "input:  \"%s\"\n", str);

   /* 1) ENCODE a new Data Matrix barcode image (in memory only) */

   enc = dmtxEncodeCreate();
   assert(enc != NULL);
   dmtxEncodeDataMatrix(enc, strlen((const char *)str), str);

   /* 2) COPY the new image data before releasing encoding memory */

   width = dmtxImageGetProp(enc->image, DmtxPropWidth);
   height = dmtxImageGetProp(enc->image, DmtxPropHeight);
   bytesPerPixel = dmtxImageGetProp(enc->image, DmtxPropBytesPerPixel);

   pxl = (unsigned char *)malloc(width * height * bytesPerPixel);
   assert(pxl != NULL);
   memcpy(pxl, enc->image->pxl, width * height * bytesPerPixel);

   dmtxEncodeDestroy(&enc);

   /* 3) DECODE the Data Matrix barcode from the copied image */

   img = dmtxImageCreate(pxl, width, height, DmtxPack24bppRGB);
   assert(img != NULL);

   dec = dmtxDecodeCreate(img, 1);
   assert(dec != NULL);

   reg = dmtxRegionFindNext(dec, NULL);
   if(reg != NULL) {
      msg = dmtxDecodeMatrixRegion(dec, reg, DmtxUndefined);
      if(msg != NULL) {
         fputs("output: \"", stdout);
         fwrite(msg->output, sizeof(unsigned char), msg->outputIdx, stdout);
         fputs("\"\n", stdout);
         dmtxMessageDestroy(&msg);
      }
      dmtxRegionDestroy(&reg);
   }

   dmtxDecodeDestroy(&dec);
   dmtxImageDestroy(&img);
   free(pxl);

   exit(0);
}
Added jni/libdmtx/test/unit_test/Makefile.am.
















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
AM_CPPFLAGS = -Wshadow -Wall -pedantic -ansi

check_PROGRAMS = unit_test

unit_test_SOURCES = unit_test.c ../../util/common/dmtxutil.c ../../util/common/dmtxutil.h
unit_test_LDFLAGS = -lm

LDADD = ../../libdmtx.la
Added jni/libdmtx/test/unit_test/unit_test.c.












































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/**
 * libdmtx - Data Matrix Encoding/Decoding Library
 * Copyright 2007, 2008, 2009 Mike Laughton. All rights reserved.
 *
 * See LICENSE file in the main project directory for full
 * terms of use and distribution.
 *
 * Contact: Mike Laughton <mike@dragonflylogic.com>
 *
 * \file unit_test.c
 */

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../../dmtx.h"
#include "../../util/common/dmtxutil.h"

char *programName;

static void timeAddTest(void);
static void timePrint(DmtxTime t);

int
main(int argc, char *argv[])
{
   programName = argv[0];

   timeAddTest();

   exit(0);
}

/**
 *
 *
 */
static void
timePrint(DmtxTime t)
{
#ifdef _MSC_VER
   fprintf(stdout, "t.sec: %llu\n", t.sec);
#else
   fprintf(stdout, "t.sec: %lu\n", t.sec);
#endif

   fprintf(stdout, "t.usec: %lu\n", t.usec);
}

/**
 *
 *
 */
static void
timeAddTest(void)
{
   DmtxTime t0, t1;

   t0 = dmtxTimeNow();
   t0.usec = 999000;

   t1 = dmtxTimeAdd(t0, 0);
   if(memcmp(&t0, &t1, sizeof(DmtxTime)) != 0)
      FatalError(1, "timeAddTest\n");

   t1 = dmtxTimeAdd(t0, 1);
   if(memcmp(&t0, &t1, sizeof(DmtxTime)) == 0)
      FatalError(2, "timeAddTest\n");

   t1 = dmtxTimeAdd(t0, 1);
   if(t1.sec != t0.sec + 1 || t1.usec != 0) {
      timePrint(t0);
      timePrint(t1);
      FatalError(3, "timeAddTest\n");
   }

   t1 = dmtxTimeAdd(t0, 1001);
   if(t1.sec != t0.sec + 2 || t1.usec != 0) {
      timePrint(t0);
      timePrint(t1);
      FatalError(4, "timeAddTest\n");
   }

   t1 = dmtxTimeAdd(t0, 2002);
   if(t1.sec != t0.sec + 3 || t1.usec != 1000) {
      timePrint(t0);
      timePrint(t1);
      FatalError(5, "timeAddTest\n");
   }
}

/**
 *
 *
 */
/**
static void
TestRGB(void)
{
   unsigned char *pxl;
   FILE *fp;

   pxl = (unsigned char *)malloc(320 * 240 * 3);
   assert(pxl != NULL);

   fp = fopen("fruit_matrix.rgb", "rb");
   assert(fp != NULL);

   fread(ptr, 3, 320 * 240, fp);
   fclose(fp);

   dmtxImageCreate(ptr, 320, 240, DmtxPack24bppRGB);
}
*/
jni/tcl/unix/configure.in became a regular file.
jni/tcl/win/tclWinFile.c became executable.