summaryrefslogtreecommitdiffstats
path: root/zbar/qrcode/qrdec.c
diff options
context:
space:
mode:
Diffstat (limited to 'zbar/qrcode/qrdec.c')
-rw-r--r--zbar/qrcode/qrdec.c4395
1 files changed, 4395 insertions, 0 deletions
diff --git a/zbar/qrcode/qrdec.c b/zbar/qrcode/qrdec.c
new file mode 100644
index 0000000..e4c922c
--- /dev/null
+++ b/zbar/qrcode/qrdec.c
@@ -0,0 +1,4395 @@
+/*Copyright (C) 2008-2009 Timothy B. Terriberry (tterribe@xiph.org)
+ You can redistribute this library and/or modify it under the terms of the
+ GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 2.1 of the License, or (at your option) any later
+ version.*/
+
+#include "config.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "bch15_5.h"
+#include "binarize.h"
+#include "error.h"
+#include "image.h"
+#include "isaac.h"
+#include "qrcode.h"
+#include "rs.h"
+#include "svg.h"
+#include "util.h"
+
+#include "qrdec.h"
+
+typedef int qr_line[3];
+
+typedef struct qr_finder_cluster qr_finder_cluster;
+typedef struct qr_finder_edge_pt qr_finder_edge_pt;
+typedef struct qr_finder_center qr_finder_center;
+
+typedef struct qr_aff qr_aff;
+typedef struct qr_hom qr_hom;
+
+typedef struct qr_finder qr_finder;
+
+typedef struct qr_hom_cell qr_hom_cell;
+typedef struct qr_sampling_grid qr_sampling_grid;
+typedef struct qr_pack_buf qr_pack_buf;
+
+/*The number of bits in an int.
+ Note the cast to (int): this prevents this value from "promoting" whole
+ expressions to an (unsigned) size_t.*/
+#define QR_INT_BITS ((int)sizeof(int) * CHAR_BIT)
+#define QR_INT_LOGBITS (QR_ILOG(QR_INT_BITS))
+
+/*A 14 bit resolution for a homography ensures that the ideal module size for a
+ version 40 code differs from that of a version 39 code by at least 2.*/
+#define QR_HOM_BITS (14)
+
+/*The number of bits of sub-module precision to use when searching for
+ alignment patterns.
+ Two bits allows an alignment pattern to be found even if the modules have
+ been eroded by up to 50% (due to blurring, etc.).
+ This must be at least one, since it affects the dynamic range of the
+ transforms, and we sample at half-module resolution to compute a bounding
+ quadrilateral for the code.*/
+#define QR_ALIGN_SUBPREC (2)
+
+/* collection of finder lines */
+typedef struct qr_finder_lines {
+ qr_finder_line *lines;
+ int nlines, clines;
+} qr_finder_lines;
+
+struct qr_reader {
+ /*The GF(256) representation used in Reed-Solomon decoding.*/
+ rs_gf256 gf;
+ /*The random number generator used by RANSAC.*/
+ isaac_ctx isaac;
+ /* current finder state, horizontal and vertical lines */
+ qr_finder_lines finder_lines[2];
+};
+
+/*Initializes a client reader handle.*/
+static void qr_reader_init(qr_reader *reader)
+{
+ /*time_t now;
+ now=time(NULL);
+ isaac_init(&_reader->isaac,&now,sizeof(now));*/
+ isaac_init(&reader->isaac, NULL, 0);
+ rs_gf256_init(&reader->gf, QR_PPOLY);
+}
+
+/*Allocates a client reader handle.*/
+qr_reader *_zbar_qr_create(void)
+{
+ qr_reader *reader = (qr_reader *)calloc(1, sizeof(*reader));
+ qr_reader_init(reader);
+ return (reader);
+}
+
+/*Frees a client reader handle.*/
+void _zbar_qr_destroy(qr_reader *reader)
+{
+ zprintf(1, "max finder lines = %dx%d\n", reader->finder_lines[0].clines,
+ reader->finder_lines[1].clines);
+ if (reader->finder_lines[0].lines)
+ free(reader->finder_lines[0].lines);
+ if (reader->finder_lines[1].lines)
+ free(reader->finder_lines[1].lines);
+ free(reader);
+}
+
+/* reset finder state between scans */
+void _zbar_qr_reset(qr_reader *reader)
+{
+ reader->finder_lines[0].nlines = 0;
+ reader->finder_lines[1].nlines = 0;
+}
+
+/*A cluster of lines crossing a finder pattern (all in the same direction).*/
+struct qr_finder_cluster {
+ /*Pointers to the lines crossing the pattern.*/
+ qr_finder_line **lines;
+ /*The number of lines in the cluster.*/
+ int nlines;
+};
+
+/*A point on the edge of a finder pattern.
+ These are obtained from the endpoints of the lines crossing this particular
+ pattern.*/
+struct qr_finder_edge_pt {
+ /*The location of the edge point.*/
+ qr_point pos;
+ /*A label classifying which edge this belongs to:
+ 0: negative u edge (left)
+ 1: positive u edge (right)
+ 2: negative v edge (top)
+ 3: positive v edge (bottom)*/
+ int edge;
+ /*The (signed) perpendicular distance of the edge point from a line parallel
+ to the edge passing through the finder center, in (u,v) coordinates.
+ This is also re-used by RANSAC to store inlier flags.*/
+ int extent;
+};
+
+/*The center of a finder pattern obtained from the crossing of one or more
+ clusters of horizontal finder lines with one or more clusters of vertical
+ finder lines.*/
+struct qr_finder_center {
+ /*The estimated location of the finder center.*/
+ qr_point pos;
+ /*The list of edge points from the crossing lines.*/
+ qr_finder_edge_pt *edge_pts;
+ /*The number of edge points from the crossing lines.*/
+ int nedge_pts;
+};
+
+static int qr_finder_vline_cmp(const void *_a, const void *_b)
+{
+ const qr_finder_line *a;
+ const qr_finder_line *b;
+ a = (const qr_finder_line *)_a;
+ b = (const qr_finder_line *)_b;
+ return ((a->pos[0] > b->pos[0]) - (a->pos[0] < b->pos[0]) << 1) +
+ (a->pos[1] > b->pos[1]) - (a->pos[1] < b->pos[1]);
+}
+
+/*Clusters adjacent lines into groups that are large enough to be crossing a
+ finder pattern (relative to their length).
+ _clusters: The buffer in which to store the clusters found.
+ _neighbors: The buffer used to store the lists of lines in each cluster.
+ _lines: The list of lines to cluster.
+ Horizontal lines must be sorted in ascending order by Y
+ coordinate, with ties broken by X coordinate.
+ Vertical lines must be sorted in ascending order by X coordinate,
+ with ties broken by Y coordinate.
+ _nlines: The number of lines in the set of lines to cluster.
+ _v: 0 for horizontal lines, or 1 for vertical lines.
+ Return: The number of clusters.*/
+static int qr_finder_cluster_lines(qr_finder_cluster *_clusters,
+ qr_finder_line **_neighbors,
+ qr_finder_line *_lines, int _nlines, int _v)
+{
+ unsigned char *mark;
+ qr_finder_line **neighbors;
+ int nneighbors;
+ int nclusters;
+ int i;
+ /*TODO: Kalman filters!*/
+ mark = (unsigned char *)calloc(_nlines, sizeof(*mark));
+ neighbors = _neighbors;
+ nclusters = 0;
+ for (i = 0; i < _nlines - 1; i++)
+ if (!mark[i]) {
+ int len;
+ int j;
+ nneighbors = 1;
+ neighbors[0] = _lines + i;
+ len = _lines[i].len;
+ for (j = i + 1; j < _nlines; j++)
+ if (!mark[j]) {
+ const qr_finder_line *a;
+ const qr_finder_line *b;
+ int thresh;
+ a = neighbors[nneighbors - 1];
+ b = _lines + j;
+ /*The clustering threshold is proportional to the size of the lines,
+ since minor noise in large areas can interrupt patterns more easily
+ at high resolutions.*/
+ thresh = a->len + 7 >> 2;
+ if (abs(a->pos[1 - _v] - b->pos[1 - _v]) > thresh)
+ break;
+ if (abs(a->pos[_v] - b->pos[_v]) > thresh)
+ continue;
+ if (abs(a->pos[_v] + a->len - b->pos[_v] - b->len) > thresh)
+ continue;
+ if (a->boffs > 0 && b->boffs > 0 &&
+ abs(a->pos[_v] - a->boffs - b->pos[_v] + b->boffs) >
+ thresh) {
+ continue;
+ }
+ if (a->eoffs > 0 && b->eoffs > 0 &&
+ abs(a->pos[_v] + a->len + a->eoffs - b->pos[_v] -
+ b->len - b->eoffs) > thresh) {
+ continue;
+ }
+ neighbors[nneighbors++] = _lines + j;
+ len += b->len;
+ }
+ /*We require at least three lines to form a cluster, which eliminates a
+ large number of false positives, saving considerable decoding time.
+ This should still be sufficient for 1-pixel codes with no noise.*/
+ if (nneighbors < 3)
+ continue;
+ /*The expected number of lines crossing a finder pattern is equal to their
+ average length.
+ We accept the cluster if size is at least 1/3 their average length (this
+ is a very small threshold, but was needed for some test images).*/
+ len = ((len << 1) + nneighbors) / (nneighbors << 1);
+ if (nneighbors * (5 << QR_FINDER_SUBPREC) >= len) {
+ _clusters[nclusters].lines = neighbors;
+ _clusters[nclusters].nlines = nneighbors;
+ for (j = 0; j < nneighbors; j++)
+ mark[neighbors[j] - _lines] = 1;
+ neighbors += nneighbors;
+ nclusters++;
+ }
+ }
+ free(mark);
+ return nclusters;
+}
+
+/*Adds the coordinates of the edge points from the lines contained in the
+ given list of clusters to the list of edge points for a finder center.
+ Only the edge point position is initialized.
+ The edge label and extent are set by qr_finder_edge_pts_aff_classify()
+ or qr_finder_edge_pts_hom_classify().
+ _edge_pts: The buffer in which to store the edge points.
+ _nedge_pts: The current number of edge points in the buffer.
+ _neighbors: The list of lines in the cluster.
+ _nneighbors: The number of lines in the list of lines in the cluster.
+ _v: 0 for horizontal lines and 1 for vertical lines.
+ Return: The new total number of edge points.*/
+static int qr_finder_edge_pts_fill(qr_finder_edge_pt *_edge_pts, int _nedge_pts,
+ qr_finder_cluster **_neighbors,
+ int _nneighbors, int _v)
+{
+ int i;
+ for (i = 0; i < _nneighbors; i++) {
+ qr_finder_cluster *c;
+ int j;
+ c = _neighbors[i];
+ for (j = 0; j < c->nlines; j++) {
+ qr_finder_line *l;
+ l = c->lines[j];
+ if (l->boffs > 0) {
+ _edge_pts[_nedge_pts].pos[0] = l->pos[0];
+ _edge_pts[_nedge_pts].pos[1] = l->pos[1];
+ _edge_pts[_nedge_pts].pos[_v] -= l->boffs;
+ _nedge_pts++;
+ }
+ if (l->eoffs > 0) {
+ _edge_pts[_nedge_pts].pos[0] = l->pos[0];
+ _edge_pts[_nedge_pts].pos[1] = l->pos[1];
+ _edge_pts[_nedge_pts].pos[_v] += l->len + l->eoffs;
+ _nedge_pts++;
+ }
+ }
+ }
+ return _nedge_pts;
+}
+
+static int qr_finder_center_cmp(const void *_a, const void *_b)
+{
+ const qr_finder_center *a;
+ const qr_finder_center *b;
+ a = (const qr_finder_center *)_a;
+ b = (const qr_finder_center *)_b;
+ return ((b->nedge_pts > a->nedge_pts) - (b->nedge_pts < a->nedge_pts)
+ << 2) +
+ ((a->pos[1] > b->pos[1]) - (a->pos[1] < b->pos[1]) << 1) +
+ (a->pos[0] > b->pos[0]) - (a->pos[0] < b->pos[0]);
+}
+
+/*Determine if a horizontal line crosses a vertical line.
+ _hline: The horizontal line.
+ _vline: The vertical line.
+ Return: A non-zero value if the lines cross, or zero if they do not.*/
+static int qr_finder_lines_are_crossing(const qr_finder_line *_hline,
+ const qr_finder_line *_vline)
+{
+ return _hline->pos[0] <= _vline->pos[0] &&
+ _vline->pos[0] < _hline->pos[0] + _hline->len &&
+ _vline->pos[1] <= _hline->pos[1] &&
+ _hline->pos[1] < _vline->pos[1] + _vline->len;
+}
+
+/*Finds horizontal clusters that cross corresponding vertical clusters,
+ presumably corresponding to a finder center.
+ _center: The buffer in which to store putative finder centers.
+ _edge_pts: The buffer to use for the edge point lists for each finder
+ center.
+ _hclusters: The clusters of horizontal lines crossing finder patterns.
+ _nhclusters: The number of horizontal line clusters.
+ _vclusters: The clusters of vertical lines crossing finder patterns.
+ _nvclusters: The number of vertical line clusters.
+ Return: The number of putative finder centers.*/
+static int qr_finder_find_crossings(qr_finder_center *_centers,
+ qr_finder_edge_pt *_edge_pts,
+ qr_finder_cluster *_hclusters,
+ int _nhclusters,
+ qr_finder_cluster *_vclusters,
+ int _nvclusters)
+{
+ qr_finder_cluster **hneighbors;
+ qr_finder_cluster **vneighbors;
+ unsigned char *hmark;
+ unsigned char *vmark;
+ int ncenters;
+ int i;
+ int j;
+ hneighbors =
+ (qr_finder_cluster **)malloc(_nhclusters * sizeof(*hneighbors));
+ vneighbors =
+ (qr_finder_cluster **)malloc(_nvclusters * sizeof(*vneighbors));
+ hmark = (unsigned char *)calloc(_nhclusters, sizeof(*hmark));
+ vmark = (unsigned char *)calloc(_nvclusters, sizeof(*vmark));
+ ncenters = 0;
+ /*TODO: This may need some re-working.
+ We should be finding groups of clusters such that _all_ horizontal lines in
+ _all_ horizontal clusters in the group cross _all_ vertical lines in _all_
+ vertical clusters in the group.
+ This is equivalent to finding the maximum bipartite clique in the
+ connectivity graph, which requires linear progamming to solve efficiently.
+ In principle, that is easy to do, but a realistic implementation without
+ floating point is a lot of work (and computationally expensive).
+ Right now we are relying on a sufficient border around the finder patterns
+ to prevent false positives.*/
+ for (i = 0; i < _nhclusters; i++)
+ if (!hmark[i]) {
+ qr_finder_line *a;
+ qr_finder_line *b;
+ int nvneighbors;
+ int nedge_pts;
+ int y;
+ a = _hclusters[i].lines[_hclusters[i].nlines >> 1];
+ y = nvneighbors = 0;
+ for (j = 0; j < _nvclusters; j++)
+ if (!vmark[j]) {
+ b = _vclusters[j].lines[_vclusters[j].nlines >> 1];
+ if (qr_finder_lines_are_crossing(a, b)) {
+ vmark[j] = 1;
+ y += (b->pos[1] << 1) + b->len;
+ if (b->boffs > 0 && b->eoffs > 0)
+ y += b->eoffs - b->boffs;
+ vneighbors[nvneighbors++] = _vclusters + j;
+ }
+ }
+ if (nvneighbors > 0) {
+ qr_finder_center *c;
+ int nhneighbors;
+ int x;
+ x = (a->pos[0] << 1) + a->len;
+ if (a->boffs > 0 && a->eoffs > 0)
+ x += a->eoffs - a->boffs;
+ hneighbors[0] = _hclusters + i;
+ nhneighbors = 1;
+ j = nvneighbors >> 1;
+ b = vneighbors[j]->lines[vneighbors[j]->nlines >> 1];
+ for (j = i + 1; j < _nhclusters; j++)
+ if (!hmark[j]) {
+ a = _hclusters[j].lines[_hclusters[j].nlines >> 1];
+ if (qr_finder_lines_are_crossing(a, b)) {
+ hmark[j] = 1;
+ x += (a->pos[0] << 1) + a->len;
+ if (a->boffs > 0 && a->eoffs > 0)
+ x += a->eoffs - a->boffs;
+ hneighbors[nhneighbors++] = _hclusters + j;
+ }
+ }
+ c = _centers + ncenters++;
+ c->pos[0] = (x + nhneighbors) / (nhneighbors << 1);
+ c->pos[1] = (y + nvneighbors) / (nvneighbors << 1);
+ c->edge_pts = _edge_pts;
+ nedge_pts = qr_finder_edge_pts_fill(_edge_pts, 0, hneighbors,
+ nhneighbors, 0);
+ nedge_pts = qr_finder_edge_pts_fill(_edge_pts, nedge_pts,
+ vneighbors, nvneighbors, 1);
+ c->nedge_pts = nedge_pts;
+ _edge_pts += nedge_pts;
+ }
+ }
+ free(vmark);
+ free(hmark);
+ free(vneighbors);
+ free(hneighbors);
+ /*Sort the centers by decreasing numbers of edge points.*/
+ qsort(_centers, ncenters, sizeof(*_centers), qr_finder_center_cmp);
+ return ncenters;
+}
+
+/*Locates a set of putative finder centers in the image.
+ First we search for horizontal and vertical lines that have
+ (dark:light:dark:light:dark) runs with size ratios of roughly (1:1:3:1:1).
+ Then we cluster them into groups such that each subsequent pair of endpoints
+ is close to the line before it in the cluster.
+ This will locate many line clusters that don't cross a finder pattern, but
+ qr_finder_find_crossings() will filter most of them out.
+ Where horizontal and vertical clusters cross, a prospective finder center is
+ returned.
+ _centers: Returns a pointer to a freshly-allocated list of finder centers.
+ This must be freed by the caller.
+ _edge_pts: Returns a pointer to a freshly-allocated list of edge points
+ around those centers.
+ This must be freed by the caller.
+ _img: The binary image to search.
+ _width: The width of the image.
+ _height: The height of the image.
+ Return: The number of putative finder centers located.*/
+static int qr_finder_centers_locate(qr_finder_center **_centers,
+ qr_finder_edge_pt **_edge_pts,
+ qr_reader *reader, int _width, int _height)
+{
+ qr_finder_line *hlines = reader->finder_lines[0].lines;
+ int nhlines = reader->finder_lines[0].nlines;
+ qr_finder_line *vlines = reader->finder_lines[1].lines;
+ int nvlines = reader->finder_lines[1].nlines;
+
+ qr_finder_line **hneighbors;
+ qr_finder_cluster *hclusters;
+ int nhclusters;
+ qr_finder_line **vneighbors;
+ qr_finder_cluster *vclusters;
+ int nvclusters;
+ int ncenters;
+
+ /*Cluster the detected lines.*/
+ hneighbors = (qr_finder_line **)malloc(nhlines * sizeof(*hneighbors));
+ /*We require more than one line per cluster, so there are at most nhlines/2.*/
+ hclusters =
+ (qr_finder_cluster *)malloc((nhlines >> 1) * sizeof(*hclusters));
+ nhclusters =
+ qr_finder_cluster_lines(hclusters, hneighbors, hlines, nhlines, 0);
+ /*We need vertical lines to be sorted by X coordinate, with ties broken by Y
+ coordinate, for clustering purposes.
+ We scan the image in the opposite order for cache efficiency, so sort the
+ lines we found here.*/
+ qsort(vlines, nvlines, sizeof(*vlines), qr_finder_vline_cmp);
+ vneighbors = (qr_finder_line **)malloc(nvlines * sizeof(*vneighbors));
+ /*We require more than one line per cluster, so there are at most nvlines/2.*/
+ vclusters =
+ (qr_finder_cluster *)malloc((nvlines >> 1) * sizeof(*vclusters));
+ nvclusters =
+ qr_finder_cluster_lines(vclusters, vneighbors, vlines, nvlines, 1);
+ /*Find line crossings among the clusters.*/
+ if (nhclusters >= 3 && nvclusters >= 3) {
+ qr_finder_edge_pt *edge_pts;
+ qr_finder_center *centers;
+ int nedge_pts;
+ int i;
+ nedge_pts = 0;
+ for (i = 0; i < nhclusters; i++)
+ nedge_pts += hclusters[i].nlines;
+ for (i = 0; i < nvclusters; i++)
+ nedge_pts += vclusters[i].nlines;
+ nedge_pts <<= 1;
+ edge_pts = (qr_finder_edge_pt *)malloc(nedge_pts * sizeof(*edge_pts));
+ centers = (qr_finder_center *)malloc(QR_MINI(nhclusters, nvclusters) *
+ sizeof(*centers));
+ ncenters = qr_finder_find_crossings(centers, edge_pts, hclusters,
+ nhclusters, vclusters, nvclusters);
+ *_centers = centers;
+ *_edge_pts = edge_pts;
+ } else
+ ncenters = 0;
+ free(vclusters);
+ free(vneighbors);
+ free(hclusters);
+ free(hneighbors);
+ return ncenters;
+}
+
+static void qr_point_translate(qr_point _point, int _dx, int _dy)
+{
+ _point[0] += _dx;
+ _point[1] += _dy;
+}
+
+static unsigned qr_point_distance2(const qr_point _p1, const qr_point _p2)
+{
+ return (_p1[0] - _p2[0]) * (_p1[0] - _p2[0]) +
+ (_p1[1] - _p2[1]) * (_p1[1] - _p2[1]);
+}
+
+/*Returns the cross product of the three points, which is positive if they are
+ in CCW order (in a right-handed coordinate system), and 0 if they're
+ colinear.*/
+static int qr_point_ccw(const qr_point _p0, const qr_point _p1,
+ const qr_point _p2)
+{
+ return (_p1[0] - _p0[0]) * (_p2[1] - _p0[1]) -
+ (_p1[1] - _p0[1]) * (_p2[0] - _p0[0]);
+}
+
+/*Evaluates a line equation at a point.
+ _line: The line to evaluate.
+ _x: The X coordinate of the point.
+ _y: The y coordinate of the point.
+ Return: The value of the line equation _line[0]*_x+_line[1]*_y+_line[2].*/
+static int qr_line_eval(qr_line _line, int _x, int _y)
+{
+ return _line[0] * _x + _line[1] * _y + _line[2];
+}
+
+/*Computes a line passing through the given point using the specified second
+ order statistics.
+ Given a line defined by the equation
+ A*x+B*y+C = 0 ,
+ the least squares fit to n points (x_i,y_i) must satisfy the two equations
+ A^2 + (Syy - Sxx)/Sxy*A*B - B^2 = 0 ,
+ C = -(xbar*A+ybar*B) ,
+ where
+ xbar = sum(x_i)/n ,
+ ybar = sum(y_i)/n ,
+ Sxx = sum((x_i-xbar)**2) ,
+ Sxy = sum((x_i-xbar)*(y_i-ybar)) ,
+ Syy = sum((y_i-ybar)**2) .
+ The quadratic can be solved for the ratio (A/B) or (B/A):
+ A/B = (Syy + sqrt((Sxx-Syy)**2 + 4*Sxy**2) - Sxx)/(-2*Sxy) ,
+ B/A = (Sxx + sqrt((Sxx-Syy)**2 + 4*Sxy**2) - Syy)/(-2*Sxy) .
+ We pick the one that leads to the larger ratio to avoid destructive
+ cancellation (and e.g., 0/0 for horizontal or vertical lines).
+ The above solutions correspond to the actual minimum.
+ The other solution of the quadratic corresponds to a saddle point of the
+ least squares objective function.
+ _l: Returns the fitted line values A, B, and C.
+ _x0: The X coordinate of the point the line is supposed to pass through.
+ _y0: The Y coordinate of the point the line is supposed to pass through.
+ _sxx: The sum Sxx.
+ _sxy: The sum Sxy.
+ _syy: The sum Syy.
+ _res: The maximum number of bits occupied by the product of any two of
+ _l[0] or _l[1].
+ Smaller numbers give less angular resolution, but allow more overhead
+ room for computations.*/
+static void qr_line_fit(qr_line _l, int _x0, int _y0, int _sxx, int _sxy,
+ int _syy, int _res)
+{
+ int dshift;
+ int dround;
+ int u;
+ int v;
+ int w;
+ u = abs(_sxx - _syy);
+ v = -_sxy << 1;
+ w = qr_ihypot(u, v);
+ /*Computations in later stages can easily overflow with moderate sizes, so we
+ compute a shift factor to scale things down into a manageable range.
+ We ensure that the product of any two of _l[0] and _l[1] fits within _res
+ bits, which allows computation of line intersections without overflow.*/
+ dshift =
+ QR_MAXI(0, QR_MAXI(qr_ilog(u), qr_ilog(abs(v))) + 1 - (_res + 1 >> 1));
+ dround = (1 << dshift) >> 1;
+ if (_sxx > _syy) {
+ _l[0] = v + dround >> dshift;
+ _l[1] = u + w + dround >> dshift;
+ } else {
+ _l[0] = u + w + dround >> dshift;
+ _l[1] = v + dround >> dshift;
+ }
+ _l[2] = -(_x0 * _l[0] + _y0 * _l[1]);
+}
+
+/*Perform a least-squares line fit to a list of points.
+ At least two points are required.*/
+static void qr_line_fit_points(qr_line _l, qr_point *_p, int _np, int _res)
+{
+ int sx;
+ int sy;
+ int xmin;
+ int xmax;
+ int ymin;
+ int ymax;
+ int xbar;
+ int ybar;
+ int dx;
+ int dy;
+ int sxx;
+ int sxy;
+ int syy;
+ int sshift;
+ int sround;
+ int i;
+ sx = sy = 0;
+ ymax = xmax = INT_MIN;
+ ymin = xmin = INT_MAX;
+ for (i = 0; i < _np; i++) {
+ sx += _p[i][0];
+ xmin = QR_MINI(xmin, _p[i][0]);
+ xmax = QR_MAXI(xmax, _p[i][0]);
+ sy += _p[i][1];
+ ymin = QR_MINI(ymin, _p[i][1]);
+ ymax = QR_MAXI(ymax, _p[i][1]);
+ }
+ xbar = (sx + (_np >> 1)) / _np;
+ ybar = (sy + (_np >> 1)) / _np;
+ sshift =
+ QR_MAXI(0, qr_ilog(_np * QR_MAXI(QR_MAXI(xmax - xbar, xbar - xmin),
+ QR_MAXI(ymax - ybar, ybar - ymin))) -
+ (QR_INT_BITS - 1 >> 1));
+ sround = (1 << sshift) >> 1;
+ sxx = sxy = syy = 0;
+ for (i = 0; i < _np; i++) {
+ dx = _p[i][0] - xbar + sround >> sshift;
+ dy = _p[i][1] - ybar + sround >> sshift;
+ sxx += dx * dx;
+ sxy += dx * dy;
+ syy += dy * dy;
+ }
+ qr_line_fit(_l, xbar, ybar, sxx, sxy, syy, _res);
+}
+
+static void qr_line_orient(qr_line _l, int _x, int _y)
+{
+ if (qr_line_eval(_l, _x, _y) < 0) {
+ _l[0] = -_l[0];
+ _l[1] = -_l[1];
+ _l[2] = -_l[2];
+ }
+}
+
+static int qr_line_isect(qr_point _p, const qr_line _l0, const qr_line _l1)
+{
+ int d;
+ int x;
+ int y;
+ d = _l0[0] * _l1[1] - _l0[1] * _l1[0];
+ if (d == 0)
+ return -1;
+ x = _l0[1] * _l1[2] - _l1[1] * _l0[2];
+ y = _l1[0] * _l0[2] - _l0[0] * _l1[2];
+ if (d < 0) {
+ x = -x;
+ y = -y;
+ d = -d;
+ }
+ _p[0] = QR_DIVROUND(x, d);
+ _p[1] = QR_DIVROUND(y, d);
+ return 0;
+}
+
+/*An affine homography.
+ This maps from the image (at subpel resolution) to a square domain with
+ power-of-two sides (of res bits) and back.*/
+struct qr_aff {
+ int fwd[2][2];
+ int inv[2][2];
+ int x0;
+ int y0;
+ int res;
+ int ires;
+};
+
+static void qr_aff_init(qr_aff *_aff, const qr_point _p0, const qr_point _p1,
+ const qr_point _p2, int _res)
+{
+ int det;
+ int ires;
+ int dx1;
+ int dy1;
+ int dx2;
+ int dy2;
+ /*det is ensured to be positive by our caller.*/
+ dx1 = _p1[0] - _p0[0];
+ dx2 = _p2[0] - _p0[0];
+ dy1 = _p1[1] - _p0[1];
+ dy2 = _p2[1] - _p0[1];
+ det = dx1 * dy2 - dy1 * dx2;
+ ires = QR_MAXI((qr_ilog(abs(det)) >> 1) - 2, 0);
+ _aff->fwd[0][0] = dx1;
+ _aff->fwd[0][1] = dx2;
+ _aff->fwd[1][0] = dy1;
+ _aff->fwd[1][1] = dy2;
+ _aff->inv[0][0] = QR_DIVROUND(dy2 << _res, det >> ires);
+ _aff->inv[0][1] = QR_DIVROUND(-dx2 << _res, det >> ires);
+ _aff->inv[1][0] = QR_DIVROUND(-dy1 << _res, det >> ires);
+ _aff->inv[1][1] = QR_DIVROUND(dx1 << _res, det >> ires);
+ _aff->x0 = _p0[0];
+ _aff->y0 = _p0[1];
+ _aff->res = _res;
+ _aff->ires = ires;
+}
+
+/*Map from the image (at subpel resolution) into the square domain.*/
+static void qr_aff_unproject(qr_point _q, const qr_aff *_aff, int _x, int _y)
+{
+ _q[0] = _aff->inv[0][0] * (_x - _aff->x0) +
+ _aff->inv[0][1] * (_y - _aff->y0) + (1 << _aff->ires >> 1) >>
+ _aff->ires;
+ _q[1] = _aff->inv[1][0] * (_x - _aff->x0) +
+ _aff->inv[1][1] * (_y - _aff->y0) + (1 << _aff->ires >> 1) >>
+ _aff->ires;
+}
+
+/*Map from the square domain into the image (at subpel resolution).*/
+static void qr_aff_project(qr_point _p, const qr_aff *_aff, int _u, int _v)
+{
+ _p[0] =
+ (_aff->fwd[0][0] * _u + _aff->fwd[0][1] * _v + (1 << _aff->res - 1) >>
+ _aff->res) +
+ _aff->x0;
+ _p[1] =
+ (_aff->fwd[1][0] * _u + _aff->fwd[1][1] * _v + (1 << _aff->res - 1) >>
+ _aff->res) +
+ _aff->y0;
+}
+
+/*A full homography.
+ Like the affine homography, this maps from the image (at subpel resolution)
+ to a square domain with power-of-two sides (of res bits) and back.*/
+struct qr_hom {
+ int fwd[3][2];
+ int inv[3][2];
+ int fwd22;
+ int inv22;
+ int x0;
+ int y0;
+ int res;
+};
+
+static void qr_hom_init(qr_hom *_hom, int _x0, int _y0, int _x1, int _y1,
+ int _x2, int _y2, int _x3, int _y3, int _res)
+{
+ int dx10;
+ int dx20;
+ int dx30;
+ int dx31;
+ int dx32;
+ int dy10;
+ int dy20;
+ int dy30;
+ int dy31;
+ int dy32;
+ int a20;
+ int a21;
+ int a22;
+ int b0;
+ int b1;
+ int b2;
+ int s1;
+ int s2;
+ int r1;
+ int r2;
+ dx10 = _x1 - _x0;
+ dx20 = _x2 - _x0;
+ dx30 = _x3 - _x0;
+ dx31 = _x3 - _x1;
+ dx32 = _x3 - _x2;
+ dy10 = _y1 - _y0;
+ dy20 = _y2 - _y0;
+ dy30 = _y3 - _y0;
+ dy31 = _y3 - _y1;
+ dy32 = _y3 - _y2;
+ a20 = dx32 * dy10 - dx10 * dy32;
+ a21 = dx20 * dy31 - dx31 * dy20;
+ a22 = dx32 * dy31 - dx31 * dy32;
+ /*Figure out if we need to downscale anything.*/
+ b0 = qr_ilog(QR_MAXI(abs(dx10), abs(dy10))) + qr_ilog(abs(a20 + a22));
+ b1 = qr_ilog(QR_MAXI(abs(dx20), abs(dy20))) + qr_ilog(abs(a21 + a22));
+ b2 = qr_ilog(QR_MAXI(QR_MAXI(abs(a20), abs(a21)), abs(a22)));
+ s1 = QR_MAXI(0, _res + QR_MAXI(QR_MAXI(b0, b1), b2) - (QR_INT_BITS - 2));
+ r1 = (1 << s1) >> 1;
+ /*Compute the final coefficients of the forward transform.
+ The 32x32->64 bit multiplies are really needed for accuracy with large
+ versions.*/
+ _hom->fwd[0][0] = QR_FIXMUL(dx10, a20 + a22, r1, s1);
+ _hom->fwd[0][1] = QR_FIXMUL(dx20, a21 + a22, r1, s1);
+ _hom->x0 = _x0;
+ _hom->fwd[1][0] = QR_FIXMUL(dy10, a20 + a22, r1, s1);
+ _hom->fwd[1][1] = QR_FIXMUL(dy20, a21 + a22, r1, s1);
+ _hom->y0 = _y0;
+ _hom->fwd[2][0] = a20 + r1 >> s1;
+ _hom->fwd[2][1] = a21 + r1 >> s1;
+ _hom->fwd22 = s1 > _res ? a22 + (r1 >> _res) >> s1 - _res :
+ a22 << _res - s1;
+ /*Now compute the inverse transform.*/
+ b0 = qr_ilog(QR_MAXI(QR_MAXI(abs(dx10), abs(dx20)), abs(dx30))) +
+ qr_ilog(QR_MAXI(abs(_hom->fwd[0][0]), abs(_hom->fwd[1][0])));
+ b1 = qr_ilog(QR_MAXI(QR_MAXI(abs(dy10), abs(dy20)), abs(dy30))) +
+ qr_ilog(QR_MAXI(abs(_hom->fwd[0][1]), abs(_hom->fwd[1][1])));
+ b2 = qr_ilog(abs(a22)) - s1;
+ s2 = QR_MAXI(0, QR_MAXI(b0, b1) + b2 - (QR_INT_BITS - 3));
+ r2 = (1 << s2) >> 1;
+ s1 += s2;
+ r1 <<= s2;
+ /*The 32x32->64 bit multiplies are really needed for accuracy with large
+ versions.*/
+ _hom->inv[0][0] = QR_FIXMUL(_hom->fwd[1][1], a22, r1, s1);
+ _hom->inv[0][1] = QR_FIXMUL(-_hom->fwd[0][1], a22, r1, s1);
+ _hom->inv[1][0] = QR_FIXMUL(-_hom->fwd[1][0], a22, r1, s1);
+ _hom->inv[1][1] = QR_FIXMUL(_hom->fwd[0][0], a22, r1, s1);
+ _hom->inv[2][0] =
+ QR_FIXMUL(_hom->fwd[1][0], _hom->fwd[2][1],
+ -QR_EXTMUL(_hom->fwd[1][1], _hom->fwd[2][0], r2), s2);
+ _hom->inv[2][1] =
+ QR_FIXMUL(_hom->fwd[0][1], _hom->fwd[2][0],
+ -QR_EXTMUL(_hom->fwd[0][0], _hom->fwd[2][1], r2), s2);
+ _hom->inv22 = QR_FIXMUL(_hom->fwd[0][0], _hom->fwd[1][1],
+ -QR_EXTMUL(_hom->fwd[0][1], _hom->fwd[1][0], r2),
+ s2);
+ _hom->res = _res;
+}
+
+/*Map from the image (at subpel resolution) into the square domain.
+ Returns a negative value if the point went to infinity.*/
+static int qr_hom_unproject(qr_point _q, const qr_hom *_hom, int _x, int _y)
+{
+ int x;
+ int y;
+ int w;
+ _x -= _hom->x0;
+ _y -= _hom->y0;
+ x = _hom->inv[0][0] * _x + _hom->inv[0][1] * _y;
+ y = _hom->inv[1][0] * _x + _hom->inv[1][1] * _y;
+ w = _hom->inv[2][0] * _x + _hom->inv[2][1] * _y + _hom->inv22 +
+ (1 << _hom->res - 1) >>
+ _hom->res;
+ if (w == 0) {
+ _q[0] = x < 0 ? INT_MIN : INT_MAX;
+ _q[1] = y < 0 ? INT_MIN : INT_MAX;
+ return -1;
+ } else {
+ if (w < 0) {
+ x = -x;
+ y = -y;
+ w = -w;
+ }
+ _q[0] = QR_DIVROUND(x, w);
+ _q[1] = QR_DIVROUND(y, w);
+ }
+ return 0;
+}
+
+/*Finish a partial projection, converting from homogeneous coordinates to the
+ normal 2-D representation.
+ In loops, we can avoid many multiplies by computing the homogeneous _x, _y,
+ and _w incrementally, but we cannot avoid the divisions, done here.*/
+static void qr_hom_fproject(qr_point _p, const qr_hom *_hom, int _x, int _y,
+ int _w)
+{
+ if (_w == 0) {
+ _p[0] = _x < 0 ? INT_MIN : INT_MAX;
+ _p[1] = _y < 0 ? INT_MIN : INT_MAX;
+ } else {
+ if (_w < 0) {
+ _x = -_x;
+ _y = -_y;
+ _w = -_w;
+ }
+ _p[0] = QR_DIVROUND(_x, _w) + _hom->x0;
+ _p[1] = QR_DIVROUND(_y, _w) + _hom->y0;
+ }
+}
+
+#if defined(QR_DEBUG)
+/*Map from the square domain into the image (at subpel resolution).
+ Currently only used directly by debug code.*/
+static void qr_hom_project(qr_point _p, const qr_hom *_hom, int _u, int _v)
+{
+ qr_hom_fproject(_p, _hom, _hom->fwd[0][0] * _u + _hom->fwd[0][1] * _v,
+ _hom->fwd[1][0] * _u + _hom->fwd[1][1] * _v,
+ _hom->fwd[2][0] * _u + _hom->fwd[2][1] * _v + _hom->fwd22);
+}
+#endif
+
+/*All the information we've collected about a finder pattern in the current
+ configuration.*/
+struct qr_finder {
+ /*The module size along each axis (in the square domain).*/
+ int size[2];
+ /*The version estimated from the module size along each axis.*/
+ int eversion[2];
+ /*The list of classified edge points for each edge.*/
+ qr_finder_edge_pt *edge_pts[4];
+ /*The number of edge points classified as belonging to each edge.*/
+ int nedge_pts[4];
+ /*The number of inliers found after running RANSAC on each edge.*/
+ int ninliers[4];
+ /*The center of the finder pattern (in the square domain).*/
+ qr_point o;
+ /*The finder center information from the original image.*/
+ qr_finder_center *c;
+};
+
+static int qr_cmp_edge_pt(const void *_a, const void *_b)
+{
+ const qr_finder_edge_pt *a;
+ const qr_finder_edge_pt *b;
+ a = (const qr_finder_edge_pt *)_a;
+ b = (const qr_finder_edge_pt *)_b;
+ return ((a->edge > b->edge) - (a->edge < b->edge) << 1) +
+ (a->extent > b->extent) - (a->extent < b->extent);
+}
+
+/*Computes the index of the edge each edge point belongs to, and its (signed)
+ distance along the corresponding axis from the center of the finder pattern
+ (in the square domain).
+ The resulting list of edge points is sorted by edge index, with ties broken
+ by extent.*/
+static void qr_finder_edge_pts_aff_classify(qr_finder *_f, const qr_aff *_aff)
+{
+ qr_finder_center *c;
+ int i;
+ int e;
+ c = _f->c;
+ for (e = 0; e < 4; e++)
+ _f->nedge_pts[e] = 0;
+ for (i = 0; i < c->nedge_pts; i++) {
+ qr_point q;
+ int d;
+ qr_aff_unproject(q, _aff, c->edge_pts[i].pos[0], c->edge_pts[i].pos[1]);
+ qr_point_translate(q, -_f->o[0], -_f->o[1]);
+ d = abs(q[1]) > abs(q[0]);
+ e = d << 1 | (q[d] >= 0);
+ _f->nedge_pts[e]++;
+ c->edge_pts[i].edge = e;
+ c->edge_pts[i].extent = q[d];
+ }
+ qsort(c->edge_pts, c->nedge_pts, sizeof(*c->edge_pts), qr_cmp_edge_pt);
+ _f->edge_pts[0] = c->edge_pts;
+ for (e = 1; e < 4; e++)
+ _f->edge_pts[e] = _f->edge_pts[e - 1] + _f->nedge_pts[e - 1];
+}
+
+/*Computes the index of the edge each edge point belongs to, and its (signed)
+ distance along the corresponding axis from the center of the finder pattern
+ (in the square domain).
+ The resulting list of edge points is sorted by edge index, with ties broken
+ by extent.*/
+static void qr_finder_edge_pts_hom_classify(qr_finder *_f, const qr_hom *_hom)
+{
+ qr_finder_center *c;
+ int i;
+ int e;
+ c = _f->c;
+ for (e = 0; e < 4; e++)
+ _f->nedge_pts[e] = 0;
+ for (i = 0; i < c->nedge_pts; i++) {
+ qr_point q;
+ int d;
+ if (qr_hom_unproject(q, _hom, c->edge_pts[i].pos[0],
+ c->edge_pts[i].pos[1]) >= 0) {
+ qr_point_translate(q, -_f->o[0], -_f->o[1]);
+ d = abs(q[1]) > abs(q[0]);
+ e = d << 1 | (q[d] >= 0);
+ _f->nedge_pts[e]++;
+ c->edge_pts[i].edge = e;
+ c->edge_pts[i].extent = q[d];
+ } else {
+ c->edge_pts[i].edge = 4;
+ c->edge_pts[i].extent = q[0];
+ }
+ }
+ qsort(c->edge_pts, c->nedge_pts, sizeof(*c->edge_pts), qr_cmp_edge_pt);
+ _f->edge_pts[0] = c->edge_pts;
+ for (e = 1; e < 4; e++)
+ _f->edge_pts[e] = _f->edge_pts[e - 1] + _f->nedge_pts[e - 1];
+}
+
+/*TODO: Perhaps these thresholds should be on the module size instead?
+ Unfortunately, I'd need real-world images of codes with larger versions to
+ see if these thresholds are still effective, but such versions aren't used
+ often.*/
+
+/*The amount that the estimated version numbers are allowed to differ from the
+ real version number and still be considered valid.*/
+#define QR_SMALL_VERSION_SLACK (1)
+/*Since cell phone cameras can have severe radial distortion, the estimated
+ version for larger versions can be off by larger amounts.*/
+#define QR_LARGE_VERSION_SLACK (3)
+
+/*Estimates the size of a module after classifying the edge points.
+ _width: The distance between UL and UR in the square domain.
+ _height: The distance between UL and DL in the square domain.*/
+static int qr_finder_estimate_module_size_and_version(qr_finder *_f, int _width,
+ int _height)
+{
+ qr_point offs;
+ int sums[4];
+ int nsums[4];
+ int usize;
+ int nusize;
+ int vsize;
+ int nvsize;
+ int uversion;
+ int vversion;
+ int e;
+ offs[0] = offs[1] = 0;
+ for (e = 0; e < 4; e++)
+ if (_f->nedge_pts[e] > 0) {
+ qr_finder_edge_pt *edge_pts;
+ int sum;
+ int mean;
+ int n;
+ int i;
+ /*Average the samples for this edge, dropping the top and bottom 25%.*/
+ edge_pts = _f->edge_pts[e];
+ n = _f->nedge_pts[e];
+ sum = 0;
+ for (i = (n >> 2); i < n - (n >> 2); i++)
+ sum += edge_pts[i].extent;
+ n = n - ((n >> 2) << 1);
+ mean = QR_DIVROUND(sum, n);
+ offs[e >> 1] += mean;
+ sums[e] = sum;
+ nsums[e] = n;
+ } else
+ nsums[e] = sums[e] = 0;
+ /*If we have samples on both sides of an axis, refine our idea of where the
+ unprojected finder center is located.*/
+ if (_f->nedge_pts[0] > 0 && _f->nedge_pts[1] > 0) {
+ _f->o[0] -= offs[0] >> 1;
+ sums[0] -= offs[0] * nsums[0] >> 1;
+ sums[1] -= offs[0] * nsums[1] >> 1;
+ }
+ if (_f->nedge_pts[2] > 0 && _f->nedge_pts[3] > 0) {
+ _f->o[1] -= offs[1] >> 1;
+ sums[2] -= offs[1] * nsums[2] >> 1;
+ sums[3] -= offs[1] * nsums[3] >> 1;
+ }
+ /*We must have _some_ samples along each axis... if we don't, our transform
+ must be pretty severely distorting the original square (e.g., with
+ coordinates so large as to cause overflow).*/
+ nusize = nsums[0] + nsums[1];
+ if (nusize <= 0)
+ return -1;
+ /*The module size is 1/3 the average edge extent.*/
+ nusize *= 3;
+ usize = sums[1] - sums[0];
+ usize = ((usize << 1) + nusize) / (nusize << 1);
+ if (usize <= 0)
+ return -1;
+ /*Now estimate the version directly from the module size and the distance
+ between the finder patterns.
+ This is done independently using the extents along each axis.
+ If either falls significantly outside the valid range (1 to 40), reject the
+ configuration.*/
+ uversion = (_width - 8 * usize) / (usize << 2);
+ if (uversion < 1 || uversion > 40 + QR_LARGE_VERSION_SLACK)
+ return -1;
+ /*Now do the same for the other axis.*/
+ nvsize = nsums[2] + nsums[3];
+ if (nvsize <= 0)
+ return -1;
+ nvsize *= 3;
+ vsize = sums[3] - sums[2];
+ vsize = ((vsize << 1) + nvsize) / (nvsize << 1);
+ if (vsize <= 0)
+ return -1;
+ vversion = (_height - 8 * vsize) / (vsize << 2);
+ if (vversion < 1 || vversion > 40 + QR_LARGE_VERSION_SLACK)
+ return -1;
+ /*If the estimated version using extents along one axis is significantly
+ different than the estimated version along the other axis, then the axes
+ have significantly different scalings (relative to the grid).
+ This can happen, e.g., when we have multiple adjacent QR codes, and we've
+ picked two finder patterns from one and the third finder pattern from
+ another, e.g.:
+ X---DL UL---X
+ |.... |....
+ X.... UR....
+ Such a configuration might even pass any other geometric checks if we
+ didn't reject it here.*/
+ if (abs(uversion - vversion) > QR_LARGE_VERSION_SLACK)
+ return -1;
+ _f->size[0] = usize;
+ _f->size[1] = vsize;
+ /*We intentionally do not compute an average version from the sizes along
+ both axes.
+ In the presence of projective distortion, one of them will be much more
+ accurate than the other.*/
+ _f->eversion[0] = uversion;
+ _f->eversion[1] = vversion;
+ return 0;
+}
+
+/*Eliminate outliers from the classified edge points with RANSAC.*/
+static void qr_finder_ransac(qr_finder *_f, const qr_aff *_hom,
+ isaac_ctx *_isaac, int _e)
+{
+ qr_finder_edge_pt *edge_pts;
+ int best_ninliers;
+ int n;
+ edge_pts = _f->edge_pts[_e];
+ n = _f->nedge_pts[_e];
+ best_ninliers = 0;
+ if (n > 1) {
+ int max_iters;
+ int i;
+ int j;
+ /*17 iterations is enough to guarantee an outlier-free sample with more
+ than 99% probability given as many as 50% outliers.*/
+ max_iters = 17;
+ for (i = 0; i < max_iters; i++) {
+ qr_point q0;
+ qr_point q1;
+ int ninliers;
+ int thresh;
+ int p0i;
+ int p1i;
+ int *p0;
+ int *p1;
+ int j;
+ /*Pick two random points on this edge.*/
+ p0i = isaac_next_uint(_isaac, n);
+ p1i = isaac_next_uint(_isaac, n - 1);
+ if (p1i >= p0i)
+ p1i++;
+ p0 = edge_pts[p0i].pos;
+ p1 = edge_pts[p1i].pos;
+ /*If the corresponding line is not within 45 degrees of the proper
+ orientation in the square domain, reject it outright.
+ This can happen, e.g., when highly skewed orientations cause points to
+ be misclassified into the wrong edge.
+ The irony is that using such points might produce a line which _does_
+ pass the corresponding validity checks.*/
+ qr_aff_unproject(q0, _hom, p0[0], p0[1]);
+ qr_aff_unproject(q1, _hom, p1[0], p1[1]);
+ qr_point_translate(q0, -_f->o[0], -_f->o[1]);
+ qr_point_translate(q1, -_f->o[0], -_f->o[1]);
+ if (abs(q0[_e >> 1] - q1[_e >> 1]) >
+ abs(q0[1 - (_e >> 1)] - q1[1 - (_e >> 1)]))
+ continue;
+ /*Identify the other edge points which are inliers.
+ The squared distance should be distributed as a \Chi^2 distribution
+ with one degree of freedom, which means for a 95% confidence the
+ point should lie within a factor 3.8414588 ~= 4 times the expected
+ variance of the point locations.
+ We grossly approximate the standard deviation as 1 pixel in one
+ direction, and 0.5 pixels in the other (because we average two
+ coordinates).*/
+ thresh = qr_isqrt(qr_point_distance2(p0, p1)
+ << 2 * QR_FINDER_SUBPREC + 1);
+ ninliers = 0;
+ for (j = 0; j < n; j++) {
+ if (abs(qr_point_ccw(p0, p1, edge_pts[j].pos)) <= thresh) {
+ edge_pts[j].extent |= 1;
+ ninliers++;
+ } else
+ edge_pts[j].extent &= ~1;
+ }
+ if (ninliers > best_ninliers) {
+ for (j = 0; j < n; j++)
+ edge_pts[j].extent <<= 1;
+ best_ninliers = ninliers;
+ /*The actual number of iterations required is
+ log(1-\alpha)/log(1-r*r),
+ where \alpha is the required probability of taking a sample with
+ no outliers (e.g., 0.99) and r is the estimated ratio of inliers
+ (e.g. ninliers/n).
+ This is just a rough (but conservative) approximation, but it
+ should be good enough to stop the iteration early when we find
+ a good set of inliers.*/
+ if (ninliers > n >> 1)
+ max_iters = (67 * n - 63 * ninliers - 1) / (n << 1);
+ }
+ }
+ /*Now collect all the inliers at the beginning of the list.*/
+ for (i = j = 0; j < best_ninliers; i++)
+ if (edge_pts[i].extent & 2) {
+ if (j < i) {
+ qr_finder_edge_pt tmp;
+ *&tmp = *(edge_pts + i);
+ *(edge_pts + j) = *(edge_pts + i);
+ *(edge_pts + i) = *&tmp;
+ }
+ j++;
+ }
+ }
+ _f->ninliers[_e] = best_ninliers;
+}
+
+/*Perform a least-squares line fit to an edge of a finder pattern using the
+ inliers found by RANSAC.*/
+static int qr_line_fit_finder_edge(qr_line _l, const qr_finder *_f, int _e,
+ int _res)
+{
+ qr_finder_edge_pt *edge_pts;
+ qr_point *pts;
+ int npts;
+ int i;
+ npts = _f->ninliers[_e];
+ if (npts < 2)
+ return -1;
+ /*We could write a custom version of qr_line_fit_points that accesses
+ edge_pts directly, but this saves on code size and doesn't measurably slow
+ things down.*/
+ pts = (qr_point *)malloc(npts * sizeof(*pts));
+ edge_pts = _f->edge_pts[_e];
+ for (i = 0; i < npts; i++) {
+ pts[i][0] = edge_pts[i].pos[0];
+ pts[i][1] = edge_pts[i].pos[1];
+ }
+ qr_line_fit_points(_l, pts, npts, _res);
+ /*Make sure the center of the finder pattern lies in the positive halfspace
+ of the line.*/
+ qr_line_orient(_l, _f->c->pos[0], _f->c->pos[1]);
+ free(pts);
+ return 0;
+}
+
+/*Perform a least-squares line fit to a pair of common finder edges using the
+ inliers found by RANSAC.
+ Unlike a normal edge fit, we guarantee that this one succeeds by creating at
+ least one point on each edge using the estimated module size if it has no
+ inliers.*/
+static void qr_line_fit_finder_pair(qr_line _l, const qr_aff *_aff,
+ const qr_finder *_f0, const qr_finder *_f1,
+ int _e)
+{
+ qr_point *pts;
+ int npts;
+ qr_finder_edge_pt *edge_pts;
+ qr_point q;
+ int n0;
+ int n1;
+ int i;
+ n0 = _f0->ninliers[_e];
+ n1 = _f1->ninliers[_e];
+ /*We could write a custom version of qr_line_fit_points that accesses
+ edge_pts directly, but this saves on code size and doesn't measurably slow
+ things down.*/
+ npts = QR_MAXI(n0, 1) + QR_MAXI(n1, 1);
+ pts = (qr_point *)malloc(npts * sizeof(*pts));
+ if (n0 > 0) {
+ edge_pts = _f0->edge_pts[_e];
+ for (i = 0; i < n0; i++) {
+ pts[i][0] = edge_pts[i].pos[0];
+ pts[i][1] = edge_pts[i].pos[1];
+ }
+ } else {
+ q[0] = _f0->o[0];
+ q[1] = _f0->o[1];
+ q[_e >> 1] += _f0->size[_e >> 1] * (2 * (_e & 1) - 1);
+ qr_aff_project(pts[0], _aff, q[0], q[1]);
+ n0++;
+ }
+ if (n1 > 0) {
+ edge_pts = _f1->edge_pts[_e];
+ for (i = 0; i < n1; i++) {
+ pts[n0 + i][0] = edge_pts[i].pos[0];
+ pts[n0 + i][1] = edge_pts[i].pos[1];
+ }
+ } else {
+ q[0] = _f1->o[0];
+ q[1] = _f1->o[1];
+ q[_e >> 1] += _f1->size[_e >> 1] * (2 * (_e & 1) - 1);
+ qr_aff_project(pts[n0], _aff, q[0], q[1]);
+ n1++;
+ }
+ qr_line_fit_points(_l, pts, npts, _aff->res);
+ /*Make sure at least one finder center lies in the positive halfspace.*/
+ qr_line_orient(_l, _f0->c->pos[0], _f0->c->pos[1]);
+ free(pts);
+}
+
+static int qr_finder_quick_crossing_check(const unsigned char *_img, int _width,
+ int _height, int _x0, int _y0,
+ int _x1, int _y1, int _v)
+{
+ /*The points must be inside the image, and have a !_v:_v:!_v pattern.
+ We don't scan the whole line initially, but quickly reject if the endpoints
+ aren't !_v, or the midpoint isn't _v.
+ If either end point is out of the image, or we don't encounter a _v pixel,
+ we return a negative value, indicating the region should be considered
+ empty.
+ Otherwise, we return a positive value to indicate it is non-empty.*/
+ if (_x0 < 0 || _x0 >= _width || _y0 < 0 || _y0 >= _height || _x1 < 0 ||
+ _x1 >= _width || _y1 < 0 || _y1 >= _height) {
+ return -1;
+ }
+ if ((!_img[_y0 * _width + _x0]) != _v || (!_img[_y1 * _width + _x1]) != _v)
+ return 1;
+ if ((!_img[(_y0 + _y1 >> 1) * _width + (_x0 + _x1 >> 1)]) == _v)
+ return -1;
+ return 0;
+}
+
+/*Locate the midpoint of a _v segment along a !_v:_v:!_v line from (_x0,_y0) to
+ (_x1,_y1).
+ All coordinates, which are NOT in subpel resolution, must lie inside the
+ image, and the endpoints are already assumed to have the value !_v.
+ The returned value is in subpel resolution.*/
+static int qr_finder_locate_crossing(const unsigned char *_img, int _width,
+ int _height, int _x0, int _y0, int _x1,
+ int _y1, int _v, qr_point _p)
+{
+ qr_point x0;
+ qr_point x1;
+ qr_point dx;
+ int step[2];
+ int steep;
+ int err;
+ int derr;
+ /*Use Bresenham's algorithm to trace along the line and find the exact
+ transitions from !_v to _v and back.*/
+ x0[0] = _x0;
+ x0[1] = _y0;
+ x1[0] = _x1;
+ x1[1] = _y1;
+ dx[0] = abs(_x1 - _x0);
+ dx[1] = abs(_y1 - _y0);
+ steep = dx[1] > dx[0];
+ err = 0;
+ derr = dx[1 - steep];
+ step[0] = ((_x0 < _x1) << 1) - 1;
+ step[1] = ((_y0 < _y1) << 1) - 1;
+ /*Find the first crossing from !_v to _v.*/
+ for (;;) {
+ /*If we make it all the way to the other side, there's no crossing.*/
+ if (x0[steep] == x1[steep])
+ return -1;
+ x0[steep] += step[steep];
+ err += derr;
+ if (err << 1 > dx[steep]) {
+ x0[1 - steep] += step[1 - steep];
+ err -= dx[steep];
+ }
+ if ((!_img[x0[1] * _width + x0[0]]) != _v)
+ break;
+ }
+ /*Find the last crossing from _v to !_v.*/
+ err = 0;
+ for (;;) {
+ if (x0[steep] == x1[steep])
+ break;
+ x1[steep] -= step[steep];
+ err += derr;
+ if (err << 1 > dx[steep]) {
+ x1[1 - steep] -= step[1 - steep];
+ err -= dx[steep];
+ }
+ if ((!_img[x1[1] * _width + x1[0]]) != _v)
+ break;
+ }
+ /*Return the midpoint of the _v segment.*/
+ _p[0] = (x0[0] + x1[0] + 1 << QR_FINDER_SUBPREC) >> 1;
+ _p[1] = (x0[1] + x1[1] + 1 << QR_FINDER_SUBPREC) >> 1;
+ return 0;
+}
+
+static int qr_aff_line_step(const qr_aff *_aff, qr_line _l, int _v, int _du,
+ int *_dv)
+{
+ int shift;
+ int round;
+ int dv;
+ int n;
+ int d;
+ n = _aff->fwd[0][_v] * _l[0] + _aff->fwd[1][_v] * _l[1];
+ d = _aff->fwd[0][1 - _v] * _l[0] + _aff->fwd[1][1 - _v] * _l[1];
+ if (d < 0) {
+ n = -n;
+ d = -d;
+ }
+ shift = QR_MAXI(0, qr_ilog(_du) + qr_ilog(abs(n)) + 3 - QR_INT_BITS);
+ round = (1 << shift) >> 1;
+ n = n + round >> shift;
+ d = d + round >> shift;
+ /*The line should not be outside 45 degrees of horizontal/vertical.
+ TODO: We impose this restriction to help ensure the loop below terminates,
+ but it should not technically be required.
+ It also, however, ensures we avoid division by zero.*/
+ if (abs(n) >= d)
+ return -1;
+ n = -_du * n;
+ dv = QR_DIVROUND(n, d);
+ if (abs(dv) >= _du)
+ return -1;
+ *_dv = dv;
+ return 0;
+}
+
+/*Computes the Hamming distance between two bit patterns (the number of bits
+ that differ).
+ May stop counting after _maxdiff differences.*/
+static int qr_hamming_dist(unsigned _y1, unsigned _y2, int _maxdiff)
+{
+ unsigned y;
+ int ret;
+ y = _y1 ^ _y2;
+ for (ret = 0; ret < _maxdiff && y; ret++)
+ y &= y - 1;
+ return ret;
+}
+
+/*Retrieve a bit (guaranteed to be 0 or 1) from the image, given coordinates in
+ subpel resolution which have not been bounds checked.*/
+static int qr_img_get_bit(const unsigned char *_img, int _width, int _height,
+ int _x, int _y)
+{
+ _x >>= QR_FINDER_SUBPREC;
+ _y >>= QR_FINDER_SUBPREC;
+ return _img[QR_CLAMPI(0, _y, _height - 1) * _width +
+ QR_CLAMPI(0, _x, _width - 1)] != 0;
+}
+
+#if defined(QR_DEBUG)
+#include "image.h"
+
+static void qr_finder_dump_aff_undistorted(qr_finder *_ul, qr_finder *_ur,
+ qr_finder *_dl, qr_aff *_aff,
+ const unsigned char *_img,
+ int _width, int _height)
+{
+ unsigned char *gimg;
+ FILE *fout;
+ int lpsz;
+ int pixel_size;
+ int dim;
+ int min;
+ int max;
+ int u;
+ int y;
+ int i;
+ int j;
+ lpsz =
+ qr_ilog(_ur->size[0] + _ur->size[1] + _dl->size[0] + _dl->size[1]) - 6;
+ pixel_size = 1 << lpsz;
+ dim = (1 << _aff->res - lpsz) + 128;
+ gimg = (unsigned char *)malloc(dim * dim * sizeof(*gimg));
+ for (i = 0; i < dim; i++)
+ for (j = 0; j < dim; j++) {
+ qr_point p;
+ qr_aff_project(p, _aff, (j - 64) << lpsz, (i - 64) << lpsz);
+ gimg[i * dim + j] =
+ _img[QR_CLAMPI(0, p[1] >> QR_FINDER_SUBPREC, _height - 1) *
+ _width +
+ QR_CLAMPI(0, p[0] >> QR_FINDER_SUBPREC, _width - 1)];
+ }
+ {
+ min = (_ur->o[0] - 7 * _ur->size[0] >> lpsz) + 64;
+ if (min < 0)
+ min = 0;
+ max = (_ur->o[0] + 7 * _ur->size[0] >> lpsz) + 64;
+ if (max > dim)
+ max = dim;
+ for (y = -7; y <= 7; y++) {
+ i = (_ur->o[1] + y * _ur->size[1] >> lpsz) + 64;
+ if (i < 0 || i >= dim)
+ continue;
+ for (j = min; j < max; j++)
+ gimg[i * dim + j] = 0x7F;
+ }
+ min = (_ur->o[1] - 7 * _ur->size[1] >> lpsz) + 64;
+ if (min < 0)
+ min = 0;
+ max = (_ur->o[1] + 7 * _ur->size[1] >> lpsz) + 64;
+ if (max > dim)
+ max = dim;
+ for (u = -7; u <= 7; u++) {
+ j = (_ur->o[0] + u * _ur->size[0] >> lpsz) + 64;
+ if (j < 0 || j >= dim)
+ continue;
+ for (i = min; i < max; i++)
+ gimg[i * dim + j] = 0x7F;
+ }
+ }
+ {
+ min = (_dl->o[0] - 7 * _dl->size[0] >> lpsz) + 64;
+ if (min < 0)
+ min = 0;
+ max = (_dl->o[0] + 7 * _dl->size[0] >> lpsz) + 64;
+ if (max > dim)
+ max = dim;
+ for (y = -7; y <= 7; y++) {
+ i = (_dl->o[1] + y * _dl->size[1] >> lpsz) + 64;
+ if (i < 0 || i >= dim)
+ continue;
+ for (j = min; j < max; j++)
+ gimg[i * dim + j] = 0x7F;
+ }
+ min = (_dl->o[1] - 7 * _dl->size[1] >> lpsz) + 64;
+ if (min < 0)
+ min = 0;
+ max = (_dl->o[1] + 7 * _dl->size[1] >> lpsz) + 64;
+ if (max > dim)
+ max = dim;
+ for (u = -7; u <= 7; u++) {
+ j = (_dl->o[0] + u * _dl->size[0] >> lpsz) + 64;
+ if (j < 0 || j >= dim)
+ continue;
+ for (i = min; i < max; i++)
+ gimg[i * dim + j] = 0x7F;
+ }
+ }
+ fout = fopen("undistorted_aff.png", "wb");
+ image_write_png(gimg, dim, dim, fout);
+ fclose(fout);
+ free(gimg);
+}
+
+static void qr_finder_dump_hom_undistorted(qr_finder *_ul, qr_finder *_ur,
+ qr_finder *_dl, qr_hom *_hom,
+ const unsigned char *_img,
+ int _width, int _height)
+{
+ unsigned char *gimg;
+ FILE *fout;
+ int lpsz;
+ int pixel_size;
+ int dim;
+ int min;
+ int max;
+ int u;
+ int v;
+ int i;
+ int j;
+ lpsz =
+ qr_ilog(_ur->size[0] + _ur->size[1] + _dl->size[0] + _dl->size[1]) - 6;
+ pixel_size = 1 << lpsz;
+ dim = (1 << _hom->res - lpsz) + 256;
+ gimg = (unsigned char *)malloc(dim * dim * sizeof(*gimg));
+ for (i = 0; i < dim; i++)
+ for (j = 0; j < dim; j++) {
+ qr_point p;
+ qr_hom_project(p, _hom, (j - 128) << lpsz, (i - 128) << lpsz);
+ gimg[i * dim + j] =
+ _img[QR_CLAMPI(0, p[1] >> QR_FINDER_SUBPREC, _height - 1) *
+ _width +
+ QR_CLAMPI(0, p[0] >> QR_FINDER_SUBPREC, _width - 1)];
+ }
+ {
+ min = (_ur->o[0] - 7 * _ur->size[0] >> lpsz) + 128;
+ if (min < 0)
+ min = 0;
+ max = (_ur->o[0] + 7 * _ur->size[0] >> lpsz) + 128;
+ if (max > dim)
+ max = dim;
+ for (v = -7; v <= 7; v++) {
+ i = (_ur->o[1] + v * _ur->size[1] >> lpsz) + 128;
+ if (i < 0 || i >= dim)
+ continue;
+ for (j = min; j < max; j++)
+ gimg[i * dim + j] = 0x7F;
+ }
+ min = (_ur->o[1] - 7 * _ur->size[1] >> lpsz) + 128;
+ if (min < 0)
+ min = 0;
+ max = (_ur->o[1] + 7 * _ur->size[1] >> lpsz) + 128;
+ if (max > dim)
+ max = dim;
+ for (u = -7; u <= 7; u++) {
+ j = (_ur->o[0] + u * _ur->size[0] >> lpsz) + 128;
+ if (j < 0 || j >= dim)
+ continue;
+ for (i = min; i < max; i++)
+ gimg[i * dim + j] = 0x7F;
+ }
+ }
+ {
+ min = (_dl->o[0] - 7 * _dl->size[0] >> lpsz) + 128;
+ if (min < 0)
+ min = 0;
+ max = (_dl->o[0] + 7 * _dl->size[0] >> lpsz) + 128;
+ if (max > dim)
+ max = dim;
+ for (v = -7; v <= 7; v++) {
+ i = (_dl->o[1] + v * _dl->size[1] >> lpsz) + 128;
+ if (i < 0 || i >= dim)
+ continue;
+ for (j = min; j < max; j++)
+ gimg[i * dim + j] = 0x7F;
+ }
+ min = (_dl->o[1] - 7 * _dl->size[1] >> lpsz) + 128;
+ if (min < 0)
+ min = 0;
+ max = (_dl->o[1] + 7 * _dl->size[1] >> lpsz) + 128;
+ if (max > dim)
+ max = dim;
+ for (u = -7; u <= 7; u++) {
+ j = (_dl->o[0] + u * _dl->size[0] >> lpsz) + 128;
+ if (j < 0 || j >= dim)
+ continue;
+ for (i = min; i < max; i++)
+ gimg[i * dim + j] = 0x7F;
+ }
+ }
+ fout = fopen("undistorted_hom.png", "wb");
+ image_write_png(gimg, dim, dim, fout);
+ fclose(fout);
+ free(gimg);
+}
+#endif
+
+/*A homography from one region of the grid back to the image.
+ Unlike a qr_hom, this does not include an inverse transform and maps directly
+ from the grid points, not a square with power-of-two sides.*/
+struct qr_hom_cell {
+ int fwd[3][3];
+ int x0;
+ int y0;
+ int u0;
+ int v0;
+};
+
+static void qr_hom_cell_init(qr_hom_cell *_cell, int _u0, int _v0, int _u1,
+ int _v1, int _u2, int _v2, int _u3, int _v3,
+ int _x0, int _y0, int _x1, int _y1, int _x2,
+ int _y2, int _x3, int _y3)
+{
+ int du10;
+ int du20;
+ int du30;
+ int du31;
+ int du32;
+ int dv10;
+ int dv20;
+ int dv30;
+ int dv31;
+ int dv32;
+ int dx10;
+ int dx20;
+ int dx30;
+ int dx31;
+ int dx32;
+ int dy10;
+ int dy20;
+ int dy30;
+ int dy31;
+ int dy32;
+ int a00;
+ int a01;
+ int a02;
+ int a10;
+ int a11;
+ int a12;
+ int a20;
+ int a21;
+ int a22;
+ int i00;
+ int i01;
+ int i10;
+ int i11;
+ int i20;
+ int i21;
+ int i22;
+ int b0;
+ int b1;
+ int b2;
+ int shift;
+ int round;
+ int x;
+ int y;
+ int w;
+ /*First, correct for the arrangement of the source points.
+ We take advantage of the fact that we know the source points have a very
+ limited dynamic range (so there will never be overflow) and a small amount
+ of projective distortion.*/
+ du10 = _u1 - _u0;
+ du20 = _u2 - _u0;
+ du30 = _u3 - _u0;
+ du31 = _u3 - _u1;
+ du32 = _u3 - _u2;
+ dv10 = _v1 - _v0;
+ dv20 = _v2 - _v0;
+ dv30 = _v3 - _v0;
+ dv31 = _v3 - _v1;
+ dv32 = _v3 - _v2;
+ /*Compute the coefficients of the forward transform from the unit square to
+ the source point configuration.*/
+ a20 = du32 * dv10 - du10 * dv32;
+ a21 = du20 * dv31 - du31 * dv20;
+ if (a20 || a21)
+ a22 = du32 * dv31 - du31 * dv32;
+ /*If the source grid points aren't in a non-affine arrangement, there's no
+ reason to scale everything by du32*dv31-du31*dv32.
+ Not doing so allows a much larger dynamic range, and is the only way we can
+ initialize a base cell that covers the whole grid.*/
+ else
+ a22 = 1;
+ a00 = du10 * (a20 + a22);
+ a01 = du20 * (a21 + a22);
+ a10 = dv10 * (a20 + a22);
+ a11 = dv20 * (a21 + a22);
+ /*Now compute the inverse transform.*/
+ i00 = a11 * a22;
+ i01 = -a01 * a22;
+ i10 = -a10 * a22;
+ i11 = a00 * a22;
+ i20 = a10 * a21 - a11 * a20;
+ i21 = a01 * a20 - a00 * a21;
+ i22 = a00 * a11 - a01 * a10;
+ /*Invert the coefficients.
+ Since i22 is the largest, we divide it by all the others.
+ The quotient is often exact (e.g., when the source points contain no
+ projective distortion), and is never zero.
+ Hence we can use zero to signal "infinity" when the divisor is zero.*/
+ if (i00)
+ i00 = QR_FLIPSIGNI(QR_DIVROUND(i22, abs(i00)), i00);
+ if (i01)
+ i01 = QR_FLIPSIGNI(QR_DIVROUND(i22, abs(i01)), i01);
+ if (i10)
+ i10 = QR_FLIPSIGNI(QR_DIVROUND(i22, abs(i10)), i10);
+ if (i11)
+ i11 = QR_FLIPSIGNI(QR_DIVROUND(i22, abs(i11)), i11);
+ if (i20)
+ i20 = QR_FLIPSIGNI(QR_DIVROUND(i22, abs(i20)), i20);
+ if (i21)
+ i21 = QR_FLIPSIGNI(QR_DIVROUND(i22, abs(i21)), i21);
+ /*Now compute the map from the unit square into the image.*/
+ dx10 = _x1 - _x0;
+ dx20 = _x2 - _x0;
+ dx30 = _x3 - _x0;
+ dx31 = _x3 - _x1;
+ dx32 = _x3 - _x2;
+ dy10 = _y1 - _y0;
+ dy20 = _y2 - _y0;
+ dy30 = _y3 - _y0;
+ dy31 = _y3 - _y1;
+ dy32 = _y3 - _y2;
+ a20 = dx32 * dy10 - dx10 * dy32;
+ a21 = dx20 * dy31 - dx31 * dy20;
+ a22 = dx32 * dy31 - dx31 * dy32;
+ /*Figure out if we need to downscale anything.*/
+ b0 = qr_ilog(QR_MAXI(abs(dx10), abs(dy10))) + qr_ilog(abs(a20 + a22));
+ b1 = qr_ilog(QR_MAXI(abs(dx20), abs(dy20))) + qr_ilog(abs(a21 + a22));
+ b2 = qr_ilog(QR_MAXI(QR_MAXI(abs(a20), abs(a21)), abs(a22)));
+ shift = QR_MAXI(0, QR_MAXI(QR_MAXI(b0, b1), b2) -
+ (QR_INT_BITS - 3 - QR_ALIGN_SUBPREC));
+ round = (1 << shift) >> 1;
+ /*Compute the final coefficients of the forward transform.*/
+ a00 = QR_FIXMUL(dx10, a20 + a22, round, shift);
+ a01 = QR_FIXMUL(dx20, a21 + a22, round, shift);
+ a10 = QR_FIXMUL(dy10, a20 + a22, round, shift);
+ a11 = QR_FIXMUL(dy20, a21 + a22, round, shift);
+ /*And compose the two transforms.
+ Since we inverted the coefficients above, we divide by them here instead
+ of multiplying.
+ This lets us take advantage of the full dynamic range.
+ Note a zero divisor is really "infinity", and thus the quotient should also
+ be zero.*/
+ _cell->fwd[0][0] =
+ (i00 ? QR_DIVROUND(a00, i00) : 0) + (i10 ? QR_DIVROUND(a01, i10) : 0);
+ _cell->fwd[0][1] =
+ (i01 ? QR_DIVROUND(a00, i01) : 0) + (i11 ? QR_DIVROUND(a01, i11) : 0);
+ _cell->fwd[1][0] =
+ (i00 ? QR_DIVROUND(a10, i00) : 0) + (i10 ? QR_DIVROUND(a11, i10) : 0);
+ _cell->fwd[1][1] =
+ (i01 ? QR_DIVROUND(a10, i01) : 0) + (i11 ? QR_DIVROUND(a11, i11) : 0);
+ _cell->fwd[2][0] = (i00 ? QR_DIVROUND(a20, i00) : 0) +
+ (i10 ? QR_DIVROUND(a21, i10) : 0) +
+ (i20 ? QR_DIVROUND(a22, i20) : 0) + round >>
+ shift;
+ _cell->fwd[2][1] = (i01 ? QR_DIVROUND(a20, i01) : 0) +
+ (i11 ? QR_DIVROUND(a21, i11) : 0) +
+ (i21 ? QR_DIVROUND(a22, i21) : 0) + round >>
+ shift;
+ _cell->fwd[2][2] = a22 + round >> shift;
+ /*Mathematically, a02 and a12 are exactly zero.
+ However, that concentrates all of the rounding error in the (_u3,_v3)
+ corner; we compute offsets which distribute it over the whole range.*/
+ x = _cell->fwd[0][0] * du10 + _cell->fwd[0][1] * dv10;
+ y = _cell->fwd[1][0] * du10 + _cell->fwd[1][1] * dv10;
+ w = _cell->fwd[2][0] * du10 + _cell->fwd[2][1] * dv10 + _cell->fwd[2][2];
+ a02 = dx10 * w - x;
+ a12 = dy10 * w - y;
+ x = _cell->fwd[0][0] * du20 + _cell->fwd[0][1] * dv20;
+ y = _cell->fwd[1][0] * du20 + _cell->fwd[1][1] * dv20;
+ w = _cell->fwd[2][0] * du20 + _cell->fwd[2][1] * dv20 + _cell->fwd[2][2];
+ a02 += dx20 * w - x;
+ a12 += dy20 * w - y;
+ x = _cell->fwd[0][0] * du30 + _cell->fwd[0][1] * dv30;
+ y = _cell->fwd[1][0] * du30 + _cell->fwd[1][1] * dv30;
+ w = _cell->fwd[2][0] * du30 + _cell->fwd[2][1] * dv30 + _cell->fwd[2][2];
+ a02 += dx30 * w - x;
+ a12 += dy30 * w - y;
+ _cell->fwd[0][2] = a02 + 2 >> 2;
+ _cell->fwd[1][2] = a12 + 2 >> 2;
+ _cell->x0 = _x0;
+ _cell->y0 = _y0;
+ _cell->u0 = _u0;
+ _cell->v0 = _v0;
+}
+
+/*Finish a partial projection, converting from homogeneous coordinates to the
+ normal 2-D representation.
+ In loops, we can avoid many multiplies by computing the homogeneous _x, _y,
+ and _w incrementally, but we cannot avoid the divisions, done here.*/
+static void qr_hom_cell_fproject(qr_point _p, const qr_hom_cell *_cell, int _x,
+ int _y, int _w)
+{
+ if (_w == 0) {
+ _p[0] = _x < 0 ? INT_MIN : INT_MAX;
+ _p[1] = _y < 0 ? INT_MIN : INT_MAX;
+ } else {
+ if (_w < 0) {
+ _x = -_x;
+ _y = -_y;
+ _w = -_w;
+ }
+ _p[0] = QR_DIVROUND(_x, _w) + _cell->x0;
+ _p[1] = QR_DIVROUND(_y, _w) + _cell->y0;
+ }
+}
+
+static void qr_hom_cell_project(qr_point _p, const qr_hom_cell *_cell, int _u,
+ int _v, int _res)
+{
+ _u -= _cell->u0 << _res;
+ _v -= _cell->v0 << _res;
+ qr_hom_cell_fproject(_p, _cell,
+ _cell->fwd[0][0] * _u + _cell->fwd[0][1] * _v +
+ (_cell->fwd[0][2] << _res),
+ _cell->fwd[1][0] * _u + _cell->fwd[1][1] * _v +
+ (_cell->fwd[1][2] << _res),
+ _cell->fwd[2][0] * _u + _cell->fwd[2][1] * _v +
+ (_cell->fwd[2][2] << _res));
+}
+
+/*Retrieves the bits corresponding to the alignment pattern template centered
+ at the given location in the original image (at subpel precision).*/
+static unsigned qr_alignment_pattern_fetch(qr_point _p[5][5], int _x0, int _y0,
+ const unsigned char *_img,
+ int _width, int _height)
+{
+ unsigned v;
+ int i;
+ int j;
+ int k;
+ int dx;
+ int dy;
+ dx = _x0 - _p[2][2][0];
+ dy = _y0 - _p[2][2][1];
+ v = 0;
+ for (k = i = 0; i < 5; i++)
+ for (j = 0; j < 5; j++, k++) {
+ v |= qr_img_get_bit(_img, _width, _height, _p[i][j][0] + dx,
+ _p[i][j][1] + dy)
+ << k;
+ }
+ return v;
+}
+
+/*Searches for an alignment pattern near the given location.*/
+static int qr_alignment_pattern_search(qr_point _p, const qr_hom_cell *_cell,
+ int _u, int _v, int _r,
+ const unsigned char *_img, int _width,
+ int _height)
+{
+ qr_point c[4];
+ int nc[4];
+ qr_point p[5][5];
+ qr_point pc;
+ unsigned best_match;
+ int best_dist;
+ int bestx;
+ int besty;
+ unsigned match;
+ int dist;
+ int u;
+ int v;
+ int x0;
+ int y0;
+ int w0;
+ int x;
+ int y;
+ int w;
+ int dxdu;
+ int dydu;
+ int dwdu;
+ int dxdv;
+ int dydv;
+ int dwdv;
+ int dx;
+ int dy;
+ int i;
+ int j;
+ /*Build up a basic template using _cell to control shape and scale.
+ We project the points in the template back to the image just once, since if
+ the alignment pattern has moved, we don't really know why.
+ If it's because of radial distortion, or the code wasn't flat, or something
+ else, there's no reason to expect that a re-projection around each
+ subsequent search point would be any closer to the actual shape than our
+ first projection.
+ Therefore we simply slide this template around, as is.*/
+ u = (_u - 2) - _cell->u0;
+ v = (_v - 2) - _cell->v0;
+ x0 = _cell->fwd[0][0] * u + _cell->fwd[0][1] * v + _cell->fwd[0][2];
+ y0 = _cell->fwd[1][0] * u + _cell->fwd[1][1] * v + _cell->fwd[1][2];
+ w0 = _cell->fwd[2][0] * u + _cell->fwd[2][1] * v + _cell->fwd[2][2];
+ dxdu = _cell->fwd[0][0];
+ dydu = _cell->fwd[1][0];
+ dwdu = _cell->fwd[2][0];
+ dxdv = _cell->fwd[0][1];
+ dydv = _cell->fwd[1][1];
+ dwdv = _cell->fwd[2][1];
+ for (i = 0; i < 5; i++) {
+ x = x0;
+ y = y0;
+ w = w0;
+ for (j = 0; j < 5; j++) {
+ qr_hom_cell_fproject(p[i][j], _cell, x, y, w);
+ x += dxdu;
+ y += dydu;
+ w += dwdu;
+ }
+ x0 += dxdv;
+ y0 += dydv;
+ w0 += dwdv;
+ }
+ bestx = p[2][2][0];
+ besty = p[2][2][1];
+ best_match =
+ qr_alignment_pattern_fetch(p, bestx, besty, _img, _width, _height);
+ best_dist = qr_hamming_dist(best_match, 0x1F8D63F, 25);
+ if (best_dist > 0) {
+ u = _u - _cell->u0;
+ v = _v - _cell->v0;
+ x = _cell->fwd[0][0] * u + _cell->fwd[0][1] * v + _cell->fwd[0][2]
+ << QR_ALIGN_SUBPREC;
+ y = _cell->fwd[1][0] * u + _cell->fwd[1][1] * v + _cell->fwd[1][2]
+ << QR_ALIGN_SUBPREC;
+ w = _cell->fwd[2][0] * u + _cell->fwd[2][1] * v + _cell->fwd[2][2]
+ << QR_ALIGN_SUBPREC;
+ /*Search an area at most _r modules around the target location, in
+ concentric squares..*/
+ for (i = 1; i < _r << QR_ALIGN_SUBPREC; i++) {
+ int side_len;
+ side_len = (i << 1) - 1;
+ x -= dxdu + dxdv;
+ y -= dydu + dydv;
+ w -= dwdu + dwdv;
+ for (j = 0; j < 4 * side_len; j++) {
+ int dir;
+ qr_hom_cell_fproject(pc, _cell, x, y, w);
+ match = qr_alignment_pattern_fetch(p, pc[0], pc[1], _img,
+ _width, _height);
+ dist = qr_hamming_dist(match, 0x1F8D63F, best_dist + 1);
+ if (dist < best_dist) {
+ best_match = match;
+ best_dist = dist;
+ bestx = pc[0];
+ besty = pc[1];
+ }
+ if (j < 2 * side_len) {
+ dir = j >= side_len;
+ x += _cell->fwd[0][dir];
+ y += _cell->fwd[1][dir];
+ w += _cell->fwd[2][dir];
+ } else {
+ dir = j >= 3 * side_len;
+ x -= _cell->fwd[0][dir];
+ y -= _cell->fwd[1][dir];
+ w -= _cell->fwd[2][dir];
+ }
+ if (!best_dist)
+ break;
+ }
+ if (!best_dist)
+ break;
+ }
+ }
+ /*If the best result we got was sufficiently bad, reject the match.
+ If we're wrong and we include it, we can grossly distort the nearby
+ region, whereas using the initial starting point should at least be
+ consistent with the geometry we already have.*/
+ if (best_dist > 6) {
+ _p[0] = p[2][2][0];
+ _p[1] = p[2][2][1];
+ return -1;
+ }
+ /*Now try to get a more accurate location of the pattern center.*/
+ dx = bestx - p[2][2][0];
+ dy = besty - p[2][2][1];
+ memset(nc, 0, sizeof(nc));
+ memset(c, 0, sizeof(c));
+ /*We consider 8 lines across the finder pattern in turn.
+ If we actually found a symmetric pattern along that line, search for its
+ exact center in the image.
+ There are plenty more lines we could use if these don't work, but if we've
+ found anything remotely close to an alignment pattern, we should be able
+ to use most of these.*/
+ for (i = 0; i < 8; i++) {
+ static const unsigned MASK_TESTS[8][2] = {
+ { 0x1040041, 0x1000001 }, { 0x0041040, 0x0001000 },
+ { 0x0110110, 0x0100010 }, { 0x0011100, 0x0001000 },
+ { 0x0420084, 0x0400004 }, { 0x0021080, 0x0001000 },
+ { 0x0006C00, 0x0004400 }, { 0x0003800, 0x0001000 },
+ };
+ static const unsigned char MASK_COORDS[8][2] = { { 0, 0 }, { 1, 1 },
+ { 4, 0 }, { 3, 1 },
+ { 2, 0 }, { 2, 1 },
+ { 0, 2 }, { 1, 2 } };
+ if ((best_match & MASK_TESTS[i][0]) == MASK_TESTS[i][1]) {
+ int x0;
+ int y0;
+ int x1;
+ int y1;
+ x0 = p[MASK_COORDS[i][1]][MASK_COORDS[i][0]][0] + dx >>
+ QR_FINDER_SUBPREC;
+ if (x0 < 0 || x0 >= _width)
+ continue;
+ y0 = p[MASK_COORDS[i][1]][MASK_COORDS[i][0]][1] + dy >>
+ QR_FINDER_SUBPREC;
+ if (y0 < 0 || y0 >= _height)
+ continue;
+ x1 = p[4 - MASK_COORDS[i][1]][4 - MASK_COORDS[i][0]][0] + dx >>
+ QR_FINDER_SUBPREC;
+ if (x1 < 0 || x1 >= _width)
+ continue;
+ y1 = p[4 - MASK_COORDS[i][1]][4 - MASK_COORDS[i][0]][1] + dy >>
+ QR_FINDER_SUBPREC;
+ if (y1 < 0 || y1 >= _height)
+ continue;
+ if (!qr_finder_locate_crossing(_img, _width, _height, x0, y0, x1,
+ y1, i & 1, pc)) {
+ int w;
+ int cx;
+ int cy;
+ cx = pc[0] - bestx;
+ cy = pc[1] - besty;
+ if (i & 1) {
+ /*Weight crossings around the center dot more highly, as they are
+ generally more reliable.*/
+ w = 3;
+ cx += cx << 1;
+ cy += cy << 1;
+ } else
+ w = 1;
+ nc[i >> 1] += w;
+ c[i >> 1][0] += cx;
+ c[i >> 1][1] += cy;
+ }
+ }
+ }
+ /*Sum offsets from lines in orthogonal directions.*/
+ for (i = 0; i < 2; i++) {
+ int a;
+ int b;
+ a = nc[i << 1];
+ b = nc[i << 1 | 1];
+ if (a && b) {
+ int w;
+ w = QR_MAXI(a, b);
+ c[i << 1][0] =
+ QR_DIVROUND(w * (b * c[i << 1][0] + a * c[i << 1 | 1][0]),
+ a * b);
+ c[i << 1][1] =
+ QR_DIVROUND(w * (b * c[i << 1][1] + a * c[i << 1 | 1][1]),
+ a * b);
+ nc[i << 1] = w << 1;
+ } else {
+ c[i << 1][0] += c[i << 1 | 1][0];
+ c[i << 1][1] += c[i << 1 | 1][1];
+ nc[i << 1] += b;
+ }
+ }
+ /*Average offsets from pairs of orthogonal lines.*/
+ c[0][0] += c[2][0];
+ c[0][1] += c[2][1];
+ nc[0] += nc[2];
+ /*If we actually found any such lines, apply the adjustment.*/
+ if (nc[0]) {
+ dx = QR_DIVROUND(c[0][0], nc[0]);
+ dy = QR_DIVROUND(c[0][1], nc[0]);
+ /*But only if it doesn't make things too much worse.*/
+ match = qr_alignment_pattern_fetch(p, bestx + dx, besty + dy, _img,
+ _width, _height);
+ dist = qr_hamming_dist(match, 0x1F8D63F, best_dist + 1);
+ if (dist <= best_dist + 1) {
+ bestx += dx;
+ besty += dy;
+ }
+ }
+ _p[0] = bestx;
+ _p[1] = besty;
+ return 0;
+}
+
+static int qr_hom_fit(qr_hom *_hom, qr_finder *_ul, qr_finder *_ur,
+ qr_finder *_dl, qr_point _p[4], const qr_aff *_aff,
+ isaac_ctx *_isaac, const unsigned char *_img, int _width,
+ int _height)
+{
+ qr_point *b;
+ int nb;
+ int cb;
+ qr_point *r;
+ int nr;
+ int cr;
+ qr_line l[4];
+ qr_point q;
+ qr_point p;
+ int ox;
+ int oy;
+ int ru;
+ int rv;
+ int dru;
+ int drv;
+ int bu;
+ int bv;
+ int dbu;
+ int dbv;
+ int rx;
+ int ry;
+ int drxi;
+ int dryi;
+ int drxj;
+ int dryj;
+ int rdone;
+ int nrempty;
+ int rlastfit;
+ int bx;
+ int by;
+ int dbxi;
+ int dbyi;
+ int dbxj;
+ int dbyj;
+ int bdone;
+ int nbempty;
+ int blastfit;
+ int shift;
+ int round;
+ int version4;
+ int brx;
+ int bry;
+ int i;
+ /*We attempt to correct large-scale perspective distortion by fitting lines
+ to the edge of the code area.
+ We could also look for an alignment pattern now, but that wouldn't work for
+ version 1 codes, which have no alignment pattern.
+ Even if the code is supposed to have one, there's go guarantee we'd find it
+ intact.*/
+ /*Fitting lines is easy for the edges on which we have two finder patterns.
+ After the fit, UL is guaranteed to be on the proper side, but if either of
+ the other two finder patterns aren't, something is wrong.*/
+ qr_finder_ransac(_ul, _aff, _isaac, 0);
+ qr_finder_ransac(_dl, _aff, _isaac, 0);
+ qr_line_fit_finder_pair(l[0], _aff, _ul, _dl, 0);
+ if (qr_line_eval(l[0], _dl->c->pos[0], _dl->c->pos[1]) < 0 ||
+ qr_line_eval(l[0], _ur->c->pos[0], _ur->c->pos[1]) < 0) {
+ return -1;
+ }
+ qr_finder_ransac(_ul, _aff, _isaac, 2);
+ qr_finder_ransac(_ur, _aff, _isaac, 2);
+ qr_line_fit_finder_pair(l[2], _aff, _ul, _ur, 2);
+ if (qr_line_eval(l[2], _dl->c->pos[0], _dl->c->pos[1]) < 0 ||
+ qr_line_eval(l[2], _ur->c->pos[0], _ur->c->pos[1]) < 0) {
+ return -1;
+ }
+ /*The edges which only have one finder pattern are more difficult.
+ We start by fitting a line to the edge of the one finder pattern we do
+ have.
+ This can fail due to an insufficient number of sample points, and even if
+ it succeeds can be fairly inaccurate, because all of the points are
+ clustered in one corner of the QR code.
+ If it fails, we just use an axis-aligned line in the affine coordinate
+ system.
+ Then we walk along the edge of the entire code, looking for
+ light:dark:light patterns perpendicular to the edge.
+ Wherever we find one, we take the center of the dark portion as an
+ additional sample point.
+ At the end, we re-fit the line using all such sample points found.*/
+ drv = _ur->size[1] >> 1;
+ qr_finder_ransac(_ur, _aff, _isaac, 1);
+ if (qr_line_fit_finder_edge(l[1], _ur, 1, _aff->res) >= 0) {
+ if (qr_line_eval(l[1], _ul->c->pos[0], _ul->c->pos[1]) < 0 ||
+ qr_line_eval(l[1], _dl->c->pos[0], _dl->c->pos[1]) < 0) {
+ return -1;
+ }
+ /*Figure out the change in ru for a given change in rv when stepping along
+ the fitted line.*/
+ if (qr_aff_line_step(_aff, l[1], 1, drv, &dru) < 0)
+ return -1;
+ } else
+ dru = 0;
+ ru = _ur->o[0] + 3 * _ur->size[0] - 2 * dru;
+ rv = _ur->o[1] - 2 * drv;
+ dbu = _dl->size[0] >> 1;
+ qr_finder_ransac(_dl, _aff, _isaac, 3);
+ if (qr_line_fit_finder_edge(l[3], _dl, 3, _aff->res) >= 0) {
+ if (qr_line_eval(l[3], _ul->c->pos[0], _ul->c->pos[1]) < 0 ||
+ qr_line_eval(l[3], _ur->c->pos[0], _ur->c->pos[1]) < 0) {
+ return -1;
+ }
+ /*Figure out the change in bv for a given change in bu when stepping along
+ the fitted line.*/
+ if (qr_aff_line_step(_aff, l[3], 0, dbu, &dbv) < 0)
+ return -1;
+ } else
+ dbv = 0;
+ bu = _dl->o[0] - 2 * dbu;
+ bv = _dl->o[1] + 3 * _dl->size[1] - 2 * dbv;
+ /*Set up the initial point lists.*/
+ nr = rlastfit = _ur->ninliers[1];
+ cr = nr + (_dl->o[1] - rv + drv - 1) / drv;
+ r = (qr_point *)malloc(cr * sizeof(*r));
+ for (i = 0; i < _ur->ninliers[1]; i++) {
+ memcpy(r[i], _ur->edge_pts[1][i].pos, sizeof(r[i]));
+ }
+ nb = blastfit = _dl->ninliers[3];
+ cb = nb + (_ur->o[0] - bu + dbu - 1) / dbu;
+ b = (qr_point *)malloc(cb * sizeof(*b));
+ for (i = 0; i < _dl->ninliers[3]; i++) {
+ memcpy(b[i], _dl->edge_pts[3][i].pos, sizeof(b[i]));
+ }
+ /*Set up the step parameters for the affine projection.*/
+ ox = (_aff->x0 << _aff->res) + (1 << _aff->res - 1);
+ oy = (_aff->y0 << _aff->res) + (1 << _aff->res - 1);
+ rx = _aff->fwd[0][0] * ru + _aff->fwd[0][1] * rv + ox;
+ ry = _aff->fwd[1][0] * ru + _aff->fwd[1][1] * rv + oy;
+ drxi = _aff->fwd[0][0] * dru + _aff->fwd[0][1] * drv;
+ dryi = _aff->fwd[1][0] * dru + _aff->fwd[1][1] * drv;
+ drxj = _aff->fwd[0][0] * _ur->size[0];
+ dryj = _aff->fwd[1][0] * _ur->size[0];
+ bx = _aff->fwd[0][0] * bu + _aff->fwd[0][1] * bv + ox;
+ by = _aff->fwd[1][0] * bu + _aff->fwd[1][1] * bv + oy;
+ dbxi = _aff->fwd[0][0] * dbu + _aff->fwd[0][1] * dbv;
+ dbyi = _aff->fwd[1][0] * dbu + _aff->fwd[1][1] * dbv;
+ dbxj = _aff->fwd[0][1] * _dl->size[1];
+ dbyj = _aff->fwd[1][1] * _dl->size[1];
+ /*Now step along the lines, looking for new sample points.*/
+ nrempty = nbempty = 0;
+ for (;;) {
+ int ret;
+ int x0;
+ int y0;
+ int x1;
+ int y1;
+ /*If we take too many steps without encountering a non-zero pixel, assume
+ we have wandered off the edge and stop looking before we hit the other
+ side of the quiet region.
+ Otherwise, stop when the lines cross (if they do so inside the affine
+ region) or come close to crossing (outside the affine region).
+ TODO: We don't have any way of detecting when we've wandered into the
+ code interior; we could stop if the outside sample ever shows up dark,
+ but this could happen because of noise in the quiet region, too.*/
+ rdone = rv >= QR_MINI(bv, _dl->o[1] + bv >> 1) || nrempty > 14;
+ bdone = bu >= QR_MINI(ru, _ur->o[0] + ru >> 1) || nbempty > 14;
+ if (!rdone && (bdone || rv < bu)) {
+ x0 = rx + drxj >> _aff->res + QR_FINDER_SUBPREC;
+ y0 = ry + dryj >> _aff->res + QR_FINDER_SUBPREC;
+ x1 = rx - drxj >> _aff->res + QR_FINDER_SUBPREC;
+ y1 = ry - dryj >> _aff->res + QR_FINDER_SUBPREC;
+ if (nr >= cr) {
+ cr = cr << 1 | 1;
+ r = (qr_point *)realloc(r, cr * sizeof(*r));
+ }
+ ret = qr_finder_quick_crossing_check(_img, _width, _height, x0, y0,
+ x1, y1, 1);
+ if (!ret) {
+ ret = qr_finder_locate_crossing(_img, _width, _height, x0, y0,
+ x1, y1, 1, r[nr]);
+ }
+ if (ret >= 0) {
+ if (!ret) {
+ qr_aff_unproject(q, _aff, r[nr][0], r[nr][1]);
+ /*Move the current point halfway towards the crossing.
+ We don't move the whole way to give us some robustness to noise.*/
+ ru = ru + q[0] >> 1;
+ /*But ensure that rv monotonically increases.*/
+ if (q[1] + drv > rv)
+ rv = rv + q[1] >> 1;
+ rx = _aff->fwd[0][0] * ru + _aff->fwd[0][1] * rv + ox;
+ ry = _aff->fwd[1][0] * ru + _aff->fwd[1][1] * rv + oy;
+ nr++;
+ /*Re-fit the line to update the step direction periodically.*/
+ if (nr > QR_MAXI(1, rlastfit + (rlastfit >> 2))) {
+ qr_line_fit_points(l[1], r, nr, _aff->res);
+ if (qr_aff_line_step(_aff, l[1], 1, drv, &dru) >= 0) {
+ drxi =
+ _aff->fwd[0][0] * dru + _aff->fwd[0][1] * drv;
+ dryi =
+ _aff->fwd[1][0] * dru + _aff->fwd[1][1] * drv;
+ }
+ rlastfit = nr;
+ }
+ }
+ nrempty = 0;
+ } else
+ nrempty++;
+ ru += dru;
+ /*Our final defense: if we overflow, stop.*/
+ if (rv + drv > rv)
+ rv += drv;
+ else
+ nrempty = INT_MAX;
+ rx += drxi;
+ ry += dryi;
+ } else if (!bdone) {
+ x0 = bx + dbxj >> _aff->res + QR_FINDER_SUBPREC;
+ y0 = by + dbyj >> _aff->res + QR_FINDER_SUBPREC;
+ x1 = bx - dbxj >> _aff->res + QR_FINDER_SUBPREC;
+ y1 = by - dbyj >> _aff->res + QR_FINDER_SUBPREC;
+ if (nb >= cb) {
+ cb = cb << 1 | 1;
+ b = (qr_point *)realloc(b, cb * sizeof(*b));
+ }
+ ret = qr_finder_quick_crossing_check(_img, _width, _height, x0, y0,
+ x1, y1, 1);
+ if (!ret) {
+ ret = qr_finder_locate_crossing(_img, _width, _height, x0, y0,
+ x1, y1, 1, b[nb]);
+ }
+ if (ret >= 0) {
+ if (!ret) {
+ qr_aff_unproject(q, _aff, b[nb][0], b[nb][1]);
+ /*Move the current point halfway towards the crossing.
+ We don't move the whole way to give us some robustness to noise.*/
+ /*But ensure that bu monotonically increases.*/
+ if (q[0] + dbu > bu)
+ bu = bu + q[0] >> 1;
+ bv = bv + q[1] >> 1;
+ bx = _aff->fwd[0][0] * bu + _aff->fwd[0][1] * bv + ox;
+ by = _aff->fwd[1][0] * bu + _aff->fwd[1][1] * bv + oy;
+ nb++;
+ /*Re-fit the line to update the step direction periodically.*/
+ if (nb > QR_MAXI(1, blastfit + (blastfit >> 2))) {
+ qr_line_fit_points(l[3], b, nb, _aff->res);
+ if (qr_aff_line_step(_aff, l[3], 0, dbu, &dbv) >= 0) {
+ dbxi =
+ _aff->fwd[0][0] * dbu + _aff->fwd[0][1] * dbv;
+ dbyi =
+ _aff->fwd[1][0] * dbu + _aff->fwd[1][1] * dbv;
+ }
+ blastfit = nb;
+ }
+ }
+ nbempty = 0;
+ } else
+ nbempty++;
+ /*Our final defense: if we overflow, stop.*/
+ if (bu + dbu > bu)
+ bu += dbu;
+ else
+ nbempty = INT_MAX;
+ bv += dbv;
+ bx += dbxi;
+ by += dbyi;
+ } else
+ break;
+ }
+ /*Fit the new lines.
+ If we _still_ don't have enough sample points, then just use an
+ axis-aligned line from the affine coordinate system (e.g., one parallel
+ to the opposite edge in the image).*/
+ if (nr > 1)
+ qr_line_fit_points(l[1], r, nr, _aff->res);
+ else {
+ qr_aff_project(p, _aff, _ur->o[0] + 3 * _ur->size[0], _ur->o[1]);
+ shift = QR_MAXI(0, qr_ilog(QR_MAXI(abs(_aff->fwd[0][1]),
+ abs(_aff->fwd[1][1]))) -
+ (_aff->res + 1 >> 1));
+ round = (1 << shift) >> 1;
+ l[1][0] = _aff->fwd[1][1] + round >> shift;
+ l[1][1] = -_aff->fwd[0][1] + round >> shift;
+ l[1][2] = -(l[1][0] * p[0] + l[1][1] * p[1]);
+ }
+ free(r);
+ if (nb > 1)
+ qr_line_fit_points(l[3], b, nb, _aff->res);
+ else {
+ qr_aff_project(p, _aff, _dl->o[0], _dl->o[1] + 3 * _dl->size[1]);
+ shift = QR_MAXI(0, qr_ilog(QR_MAXI(abs(_aff->fwd[0][1]),
+ abs(_aff->fwd[1][1]))) -
+ (_aff->res + 1 >> 1));
+ round = (1 << shift) >> 1;
+ l[3][0] = _aff->fwd[1][0] + round >> shift;
+ l[3][1] = -_aff->fwd[0][0] + round >> shift;
+ l[3][2] = -(l[1][0] * p[0] + l[1][1] * p[1]);
+ }
+ free(b);
+ for (i = 0; i < 4; i++) {
+ if (qr_line_isect(_p[i], l[i & 1], l[2 + (i >> 1)]) < 0)
+ return -1;
+ /*It's plausible for points to be somewhat outside the image, but too far
+ and too much of the pattern will be gone for it to be decodable.*/
+ if (_p[i][0] < -_width << QR_FINDER_SUBPREC ||
+ _p[i][0] >= _width << QR_FINDER_SUBPREC + 1 ||
+ _p[i][1] < -_height << QR_FINDER_SUBPREC ||
+ _p[i][1] >= _height << QR_FINDER_SUBPREC + 1) {
+ return -1;
+ }
+ }
+ /*By default, use the edge intersection point for the bottom-right corner.*/
+ brx = _p[3][0];
+ bry = _p[3][1];
+ /*However, if our average version estimate is greater than 1, NOW we try to
+ search for an alignment pattern.
+ We get a much better success rate by doing this after our initial attempt
+ to promote the transform to a homography than before.
+ You might also think it would be more reliable to use the interior finder
+ pattern edges, since the outer ones may be obscured or damaged, and it
+ would save us a reprojection below, since they would form a nice square
+ with the location of the alignment pattern, but this turns out to be a bad
+ idea.
+ Non-linear distortion is usually maximal on the outside edge, and thus
+ estimating the grid position from points on the interior means we might
+ get mis-aligned by the time we reach the edge.*/
+ version4 = _ul->eversion[0] + _ul->eversion[1] + _ur->eversion[0] +
+ _dl->eversion[1];
+ if (version4 > 4) {
+ qr_hom_cell cell;
+ qr_point p3;
+ int dim;
+ dim = 17 + version4;
+ qr_hom_cell_init(&cell, 0, 0, dim - 1, 0, 0, dim - 1, dim - 1, dim - 1,
+ _p[0][0], _p[0][1], _p[1][0], _p[1][1], _p[2][0],
+ _p[2][1], _p[3][0], _p[3][1]);
+ if (qr_alignment_pattern_search(p3, &cell, dim - 7, dim - 7, 4, _img,
+ _width, _height) >= 0) {
+ long long w;
+ long long mask;
+ int c21;
+ int dx21;
+ int dy21;
+ /*There's no real need to update the bounding box corner, and in fact we
+ actively perform worse if we do.
+ Clearly it was good enough for us to find this alignment pattern, so
+ it should be good enough to use for grid initialization.
+ The point of doing the search was to get more accurate version
+ estimates and a better chance of decoding the version and format info.
+ This is particularly important for small versions that have no encoded
+ version info, since any mismatch in version renders the code
+ undecodable.*/
+ /*We do, however, need four points in a square to initialize our
+ homography, so project the point from the alignment center to the
+ corner of the code area.*/
+ c21 = _p[2][0] * _p[1][1] - _p[2][1] * _p[1][0];
+ dx21 = _p[2][0] - _p[1][0];
+ dy21 = _p[2][1] - _p[1][1];
+ w = QR_EXTMUL(dim - 7, c21,
+ QR_EXTMUL(dim - 13, _p[0][0] * dy21 - _p[0][1] * dx21,
+ QR_EXTMUL(6, p3[0] * dy21 - p3[1] * dx21,
+ 0)));
+ /*The projection failed: invalid geometry.*/
+ if (w == 0)
+ return -1;
+ mask = QR_SIGNMASK(w);
+ w = w + mask ^ mask;
+ brx = (int)QR_DIVROUND(
+ QR_EXTMUL((dim - 7) * _p[0][0], p3[0] * dy21,
+ QR_EXTMUL((dim - 13) * p3[0], c21 - _p[0][1] * dx21,
+ QR_EXTMUL(6 * _p[0][0], c21 - p3[1] * dx21,
+ 0))) +
+ mask ^
+ mask,
+ w);
+ bry = (int)QR_DIVROUND(
+ QR_EXTMUL((dim - 7) * _p[0][1], -p3[1] * dx21,
+ QR_EXTMUL((dim - 13) * p3[1], c21 + _p[0][0] * dy21,
+ QR_EXTMUL(6 * _p[0][1], c21 + p3[0] * dy21,
+ 0))) +
+ mask ^
+ mask,
+ w);
+ }
+ }
+ /*Now we have four points that map to a square: initialize the projection.*/
+ qr_hom_init(_hom, _p[0][0], _p[0][1], _p[1][0], _p[1][1], _p[2][0],
+ _p[2][1], brx, bry, QR_HOM_BITS);
+ return 0;
+}
+
+/*The BCH(18,6,3) codes are only used for version information, which must lie
+ between 7 and 40 (inclusive).*/
+static const unsigned BCH18_6_CODES[34] = {
+ 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847,
+ 0x0E60D, 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6,
+ 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, 0x1B08E,
+ 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA,
+ 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69
+};
+
+/*Corrects a BCH(18,6,3) code word.
+ _y: Contains the code word to be checked on input, and the corrected value on
+ output.
+ Return: The number of errors.
+ If more than 3 errors are detected, returns a negative value and
+ performs no correction.*/
+static int bch18_6_correct(unsigned *_y)
+{
+ unsigned x;
+ unsigned y;
+ int nerrs;
+ y = *_y;
+ /*Check the easy case first: see if the data bits were uncorrupted.*/
+ x = y >> 12;
+ if (x >= 7 && x <= 40) {
+ nerrs = qr_hamming_dist(y, BCH18_6_CODES[x - 7], 4);
+ if (nerrs < 4) {
+ *_y = BCH18_6_CODES[x - 7];
+ return nerrs;
+ }
+ }
+ /*Exhaustive search is faster than field operations in GF(19).*/
+ for (x = 0; x < 34; x++)
+ if (x + 7 != y >> 12) {
+ nerrs = qr_hamming_dist(y, BCH18_6_CODES[x], 4);
+ if (nerrs < 4) {
+ *_y = BCH18_6_CODES[x];
+ return nerrs;
+ }
+ }
+ return -1;
+}
+
+#if 0
+static unsigned bch18_6_encode(unsigned _x){
+ return (-(_x&1)&0x01F25)^(-(_x>>1&1)&0x0216F)^(-(_x>>2&1)&0x042DE)^
+ (-(_x>>3&1)&0x085BC)^(-(_x>>4&1)&0x10B78)^(-(_x>>5&1)&0x209D5);
+}
+#endif
+
+/*Reads the version bits near a finder module and decodes the version number.*/
+static int qr_finder_version_decode(qr_finder *_f, const qr_hom *_hom,
+ const unsigned char *_img, int _width,
+ int _height, int _dir)
+{
+ qr_point q;
+ unsigned v;
+ int x0;
+ int y0;
+ int w0;
+ int dxi;
+ int dyi;
+ int dwi;
+ int dxj;
+ int dyj;
+ int dwj;
+ int ret;
+ int i;
+ int j;
+ int k;
+ v = 0;
+ q[_dir] = _f->o[_dir] - 7 * _f->size[_dir];
+ q[1 - _dir] = _f->o[1 - _dir] - 3 * _f->size[1 - _dir];
+ x0 = _hom->fwd[0][0] * q[0] + _hom->fwd[0][1] * q[1];
+ y0 = _hom->fwd[1][0] * q[0] + _hom->fwd[1][1] * q[1];
+ w0 = _hom->fwd[2][0] * q[0] + _hom->fwd[2][1] * q[1] + _hom->fwd22;
+ dxi = _hom->fwd[0][1 - _dir] * _f->size[1 - _dir];
+ dyi = _hom->fwd[1][1 - _dir] * _f->size[1 - _dir];
+ dwi = _hom->fwd[2][1 - _dir] * _f->size[1 - _dir];
+ dxj = _hom->fwd[0][_dir] * _f->size[_dir];
+ dyj = _hom->fwd[1][_dir] * _f->size[_dir];
+ dwj = _hom->fwd[2][_dir] * _f->size[_dir];
+ for (k = i = 0; i < 6; i++) {
+ int x;
+ int y;
+ int w;
+ x = x0;
+ y = y0;
+ w = w0;
+ for (j = 0; j < 3; j++, k++) {
+ qr_point p;
+ qr_hom_fproject(p, _hom, x, y, w);
+ v |= qr_img_get_bit(_img, _width, _height, p[0], p[1]) << k;
+ x += dxj;
+ y += dyj;
+ w += dwj;
+ }
+ x0 += dxi;
+ y0 += dyi;
+ w0 += dwi;
+ }
+ ret = bch18_6_correct(&v);
+ /*TODO: I seem to have an image with the version bits in a different order
+ (the transpose of the standard order).
+ Even if I change the order here so I can parse the version on this image,
+ I can't decode the rest of the code.
+ If this is really needed, we should just re-order the bits.*/
+#if 0
+ if(ret<0){
+ /*17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ 0 3 6 9 12 15 1 4 7 10 13 16 2 5 8 11 14 17
+ 17 13 9 5 1 -3 10 6 2 -2 -6-10 3 -1 -5 -9-13-17*/
+ v=0;
+ for(k=i=0;i<3;i++){
+ p[_dir]=_f->o[_dir]+_f->size[_dir]*(-5-i);
+ for(j=0;j<6;j++,k++){
+ qr_point q;
+ p[1-_dir]=_f->o[1-_dir]+_f->size[1-_dir]*(2-j);
+ qr_hom_project(q,_hom,p[0],p[1]);
+ v|=qr_img_get_bit(_img,_width,_height,q[0],q[1])<<k;
+ }
+ }
+ ret=bch18_6_correct(&v);
+ }
+#endif
+ return ret >= 0 ? (int)(v >> 12) : ret;
+}
+
+/*Reads the format info bits near the finder modules and decodes them.*/
+static int qr_finder_fmt_info_decode(qr_finder *_ul, qr_finder *_ur,
+ qr_finder *_dl, const qr_hom *_hom,
+ const unsigned char *_img, int _width,
+ int _height)
+{
+ qr_point p;
+ unsigned lo[2];
+ unsigned hi[2];
+ int u;
+ int v;
+ int x;
+ int y;
+ int w;
+ int dx;
+ int dy;
+ int dw;
+ int fmt_info[4];
+ int count[4];
+ int nerrs[4];
+ int nfmt_info;
+ int besti;
+ int imax;
+ int di;
+ int i;
+ int k;
+ /*Read the bits around the UL corner.*/
+ lo[0] = 0;
+ u = _ul->o[0] + 5 * _ul->size[0];
+ v = _ul->o[1] - 3 * _ul->size[1];
+ x = _hom->fwd[0][0] * u + _hom->fwd[0][1] * v;
+ y = _hom->fwd[1][0] * u + _hom->fwd[1][1] * v;
+ w = _hom->fwd[2][0] * u + _hom->fwd[2][1] * v + _hom->fwd22;
+ dx = _hom->fwd[0][1] * _ul->size[1];
+ dy = _hom->fwd[1][1] * _ul->size[1];
+ dw = _hom->fwd[2][1] * _ul->size[1];
+ for (k = i = 0;; i++) {
+ /*Skip the timing pattern row.*/
+ if (i != 6) {
+ qr_hom_fproject(p, _hom, x, y, w);
+ lo[0] |= qr_img_get_bit(_img, _width, _height, p[0], p[1]) << k++;
+ /*Don't advance q in the last iteration... we'll start the next loop from
+ the current position.*/
+ if (i >= 8)
+ break;
+ }
+ x += dx;
+ y += dy;
+ w += dw;
+ }
+ hi[0] = 0;
+ dx = -_hom->fwd[0][0] * _ul->size[0];
+ dy = -_hom->fwd[1][0] * _ul->size[0];
+ dw = -_hom->fwd[2][0] * _ul->size[0];
+ while (i-- > 0) {
+ x += dx;
+ y += dy;
+ w += dw;
+ /*Skip the timing pattern column.*/
+ if (i != 6) {
+ qr_hom_fproject(p, _hom, x, y, w);
+ hi[0] |= qr_img_get_bit(_img, _width, _height, p[0], p[1]) << k++;
+ }
+ }
+ /*Read the bits next to the UR corner.*/
+ lo[1] = 0;
+ u = _ur->o[0] + 3 * _ur->size[0];
+ v = _ur->o[1] + 5 * _ur->size[1];
+ x = _hom->fwd[0][0] * u + _hom->fwd[0][1] * v;
+ y = _hom->fwd[1][0] * u + _hom->fwd[1][1] * v;
+ w = _hom->fwd[2][0] * u + _hom->fwd[2][1] * v + _hom->fwd22;
+ dx = -_hom->fwd[0][0] * _ur->size[0];
+ dy = -_hom->fwd[1][0] * _ur->size[0];
+ dw = -_hom->fwd[2][0] * _ur->size[0];
+ for (k = 0; k < 8; k++) {
+ qr_hom_fproject(p, _hom, x, y, w);
+ lo[1] |= qr_img_get_bit(_img, _width, _height, p[0], p[1]) << k;
+ x += dx;
+ y += dy;
+ w += dw;
+ }
+ /*Read the bits next to the DL corner.*/
+ hi[1] = 0;
+ u = _dl->o[0] + 5 * _dl->size[0];
+ v = _dl->o[1] - 3 * _dl->size[1];
+ x = _hom->fwd[0][0] * u + _hom->fwd[0][1] * v;
+ y = _hom->fwd[1][0] * u + _hom->fwd[1][1] * v;
+ w = _hom->fwd[2][0] * u + _hom->fwd[2][1] * v + _hom->fwd22;
+ dx = _hom->fwd[0][1] * _dl->size[1];
+ dy = _hom->fwd[1][1] * _dl->size[1];
+ dw = _hom->fwd[2][1] * _dl->size[1];
+ for (k = 8; k < 15; k++) {
+ qr_hom_fproject(p, _hom, x, y, w);
+ hi[1] |= qr_img_get_bit(_img, _width, _height, p[0], p[1]) << k;
+ x += dx;
+ y += dy;
+ w += dw;
+ }
+ /*For each group of bits we have two samples... try them in all combinations
+ and pick the most popular valid code, breaking ties using the number of
+ bit errors.*/
+ imax = 2 << (hi[0] != hi[1]);
+ di = 1 + (lo[0] == lo[1]);
+ nfmt_info = 0;
+ for (i = 0; i < imax; i += di) {
+ unsigned v;
+ int ret;
+ int j;
+ v = (lo[i & 1] | hi[i >> 1]) ^ 0x5412;
+ ret = bch15_5_correct(&v);
+ v >>= 10;
+ if (ret < 0)
+ ret = 4;
+ for (j = 0;; j++) {
+ if (j >= nfmt_info) {
+ fmt_info[j] = v;
+ count[j] = 1;
+ nerrs[j] = ret;
+ nfmt_info++;
+ break;
+ }
+ if (fmt_info[j] == (int)v) {
+ count[j]++;
+ if (ret < nerrs[j])
+ nerrs[j] = ret;
+ break;
+ }
+ }
+ }
+ besti = 0;
+ for (i = 1; i < nfmt_info; i++) {
+ if (nerrs[besti] > 3 && nerrs[i] <= 3 || count[i] > count[besti] ||
+ count[i] == count[besti] && nerrs[i] < nerrs[besti]) {
+ besti = i;
+ }
+ }
+ return nerrs[besti] < 4 ? fmt_info[besti] : -1;
+}
+
+/*The grid used to sample the image bits.
+ The grid is divided into separate cells bounded by finder patterns and/or
+ alignment patterns, and a separate map back to the original image is
+ constructed for each cell.
+ All of these structural elements, as well as the timing patterns, version
+ info, and format info, are marked in fpmask so they can easily be skipped
+ during decode.*/
+struct qr_sampling_grid {
+ qr_hom_cell *cells[6];
+ unsigned *fpmask;
+ int cell_limits[6];
+ int ncells;
+};
+
+/*Mark a given region as belonging to the function pattern.*/
+static void qr_sampling_grid_fp_mask_rect(qr_sampling_grid *_grid, int _dim,
+ int _u, int _v, int _w, int _h)
+{
+ int i;
+ int j;
+ int stride;
+ stride = _dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS;
+ /*Note that we store bits column-wise, since that's how they're read out of
+ the grid.*/
+ for (j = _u; j < _u + _w; j++)
+ for (i = _v; i < _v + _h; i++) {
+ _grid->fpmask[j * stride + (i >> QR_INT_LOGBITS)] |=
+ 1 << (i & QR_INT_BITS - 1);
+ }
+}
+
+/*Determine if a given grid location is inside the function pattern.*/
+static int qr_sampling_grid_is_in_fp(const qr_sampling_grid *_grid, int _dim,
+ int _u, int _v)
+{
+ return _grid->fpmask[_u * (_dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS) +
+ (_v >> QR_INT_LOGBITS)] >>
+ (_v & QR_INT_BITS - 1) &
+ 1;
+}
+
+/*The spacing between alignment patterns after the second for versions >= 7.
+ We could compact this more, but the code to access it would eliminate the
+ gains.*/
+static const unsigned char QR_ALIGNMENT_SPACING[34] = {
+ 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24,
+ 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28
+};
+
+static inline void qr_svg_points(const char *cls, qr_point *p, int n)
+{
+ int i;
+ svg_path_start(cls, 1, 0, 0);
+ for (i = 0; i < n; i++, p++)
+ svg_path_moveto(SVG_ABS, p[0][0], p[0][1]);
+ svg_path_end();
+}
+
+/*Initialize the sampling grid for each region of the code.
+ _version: The (decoded) version number.
+ _ul_pos: The location of the UL finder pattern.
+ _ur_pos: The location of the UR finder pattern.
+ _dl_pos: The location of the DL finder pattern.
+ _p: On input, contains estimated positions of the four corner modules.
+ On output, contains a bounding quadrilateral for the code.
+ _img: The binary input image.
+ _width: The width of the input image.
+ _height: The height of the input image.
+ Return: 0 on success, or a negative value on error.*/
+static void qr_sampling_grid_init(qr_sampling_grid *_grid, int _version,
+ const qr_point _ul_pos,
+ const qr_point _ur_pos,
+ const qr_point _dl_pos, qr_point _p[4],
+ const unsigned char *_img, int _width,
+ int _height)
+{
+ qr_hom_cell base_cell;
+ int align_pos[7];
+ int dim;
+ int nalign;
+ int i;
+ dim = 17 + (_version << 2);
+ nalign = (_version / 7) + 2;
+ /*Create a base cell to bootstrap the alignment pattern search.*/
+ qr_hom_cell_init(&base_cell, 0, 0, dim - 1, 0, 0, dim - 1, dim - 1, dim - 1,
+ _p[0][0], _p[0][1], _p[1][0], _p[1][1], _p[2][0], _p[2][1],
+ _p[3][0], _p[3][1]);
+ /*Allocate the array of cells.*/
+ _grid->ncells = nalign - 1;
+ _grid->cells[0] = (qr_hom_cell *)malloc((nalign - 1) * (nalign - 1) *
+ sizeof(*_grid->cells[0]));
+ for (i = 1; i < _grid->ncells; i++)
+ _grid->cells[i] = _grid->cells[i - 1] + _grid->ncells;
+ /*Initialize the function pattern mask.*/
+ _grid->fpmask =
+ (unsigned *)calloc(dim, (dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS) *
+ sizeof(*_grid->fpmask));
+ /*Mask out the finder patterns (and separators and format info bits).*/
+ qr_sampling_grid_fp_mask_rect(_grid, dim, 0, 0, 9, 9);
+ qr_sampling_grid_fp_mask_rect(_grid, dim, 0, dim - 8, 9, 8);
+ qr_sampling_grid_fp_mask_rect(_grid, dim, dim - 8, 0, 8, 9);
+ /*Mask out the version number bits.*/
+ if (_version > 6) {
+ qr_sampling_grid_fp_mask_rect(_grid, dim, 0, dim - 11, 6, 3);
+ qr_sampling_grid_fp_mask_rect(_grid, dim, dim - 11, 0, 3, 6);
+ }
+ /*Mask out the timing patterns.*/
+ qr_sampling_grid_fp_mask_rect(_grid, dim, 9, 6, dim - 17, 1);
+ qr_sampling_grid_fp_mask_rect(_grid, dim, 6, 9, 1, dim - 17);
+ /*If we have no alignment patterns (e.g., this is a version 1 code), just use
+ the base cell and hope it's good enough.*/
+ if (_version < 2)
+ memcpy(_grid->cells[0], &base_cell, sizeof(base_cell));
+ else {
+ qr_point *q;
+ qr_point *p;
+ int j;
+ int k;
+ q = (qr_point *)malloc(nalign * nalign * sizeof(*q));
+ p = (qr_point *)malloc(nalign * nalign * sizeof(*p));
+ /*Initialize the alignment pattern position list.*/
+ align_pos[0] = 6;
+ align_pos[nalign - 1] = dim - 7;
+ if (_version > 6) {
+ int d;
+ d = QR_ALIGNMENT_SPACING[_version - 7];
+ for (i = nalign - 1; i-- > 1;)
+ align_pos[i] = align_pos[i + 1] - d;
+ }
+ /*Three of the corners use a finder pattern instead of a separate
+ alignment pattern.*/
+ q[0][0] = 3;
+ q[0][1] = 3;
+ p[0][0] = _ul_pos[0];
+ p[0][1] = _ul_pos[1];
+ q[nalign - 1][0] = dim - 4;
+ q[nalign - 1][1] = 3;
+ p[nalign - 1][0] = _ur_pos[0];
+ p[nalign - 1][1] = _ur_pos[1];
+ q[(nalign - 1) * nalign][0] = 3;
+ q[(nalign - 1) * nalign][1] = dim - 4;
+ p[(nalign - 1) * nalign][0] = _dl_pos[0];
+ p[(nalign - 1) * nalign][1] = _dl_pos[1];
+ /*Scan for alignment patterns using a diagonal sweep.*/
+ for (k = 1; k < 2 * nalign - 1; k++) {
+ int jmin;
+ int jmax;
+ jmax = QR_MINI(k, nalign - 1) - (k == nalign - 1);
+ jmin = QR_MAXI(0, k - (nalign - 1)) + (k == nalign - 1);
+ for (j = jmin; j <= jmax; j++) {
+ qr_hom_cell *cell;
+ int u;
+ int v;
+ int k;
+ i = jmax - (j - jmin);
+ k = i * nalign + j;
+ u = align_pos[j];
+ v = align_pos[i];
+ q[k][0] = u;
+ q[k][1] = v;
+ /*Mask out the alignment pattern.*/
+ qr_sampling_grid_fp_mask_rect(_grid, dim, u - 2, v - 2, 5, 5);
+ /*Pick a cell to use to govern the alignment pattern search.*/
+ if (i > 1 && j > 1) {
+ qr_point p0;
+ qr_point p1;
+ qr_point p2;
+ /*Each predictor is basically a straight-line extrapolation from two
+ neighboring alignment patterns (except possibly near the opposing
+ finder patterns).*/
+ qr_hom_cell_project(p0, _grid->cells[i - 2] + j - 1, u, v,
+ 0);
+ qr_hom_cell_project(p1, _grid->cells[i - 2] + j - 2, u, v,
+ 0);
+ qr_hom_cell_project(p2, _grid->cells[i - 1] + j - 2, u, v,
+ 0);
+ /*Take the median of the predictions as the search center.*/
+ QR_SORT2I(p0[0], p1[0]);
+ QR_SORT2I(p0[1], p1[1]);
+ QR_SORT2I(p1[0], p2[0]);
+ QR_SORT2I(p1[1], p2[1]);
+ QR_SORT2I(p0[0], p1[0]);
+ QR_SORT2I(p0[1], p1[1]);
+ /*We need a cell that has the target point at a known (u,v) location.
+ Since our cells don't have inverses, just construct one from our
+ neighboring points.*/
+ cell = _grid->cells[i - 1] + j - 1;
+ qr_hom_cell_init(cell, q[k - nalign - 1][0],
+ q[k - nalign - 1][1], q[k - nalign][0],
+ q[k - nalign][1], q[k - 1][0], q[k - 1][1],
+ q[k][0], q[k][1], p[k - nalign - 1][0],
+ p[k - nalign - 1][1], p[k - nalign][0],
+ p[k - nalign][1], p[k - 1][0], p[k - 1][1],
+ p1[0], p1[1]);
+ } else if (i > 1 && j > 0)
+ cell = _grid->cells[i - 2] + j - 1;
+ else if (i > 0 && j > 1)
+ cell = _grid->cells[i - 1] + j - 2;
+ else
+ cell = &base_cell;
+ /*Use a very small search radius.
+ A large displacement here usually means a false positive (e.g., when
+ the real alignment pattern is damaged or missing), which can
+ severely distort the projection.*/
+ qr_alignment_pattern_search(p[k], cell, u, v, 2, _img, _width,
+ _height);
+ if (i > 0 && j > 0) {
+ qr_hom_cell_init(_grid->cells[i - 1] + j - 1,
+ q[k - nalign - 1][0], q[k - nalign - 1][1],
+ q[k - nalign][0], q[k - nalign][1],
+ q[k - 1][0], q[k - 1][1], q[k][0], q[k][1],
+ p[k - nalign - 1][0], p[k - nalign - 1][1],
+ p[k - nalign][0], p[k - nalign][1],
+ p[k - 1][0], p[k - 1][1], p[k][0],
+ p[k][1]);
+ }
+ }
+ }
+ qr_svg_points("align", p, nalign * nalign);
+ free(q);
+ free(p);
+ }
+ /*Set the limits over which each cell is used.*/
+ memcpy(_grid->cell_limits, align_pos + 1,
+ (_grid->ncells - 1) * sizeof(*_grid->cell_limits));
+ _grid->cell_limits[_grid->ncells - 1] = dim;
+ /*Produce a bounding square for the code (to mark finder centers with).
+ Because of non-linear distortion, this might not actually bound the code,
+ but it should be good enough.
+ I don't think it's worth computing a convex hull or anything silly like
+ that.*/
+ qr_hom_cell_project(_p[0], _grid->cells[0] + 0, -1, -1, 1);
+ qr_hom_cell_project(_p[1], _grid->cells[0] + _grid->ncells - 1,
+ (dim << 1) - 1, -1, 1);
+ qr_hom_cell_project(_p[2], _grid->cells[_grid->ncells - 1] + 0, -1,
+ (dim << 1) - 1, 1);
+ qr_hom_cell_project(_p[3],
+ _grid->cells[_grid->ncells - 1] + _grid->ncells - 1,
+ (dim << 1) - 1, (dim << 1) - 1, 1);
+ /*Clamp the points somewhere near the image (this is really just in case a
+ corner is near the plane at infinity).*/
+ for (i = 0; i < 4; i++) {
+ _p[i][0] = QR_CLAMPI(-_width << QR_FINDER_SUBPREC, _p[i][0],
+ _width << QR_FINDER_SUBPREC + 1);
+ _p[i][1] = QR_CLAMPI(-_height << QR_FINDER_SUBPREC, _p[i][1],
+ _height << QR_FINDER_SUBPREC + 1);
+ }
+ /*TODO: Make fine adjustments using the timing patterns.
+ Possible strategy: scan the timing pattern at QR_ALIGN_SUBPREC (or finer)
+ resolution, use dynamic programming to match midpoints between
+ transitions to the ideal grid locations.*/
+}
+
+static void qr_sampling_grid_clear(qr_sampling_grid *_grid)
+{
+ free(_grid->fpmask);
+ free(_grid->cells[0]);
+}
+
+#if defined(QR_DEBUG)
+static void qr_sampling_grid_dump(qr_sampling_grid *_grid, int _version,
+ const unsigned char *_img, int _width,
+ int _height)
+{
+ unsigned char *gimg;
+ FILE *fout;
+ int dim;
+ int u;
+ int v;
+ int x;
+ int y;
+ int w;
+ int i;
+ int j;
+ int r;
+ int s;
+ dim = 17 + (_version << 2) + 8 << QR_ALIGN_SUBPREC;
+ gimg = (unsigned char *)malloc(dim * dim * sizeof(*gimg));
+ for (i = 0; i < dim; i++)
+ for (j = 0; j < dim; j++) {
+ qr_hom_cell *cell;
+ if (i >= (4 << QR_ALIGN_SUBPREC) &&
+ i <= dim - (5 << QR_ALIGN_SUBPREC) &&
+ j >= (4 << QR_ALIGN_SUBPREC) &&
+ j <= dim - (5 << QR_ALIGN_SUBPREC) &&
+ ((!(i & (1 << QR_ALIGN_SUBPREC) - 1)) ^
+ (!(j & (1 << QR_ALIGN_SUBPREC) - 1)))) {
+ gimg[i * dim + j] = 0x7F;
+ } else {
+ qr_point p;
+ u = (j >> QR_ALIGN_SUBPREC) - 4;
+ v = (i >> QR_ALIGN_SUBPREC) - 4;
+ for (r = 0; r < _grid->ncells - 1; r++)
+ if (u < _grid->cell_limits[r])
+ break;
+ for (s = 0; s < _grid->ncells - 1; s++)
+ if (v < _grid->cell_limits[s])
+ break;
+ cell = _grid->cells[s] + r;
+ u = j - (cell->u0 + 4 << QR_ALIGN_SUBPREC);
+ v = i - (cell->v0 + 4 << QR_ALIGN_SUBPREC);
+ x = cell->fwd[0][0] * u + cell->fwd[0][1] * v +
+ (cell->fwd[0][2] << QR_ALIGN_SUBPREC);
+ y = cell->fwd[1][0] * u + cell->fwd[1][1] * v +
+ (cell->fwd[1][2] << QR_ALIGN_SUBPREC);
+ w = cell->fwd[2][0] * u + cell->fwd[2][1] * v +
+ (cell->fwd[2][2] << QR_ALIGN_SUBPREC);
+ qr_hom_cell_fproject(p, cell, x, y, w);
+ gimg[i * dim + j] =
+ _img[QR_CLAMPI(0, p[1] >> QR_FINDER_SUBPREC, _height - 1) *
+ _width +
+ QR_CLAMPI(0, p[0] >> QR_FINDER_SUBPREC, _width - 1)];
+ }
+ }
+ for (v = 0; v < 17 + (_version << 2); v++)
+ for (u = 0; u < 17 + (_version << 2); u++) {
+ if (qr_sampling_grid_is_in_fp(_grid, 17 + (_version << 2), u, v)) {
+ j = u + 4 << QR_ALIGN_SUBPREC;
+ i = v + 4 << QR_ALIGN_SUBPREC;
+ gimg[(i - 1) * dim + j - 1] = 0x7F;
+ gimg[(i - 1) * dim + j] = 0x7F;
+ gimg[(i - 1) * dim + j + 1] = 0x7F;
+ gimg[i * dim + j - 1] = 0x7F;
+ gimg[i * dim + j + 1] = 0x7F;
+ gimg[(i + 1) * dim + j - 1] = 0x7F;
+ gimg[(i + 1) * dim + j] = 0x7F;
+ gimg[(i + 1) * dim + j + 1] = 0x7F;
+ }
+ }
+ fout = fopen("grid.png", "wb");
+ image_write_png(gimg, dim, dim, fout);
+ fclose(fout);
+ free(gimg);
+}
+#endif
+
+/*Generate the data mask corresponding to the given mask pattern.*/
+static void qr_data_mask_fill(unsigned *_mask, int _dim, int _pattern)
+{
+ int stride;
+ int i;
+ int j;
+ stride = _dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS;
+ /*Note that we store bits column-wise, since that's how they're read out of
+ the grid.*/
+ switch (_pattern) {
+ /*10101010 i+j+1&1
+ 01010101
+ 10101010
+ 01010101*/
+ case 0: {
+ int m;
+ m = 0x55;
+ for (j = 0; j < _dim; j++) {
+ memset(_mask + j * stride, m, stride * sizeof(*_mask));
+ m ^= 0xFF;
+ }
+ } break;
+ /*11111111 i+1&1
+ 00000000
+ 11111111
+ 00000000*/
+ case 1:
+ memset(_mask, 0x55, _dim * stride * sizeof(*_mask));
+ break;
+ /*10010010 (j+1)%3&1
+ 10010010
+ 10010010
+ 10010010*/
+ case 2: {
+ unsigned m;
+ m = 0xFF;
+ for (j = 0; j < _dim; j++) {
+ memset(_mask + j * stride, m & 0xFF, stride * sizeof(*_mask));
+ m = m << 8 | m >> 16;
+ }
+ } break;
+ /*10010010 (i+j+1)%3&1
+ 00100100
+ 01001001
+ 10010010*/
+ case 3: {
+ unsigned mi;
+ unsigned mj;
+ mj = 0;
+ for (i = 0; i < (QR_INT_BITS + 2) / 3; i++)
+ mj |= 1 << 3 * i;
+ for (j = 0; j < _dim; j++) {
+ mi = mj;
+ for (i = 0; i < stride; i++) {
+ _mask[j * stride + i] = mi;
+ mi = mi >> QR_INT_BITS % 3 | mi << 3 - QR_INT_BITS % 3;
+ }
+ mj = mj >> 1 | mj << 2;
+ }
+ } break;
+ /*11100011 (i>>1)+(j/3)+1&1
+ 11100011
+ 00011100
+ 00011100*/
+ case 4: {
+ unsigned m;
+ m = 7;
+ for (j = 0; j < _dim; j++) {
+ memset(_mask + j * stride, (0xCC ^ -(m & 1)) & 0xFF,
+ stride * sizeof(*_mask));
+ m = m >> 1 | m << 5;
+ }
+ } break;
+ /*11111111 !((i*j)%6)
+ 10000010
+ 10010010
+ 10101010*/
+ case 5: {
+ for (j = 0; j < _dim; j++) {
+ unsigned m;
+ m = 0;
+ for (i = 0; i < 6; i++)
+ m |= !((i * j) % 6) << i;
+ for (i = 6; i < QR_INT_BITS; i <<= 1)
+ m |= m << i;
+ for (i = 0; i < stride; i++) {
+ _mask[j * stride + i] = m;
+ m = m >> QR_INT_BITS % 6 | m << 6 - QR_INT_BITS % 6;
+ }
+ }
+ } break;
+ /*11111111 (i*j)%3+i*j+1&1
+ 11100011
+ 11011011
+ 10101010*/
+ case 6: {
+ for (j = 0; j < _dim; j++) {
+ unsigned m;
+ m = 0;
+ for (i = 0; i < 6; i++)
+ m |= ((i * j) % 3 + i * j + 1 & 1) << i;
+ for (i = 6; i < QR_INT_BITS; i <<= 1)
+ m |= m << i;
+ for (i = 0; i < stride; i++) {
+ _mask[j * stride + i] = m;
+ m = m >> QR_INT_BITS % 6 | m << 6 - QR_INT_BITS % 6;
+ }
+ }
+ } break;
+ /*10101010 (i*j)%3+i+j+1&1
+ 00011100
+ 10001110
+ 01010101*/
+ default: {
+ for (j = 0; j < _dim; j++) {
+ unsigned m;
+ m = 0;
+ for (i = 0; i < 6; i++)
+ m |= ((i * j) % 3 + i + j + 1 & 1) << i;
+ for (i = 6; i < QR_INT_BITS; i <<= 1)
+ m |= m << i;
+ for (i = 0; i < stride; i++) {
+ _mask[j * stride + i] = m;
+ m = m >> QR_INT_BITS % 6 | m << 6 - QR_INT_BITS % 6;
+ }
+ }
+ } break;
+ }
+}
+
+static void qr_sampling_grid_sample(const qr_sampling_grid *_grid,
+ unsigned *_data_bits, int _dim,
+ int _fmt_info, const unsigned char *_img,
+ int _width, int _height)
+{
+ int stride;
+ int u0;
+ int u1;
+ int j;
+ /*We initialize the buffer with the data mask and XOR bits into it as we read
+ them out of the image instead of unmasking in a separate step.*/
+ qr_data_mask_fill(_data_bits, _dim, _fmt_info & 7);
+ stride = _dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS;
+ u0 = 0;
+ svg_path_start("sampling-grid", 1, 0, 0);
+ /*We read data cell-by-cell to avoid having to constantly change which
+ projection we're using as we read each bit.
+ This (and the position-dependent data mask) is the reason we buffer the
+ bits we read instead of converting them directly to codewords here.
+ Note that bits are stored column-wise, since that's how we'll scan them.*/
+ for (j = 0; j < _grid->ncells; j++) {
+ int i;
+ int v0;
+ int v1;
+ u1 = _grid->cell_limits[j];
+ v0 = 0;
+ for (i = 0; i < _grid->ncells; i++) {
+ qr_hom_cell *cell;
+ int x0;
+ int y0;
+ int w0;
+ int u;
+ int du;
+ int dv;
+ v1 = _grid->cell_limits[i];
+ cell = _grid->cells[i] + j;
+ du = u0 - cell->u0;
+ dv = v0 - cell->v0;
+ x0 = cell->fwd[0][0] * du + cell->fwd[0][1] * dv + cell->fwd[0][2];
+ y0 = cell->fwd[1][0] * du + cell->fwd[1][1] * dv + cell->fwd[1][2];
+ w0 = cell->fwd[2][0] * du + cell->fwd[2][1] * dv + cell->fwd[2][2];
+ for (u = u0; u < u1; u++) {
+ int x;
+ int y;
+ int w;
+ int v;
+ x = x0;
+ y = y0;
+ w = w0;
+ for (v = v0; v < v1; v++) {
+ /*Skip doing all the divisions and bounds checks if the bit is in the
+ function pattern.*/
+ if (!qr_sampling_grid_is_in_fp(_grid, _dim, u, v)) {
+ qr_point p;
+ qr_hom_cell_fproject(p, cell, x, y, w);
+ _data_bits[u * stride + (v >> QR_INT_LOGBITS)] ^=
+ qr_img_get_bit(_img, _width, _height, p[0], p[1])
+ << (v & QR_INT_BITS - 1);
+ svg_path_moveto(SVG_ABS, p[0], p[1]);
+ }
+ x += cell->fwd[0][1];
+ y += cell->fwd[1][1];
+ w += cell->fwd[2][1];
+ }
+ x0 += cell->fwd[0][0];
+ y0 += cell->fwd[1][0];
+ w0 += cell->fwd[2][0];
+ }
+ v0 = v1;
+ }
+ u0 = u1;
+ }
+ svg_path_end();
+}
+
+/*Arranges the sample bits read by qr_sampling_grid_sample() into bytes and
+ groups those bytes into Reed-Solomon blocks.
+ The individual block pointers are destroyed by this routine.*/
+static void qr_samples_unpack(unsigned char **_blocks, int _nblocks,
+ int _nshort_data, int _nshort_blocks,
+ const unsigned *_data_bits,
+ const unsigned *_fp_mask, int _dim)
+{
+ unsigned bits;
+ int biti;
+ int stride;
+ int blocki;
+ int blockj;
+ int i;
+ int j;
+ stride = _dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS;
+ /*If _all_ the blocks are short, don't skip anything (see below).*/
+ if (_nshort_blocks >= _nblocks)
+ _nshort_blocks = 0;
+ /*Scan columns in pairs from right to left.*/
+ bits = 0;
+ for (blocki = blockj = biti = 0, j = _dim - 1; j > 0; j -= 2) {
+ unsigned data1;
+ unsigned data2;
+ unsigned fp_mask1;
+ unsigned fp_mask2;
+ int nbits;
+ int l;
+ /*Scan up a pair of columns.*/
+ nbits = (_dim - 1 & QR_INT_BITS - 1) + 1;
+ l = j * stride;
+ for (i = stride; i-- > 0;) {
+ data1 = _data_bits[l + i];
+ fp_mask1 = _fp_mask[l + i];
+ data2 = _data_bits[l + i - stride];
+ fp_mask2 = _fp_mask[l + i - stride];
+ while (nbits-- > 0) {
+ /*Pull a bit from the right column.*/
+ if (!(fp_mask1 >> nbits & 1)) {
+ bits = bits << 1 | data1 >> nbits & 1;
+ biti++;
+ }
+ /*Pull a bit from the left column.*/
+ if (!(fp_mask2 >> nbits & 1)) {
+ bits = bits << 1 | data2 >> nbits & 1;
+ biti++;
+ }
+ /*If we finished a byte, drop it in a block.*/
+ if (biti >= 8) {
+ biti -= 8;
+ *_blocks[blocki++]++ = (unsigned char)(bits >> biti);
+ /*For whatever reason, the long blocks are at the _end_ of the list,
+ instead of the beginning.
+ Even worse, the extra bytes they get come at the end of the data
+ bytes, before the parity bytes.
+ Hence the logic here: when we've filled up the data portion of the
+ short blocks, skip directly to the long blocks for the next byte.
+ It's also the reason we increment _blocks[blocki] on each store,
+ instead of just indexing with blockj (after this iteration the
+ number of bytes in each block differs).*/
+ if (blocki >= _nblocks)
+ blocki = ++blockj == _nshort_data ? _nshort_blocks : 0;
+ }
+ }
+ nbits = QR_INT_BITS;
+ }
+ j -= 2;
+ /*Skip the column with the vertical timing pattern.*/
+ if (j == 6)
+ j--;
+ /*Scan down a pair of columns.*/
+ l = j * stride;
+ for (i = 0; i < stride; i++) {
+ data1 = _data_bits[l + i];
+ fp_mask1 = _fp_mask[l + i];
+ data2 = _data_bits[l + i - stride];
+ fp_mask2 = _fp_mask[l + i - stride];
+ nbits = QR_MINI(_dim - (i << QR_INT_LOGBITS), QR_INT_BITS);
+ while (nbits-- > 0) {
+ /*Pull a bit from the right column.*/
+ if (!(fp_mask1 & 1)) {
+ bits = bits << 1 | data1 & 1;
+ biti++;
+ }
+ data1 >>= 1;
+ fp_mask1 >>= 1;
+ /*Pull a bit from the left column.*/
+ if (!(fp_mask2 & 1)) {
+ bits = bits << 1 | data2 & 1;
+ biti++;
+ }
+ data2 >>= 1;
+ fp_mask2 >>= 1;
+ /*If we finished a byte, drop it in a block.*/
+ if (biti >= 8) {
+ biti -= 8;
+ *_blocks[blocki++]++ = (unsigned char)(bits >> biti);
+ /*See comments on the "up" loop for the reason behind this mess.*/
+ if (blocki >= _nblocks)
+ blocki = ++blockj == _nshort_data ? _nshort_blocks : 0;
+ }
+ }
+ }
+ }
+}
+
+/*Bit reading code blatantly stolen^W^Wadapted from libogg/libtheora (because
+ I've already debugged it and I know it works).
+ Portions (C) Xiph.Org Foundation 1994-2008, BSD-style license.*/
+struct qr_pack_buf {
+ const unsigned char *buf;
+ int endbyte;
+ int endbit;
+ int storage;
+};
+
+static void qr_pack_buf_init(qr_pack_buf *_b, const unsigned char *_data,
+ int _ndata)
+{
+ _b->buf = _data;
+ _b->storage = _ndata;
+ _b->endbyte = _b->endbit = 0;
+}
+
+/*Assumes 0<=_bits<=16.*/
+static int qr_pack_buf_read(qr_pack_buf *_b, int _bits)
+{
+ const unsigned char *p;
+ unsigned ret;
+ int m;
+ int d;
+ m = 16 - _bits;
+ _bits += _b->endbit;
+ d = _b->storage - _b->endbyte;
+ if (d <= 2) {
+ /*Not the main path.*/
+ if (d * 8 < _bits) {
+ _b->endbyte += _bits >> 3;
+ _b->endbit = _bits & 7;
+ return -1;
+ }
+ /*Special case to avoid reading p[0] below, which might be past the end of
+ the buffer; also skips some useless accounting.*/
+ else if (!_bits)
+ return 0;
+ }
+ p = _b->buf + _b->endbyte;
+ ret = p[0] << 8 + _b->endbit;
+ if (_bits > 8) {
+ ret |= p[1] << _b->endbit;
+ if (_bits > 16)
+ ret |= p[2] >> 8 - _b->endbit;
+ }
+ _b->endbyte += _bits >> 3;
+ _b->endbit = _bits & 7;
+ return (ret & 0xFFFF) >> m;
+}
+
+static int qr_pack_buf_avail(const qr_pack_buf *_b)
+{
+ return (_b->storage - _b->endbyte << 3) - _b->endbit;
+}
+
+/*The characters available in QR_MODE_ALNUM.*/
+static const unsigned char QR_ALNUM_TABLE[45] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
+ 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':'
+};
+
+static int qr_code_data_parse(qr_code_data *_qrdata, int _version,
+ const unsigned char *_data, int _ndata)
+{
+ qr_pack_buf qpb;
+ unsigned self_parity;
+ int centries;
+ int len_bits_idx;
+ /*Entries are stored directly in the struct during parsing.
+ Caller cleans up any allocated data on failure.*/
+ _qrdata->entries = NULL;
+ _qrdata->nentries = 0;
+ _qrdata->sa_size = 0;
+ self_parity = 0;
+ centries = 0;
+ /*The versions are divided into 3 ranges that each use a different number of
+ bits for length fields.*/
+ len_bits_idx = (_version > 9) + (_version > 26);
+ qr_pack_buf_init(&qpb, _data, _ndata);
+ /*While we have enough bits to read a mode...*/
+ while (qr_pack_buf_avail(&qpb) >= 4) {
+ qr_code_data_entry *entry;
+ int mode;
+ mode = qr_pack_buf_read(&qpb, 4);
+ /*Mode 0 is a terminator.*/
+ if (!mode)
+ break;
+ if (_qrdata->nentries >= centries) {
+ centries = centries << 1 | 1;
+ _qrdata->entries = (qr_code_data_entry *)realloc(
+ _qrdata->entries, centries * sizeof(*_qrdata->entries));
+ }
+ entry = _qrdata->entries + _qrdata->nentries++;
+ entry->mode = mode;
+ /*Set the buffer to NULL, because if parsing fails, we might try to free it
+ on clean-up.*/
+ entry->payload.data.buf = NULL;
+ switch (mode) {
+ /*The number of bits used to encode the character count for each version
+ range and each data mode.*/
+ static const unsigned char LEN_BITS[3][4] = { { 10, 9, 8, 8 },
+ { 12, 11, 16, 10 },
+ { 14, 13, 16, 12 } };
+ case QR_MODE_NUM: {
+ unsigned char *buf;
+ unsigned bits;
+ unsigned c;
+ int len;
+ int count;
+ int rem;
+ len = qr_pack_buf_read(&qpb, LEN_BITS[len_bits_idx][0]);
+ if (len < 0)
+ return -1;
+ /*Check to see if there are enough bits left now, so we don't have to
+ in the decode loop.*/
+ count = len / 3;
+ rem = len % 3;
+ if (qr_pack_buf_avail(&qpb) <
+ 10 * count + 7 * (rem >> 1 & 1) + 4 * (rem & 1))
+ return -1;
+ entry->payload.data.buf = buf =
+ (unsigned char *)malloc(len * sizeof(*buf));
+ entry->payload.data.len = len;
+ /*Read groups of 3 digits encoded in 10 bits.*/
+ while (count-- > 0) {
+ bits = qr_pack_buf_read(&qpb, 10);
+ if (bits >= 1000)
+ return -1;
+ c = '0' + bits / 100;
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ bits %= 100;
+ c = '0' + bits / 10;
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ c = '0' + bits % 10;
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ }
+ /*Read the last two digits encoded in 7 bits.*/
+ if (rem > 1) {
+ bits = qr_pack_buf_read(&qpb, 7);
+ if (bits >= 100)
+ return -1;
+ c = '0' + bits / 10;
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ c = '0' + bits % 10;
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ }
+ /*Or the last one digit encoded in 4 bits.*/
+ else if (rem) {
+ bits = qr_pack_buf_read(&qpb, 4);
+ if (bits >= 10)
+ return -1;
+ c = '0' + bits;
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ }
+ } break;
+ case QR_MODE_ALNUM: {
+ unsigned char *buf;
+ unsigned bits;
+ unsigned c;
+ int len;
+ int count;
+ int rem;
+ len = qr_pack_buf_read(&qpb, LEN_BITS[len_bits_idx][1]);
+ if (len < 0)
+ return -1;
+ /*Check to see if there are enough bits left now, so we don't have to
+ in the decode loop.*/
+ count = len >> 1;
+ rem = len & 1;
+ if (qr_pack_buf_avail(&qpb) < 11 * count + 6 * rem)
+ return -1;
+ entry->payload.data.buf = buf =
+ (unsigned char *)malloc(len * sizeof(*buf));
+ entry->payload.data.len = len;
+ /*Read groups of two characters encoded in 11 bits.*/
+ while (count-- > 0) {
+ bits = qr_pack_buf_read(&qpb, 11);
+ if (bits >= 2025)
+ return -1;
+ c = QR_ALNUM_TABLE[bits / 45];
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ c = QR_ALNUM_TABLE[bits % 45];
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ len -= 2;
+ }
+ /*Read the last character encoded in 6 bits.*/
+ if (rem) {
+ bits = qr_pack_buf_read(&qpb, 6);
+ if (bits >= 45)
+ return -1;
+ c = QR_ALNUM_TABLE[bits];
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ }
+ } break;
+ /*Structured-append header.*/
+ case QR_MODE_STRUCT: {
+ int bits;
+ bits = qr_pack_buf_read(&qpb, 16);
+ if (bits < 0)
+ return -1;
+ /*We save a copy of the data in _qrdata for easy reference when
+ grouping structured-append codes.
+ If for some reason the code has multiple S-A headers, first one wins,
+ since it is supposed to come before everything else (TODO: should we
+ return an error instead?).*/
+ if (_qrdata->sa_size == 0) {
+ _qrdata->sa_index = entry->payload.sa.sa_index =
+ (unsigned char)(bits >> 12 & 0xF);
+ _qrdata->sa_size = entry->payload.sa.sa_size =
+ (unsigned char)((bits >> 8 & 0xF) + 1);
+ _qrdata->sa_parity = entry->payload.sa.sa_parity =
+ (unsigned char)(bits & 0xFF);
+ }
+ } break;
+ case QR_MODE_BYTE: {
+ unsigned char *buf;
+ unsigned c;
+ int len;
+ len = qr_pack_buf_read(&qpb, LEN_BITS[len_bits_idx][2]);
+ if (len < 0)
+ return -1;
+ /*Check to see if there are enough bits left now, so we don't have to
+ in the decode loop.*/
+ if (qr_pack_buf_avail(&qpb) < len << 3)
+ return -1;
+ entry->payload.data.buf = buf =
+ (unsigned char *)malloc(len * sizeof(*buf));
+ entry->payload.data.len = len;
+ while (len-- > 0) {
+ c = qr_pack_buf_read(&qpb, 8);
+ self_parity ^= c;
+ *buf++ = (unsigned char)c;
+ }
+ } break;
+ /*FNC1 first position marker.*/
+ case QR_MODE_FNC1_1ST:
+ break;
+ /*Extended Channel Interpretation data.*/
+ case QR_MODE_ECI: {
+ unsigned val;
+ int bits;
+ /*ECI uses a variable-width encoding similar to UTF-8*/
+ bits = qr_pack_buf_read(&qpb, 8);
+ if (bits < 0)
+ return -1;
+ /*One byte:*/
+ if (!(bits & 0x80))
+ val = bits;
+ /*Two bytes:*/
+ else if (!(bits & 0x40)) {
+ val = bits & 0x3F << 8;
+ bits = qr_pack_buf_read(&qpb, 8);
+ if (bits < 0)
+ return -1;
+ val |= bits;
+ }
+ /*Three bytes:*/
+ else if (!(bits & 0x20)) {
+ val = bits & 0x1F << 16;
+ bits = qr_pack_buf_read(&qpb, 16);
+ if (bits < 0)
+ return -1;
+ val |= bits;
+ /*Valid ECI values are 0...999999.*/
+ if (val >= 1000000)
+ return -1;
+ }
+ /*Invalid lead byte.*/
+ else
+ return -1;
+ entry->payload.eci = val;
+ } break;
+ case QR_MODE_KANJI: {
+ unsigned char *buf;
+ unsigned bits;
+ int len;
+ len = qr_pack_buf_read(&qpb, LEN_BITS[len_bits_idx][3]);
+ if (len < 0)
+ return -1;
+ /*Check to see if there are enough bits left now, so we don't have to
+ in the decode loop.*/
+ if (qr_pack_buf_avail(&qpb) < 13 * len)
+ return -1;
+ entry->payload.data.buf = buf =
+ (unsigned char *)malloc(2 * len * sizeof(*buf));
+ entry->payload.data.len = 2 * len;
+ /*Decode 2-byte SJIS characters encoded in 13 bits.*/
+ while (len-- > 0) {
+ bits = qr_pack_buf_read(&qpb, 13);
+ bits = (bits / 0xC0 << 8 | bits % 0xC0) + 0x8140;
+ if (bits >= 0xA000)
+ bits += 0x4000;
+ /*TODO: Are values 0xXX7F, 0xXXFD...0xXXFF always invalid?
+ Should we reject them here?*/
+ self_parity ^= bits;
+ *buf++ = (unsigned char)(bits >> 8);
+ *buf++ = (unsigned char)(bits & 0xFF);
+ }
+ } break;
+ /*FNC1 second position marker.*/
+ case QR_MODE_FNC1_2ND: {
+ int bits;
+ /*FNC1 in the 2nd position encodes an Application Indicator in one
+ byte, which is either a letter (A...Z or a...z) or a 2-digit number.
+ The letters are encoded with their ASCII value plus 100, the numbers
+ are encoded directly with their numeric value.
+ Values 100...164, 191...196, and 223...255 are invalid, so we reject
+ them here.*/
+ bits = qr_pack_buf_read(&qpb, 8);
+ if (!(bits >= 0 && bits < 100 || bits >= 165 && bits < 191 ||
+ bits >= 197 && bits < 223)) {
+ return -1;
+ }
+ entry->payload.ai = bits;
+ } break;
+ /*Unknown mode number:*/
+ default: {
+ /*Unfortunately, because we have to understand the format of a mode to
+ know how many bits it occupies, we can't skip unknown modes.
+ Therefore we have to fail.*/
+ return -1;
+ } break;
+ }
+ }
+ /*Store the parity of the data from this code, for S-A.
+ The final parity is the 8-bit XOR of all the decoded bytes of literal data.
+ We don't combine the 2-byte kanji codes into one byte in the loops above,
+ because we can just do it here instead.*/
+ _qrdata->self_parity = ((self_parity >> 8) ^ self_parity) & 0xFF;
+ /*Success.*/
+ _qrdata->entries = (qr_code_data_entry *)realloc(
+ _qrdata->entries, _qrdata->nentries * sizeof(*_qrdata->entries));
+ return 0;
+}
+
+static void qr_code_data_clear(qr_code_data *_qrdata)
+{
+ int i;
+ for (i = 0; i < _qrdata->nentries; i++) {
+ if (QR_MODE_HAS_DATA(_qrdata->entries[i].mode)) {
+ free(_qrdata->entries[i].payload.data.buf);
+ }
+ }
+ free(_qrdata->entries);
+}
+
+void qr_code_data_list_init(qr_code_data_list *_qrlist)
+{
+ _qrlist->qrdata = NULL;
+ _qrlist->nqrdata = _qrlist->cqrdata = 0;
+}
+
+void qr_code_data_list_clear(qr_code_data_list *_qrlist)
+{
+ int i;
+ for (i = 0; i < _qrlist->nqrdata; i++)
+ qr_code_data_clear(_qrlist->qrdata + i);
+ free(_qrlist->qrdata);
+ qr_code_data_list_init(_qrlist);
+}
+
+static void qr_code_data_list_add(qr_code_data_list *_qrlist,
+ qr_code_data *_qrdata)
+{
+ if (_qrlist->nqrdata >= _qrlist->cqrdata) {
+ _qrlist->cqrdata = _qrlist->cqrdata << 1 | 1;
+ _qrlist->qrdata = (qr_code_data *)realloc(
+ _qrlist->qrdata, _qrlist->cqrdata * sizeof(*_qrlist->qrdata));
+ }
+ memcpy(_qrlist->qrdata + _qrlist->nqrdata++, _qrdata, sizeof(*_qrdata));
+}
+
+#if 0
+static const unsigned short QR_NCODEWORDS[40]={
+ 26, 44, 70, 100, 134, 172, 196, 242, 292, 346,
+ 404, 466, 532, 581, 655, 733, 815, 901, 991,1085,
+ 1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,
+ 2323,2465,2611,2761,2876,3034,3196,3362,3532,3706
+};
+#endif
+
+/*The total number of codewords in a QR code.*/
+static int qr_code_ncodewords(unsigned _version)
+{
+ unsigned nalign;
+ /*This is 24-27 instructions on ARM in thumb mode, or a 26-32 byte savings
+ over just using a table (not counting the instructions that would be
+ needed to do the table lookup).*/
+ if (_version == 1)
+ return 26;
+ nalign = (_version / 7) + 2;
+ return (_version << 4) * (_version + 8) - (5 * nalign) * (5 * nalign - 2) +
+ 36 * (_version < 7) + 83 >>
+ 3;
+}
+
+#if 0
+/*The number of parity bytes per Reed-Solomon block for each version and error
+ correction level.*/
+static const unsigned char QR_RS_NPAR[40][4]={
+ { 7,10,13,17},{10,16,22,28},{15,26,18,22},{20,18,26,16},
+ {26,24,18,22},{18,16,24,28},{20,18,18,26},{24,22,22,26},
+ {30,22,20,24},{18,26,24,28},{20,30,28,24},{24,22,26,28},
+ {26,22,24,22},{30,24,20,24},{22,24,30,24},{24,28,24,30},
+ {28,28,28,28},{30,26,28,28},{28,26,26,26},{28,26,30,28},
+ {28,26,28,30},{28,28,30,24},{30,28,30,30},{30,28,30,30},
+ {26,28,30,30},{28,28,28,30},{30,28,30,30},{30,28,30,30},
+ {30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30},
+ {30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30},
+ {30,28,30,30},{30,28,30,30},{30,28,30,30},{30,28,30,30}
+};
+#endif
+
+/*Bulk data for the number of parity bytes per Reed-Solomon block.*/
+static const unsigned char QR_RS_NPAR_VALS[71] = {
+ /*[ 0]*/ 7, 10, 13, 17,
+ /*[ 4]*/ 10, 16, 22, 28, 26, 26, 26, 22, 24, 22, 22, 26,
+ 24, 18, 22,
+ /*[19]*/ 15, 26, 18, 22, 24, 30, 24, 20, 24,
+ /*[28]*/ 18, 16, 24, 28, 28, 28, 28, 30, 24,
+ /*[37]*/ 20, 18, 18, 26, 24, 28, 24, 30, 26, 28, 28, 26,
+ 28, 30, 30, 22, 20, 24,
+ /*[55]*/ 20, 18, 26, 16,
+ /*[59]*/ 20, 30, 28, 24, 22, 26, 28, 26, 30, 28, 30, 30
+};
+
+/*An offset into QR_RS_NPAR_DATA for each version that gives the number of
+ parity bytes per Reed-Solomon block for each error correction level.*/
+static const unsigned char QR_RS_NPAR_OFFS[40] = {
+ 0, 4, 19, 55, 15, 28, 37, 12, 51, 39, 59, 62, 10, 24,
+ 22, 41, 31, 44, 7, 65, 47, 33, 67, 67, 48, 32, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67
+};
+
+/*The number of Reed-Solomon blocks for each version and error correction
+ level.*/
+static const unsigned char QR_RS_NBLOCKS[40][4] = {
+ { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 2, 2 },
+ { 1, 2, 2, 4 }, { 1, 2, 4, 4 }, { 2, 4, 4, 4 },
+ { 2, 4, 6, 5 }, { 2, 4, 6, 6 }, { 2, 5, 8, 8 },
+ { 4, 5, 8, 8 }, { 4, 5, 8, 11 }, { 4, 8, 10, 11 },
+ { 4, 9, 12, 16 }, { 4, 9, 16, 16 }, { 6, 10, 12, 18 },
+ { 6, 10, 17, 16 }, { 6, 11, 16, 19 }, { 6, 13, 18, 21 },
+ { 7, 14, 21, 25 }, { 8, 16, 20, 25 }, { 8, 17, 23, 25 },
+ { 9, 17, 23, 34 }, { 9, 18, 25, 30 }, { 10, 20, 27, 32 },
+ { 12, 21, 29, 35 }, { 12, 23, 34, 37 }, { 12, 25, 34, 40 },
+ { 13, 26, 35, 42 }, { 14, 28, 38, 45 }, { 15, 29, 40, 48 },
+ { 16, 31, 43, 51 }, { 17, 33, 45, 54 }, { 18, 35, 48, 57 },
+ { 19, 37, 51, 60 }, { 19, 38, 53, 63 }, { 20, 40, 56, 66 },
+ { 21, 43, 59, 70 }, { 22, 45, 62, 74 }, { 24, 47, 65, 77 },
+ { 25, 49, 68, 81 }
+};
+
+/*Attempts to fully decode a QR code.
+ _qrdata: Returns the parsed code data.
+ _gf: Used for Reed-Solomon error correction.
+ _ul_pos: The location of the UL finder pattern.
+ _ur_pos: The location of the UR finder pattern.
+ _dl_pos: The location of the DL finder pattern.
+ _version: The (decoded) version number.
+ _fmt_info: The decoded format info.
+ _img: The binary input image.
+ _width: The width of the input image.
+ _height: The height of the input image.
+ Return: 0 on success, or a negative value on error.*/
+static int qr_code_decode(qr_code_data *_qrdata, const rs_gf256 *_gf,
+ const qr_point _ul_pos, const qr_point _ur_pos,
+ const qr_point _dl_pos, int _version, int _fmt_info,
+ const unsigned char *_img, int _width, int _height)
+{
+ qr_sampling_grid grid;
+ unsigned *data_bits;
+ unsigned char **blocks;
+ unsigned char *block_data;
+ int nblocks;
+ int nshort_blocks;
+ int ncodewords;
+ int block_sz;
+ int ecc_level;
+ int ndata;
+ int npar;
+ int dim;
+ int ret;
+ int i;
+ /*Read the bits out of the image.*/
+ qr_sampling_grid_init(&grid, _version, _ul_pos, _ur_pos, _dl_pos,
+ _qrdata->bbox, _img, _width, _height);
+#if defined(QR_DEBUG)
+ qr_sampling_grid_dump(&grid, _version, _img, _width, _height);
+#endif
+ dim = 17 + (_version << 2);
+ data_bits = (unsigned *)malloc(
+ dim * (dim + QR_INT_BITS - 1 >> QR_INT_LOGBITS) * sizeof(*data_bits));
+ qr_sampling_grid_sample(&grid, data_bits, dim, _fmt_info, _img, _width,
+ _height);
+ /*Group those bits into Reed-Solomon codewords.*/
+ ecc_level = (_fmt_info >> 3) ^ 1;
+ nblocks = QR_RS_NBLOCKS[_version - 1][ecc_level];
+ npar = *(QR_RS_NPAR_VALS + QR_RS_NPAR_OFFS[_version - 1] + ecc_level);
+ ncodewords = qr_code_ncodewords(_version);
+ block_sz = ncodewords / nblocks;
+ nshort_blocks = nblocks - (ncodewords % nblocks);
+ blocks = (unsigned char **)malloc(nblocks * sizeof(*blocks));
+ block_data = (unsigned char *)malloc(ncodewords * sizeof(*block_data));
+ blocks[0] = block_data;
+ for (i = 1; i < nblocks; i++)
+ blocks[i] = blocks[i - 1] + block_sz + (i > nshort_blocks);
+ qr_samples_unpack(blocks, nblocks, block_sz - npar, nshort_blocks,
+ data_bits, grid.fpmask, dim);
+ qr_sampling_grid_clear(&grid);
+ free(blocks);
+ free(data_bits);
+ /*Perform the error correction.*/
+ ndata = 0;
+ ncodewords = 0;
+ ret = 0;
+ for (i = 0; i < nblocks; i++) {
+ int block_szi;
+ int ndatai;
+ block_szi = block_sz + (i >= nshort_blocks);
+ ret = rs_correct(_gf, QR_M0, block_data + ncodewords, block_szi, npar,
+ NULL, 0);
+ zprintf(1, "Number of errors corrected: %i%s\n", ret,
+ ret < 0 ? " (data irrecoverable)" : "");
+ /*For version 1 symbols and version 2-L and 3-L symbols, we aren't allowed
+ to use all the parity bytes for correction.
+ They are instead used to improve detection.
+ Version 1-L reserves 3 parity bytes for detection.
+ Versions 1-M and 2-L reserve 2 parity bytes for detection.
+ Versions 1-Q, 1-H, and 3-L reserve 1 parity byte for detection.
+ We can ignore the version 3-L restriction because it has an odd number of
+ parity bytes, and we don't support erasure detection.*/
+ if (ret < 0 || _version == 1 && ret > ecc_level + 1 << 1 ||
+ _version == 2 && ecc_level == 0 && ret > 4) {
+ ret = -1;
+ break;
+ }
+ ndatai = block_szi - npar;
+ memmove(block_data + ndata, block_data + ncodewords,
+ ndatai * sizeof(*block_data));
+ ncodewords += block_szi;
+ ndata += ndatai;
+ }
+ /*Parse the corrected bitstream.*/
+ if (ret >= 0) {
+ ret = qr_code_data_parse(_qrdata, _version, block_data, ndata);
+ /*We could return any partially decoded data, but then we'd have to have
+ API support for that; a mode ignoring ECC errors might also be useful.*/
+ if (ret < 0)
+ qr_code_data_clear(_qrdata);
+ _qrdata->version = _version;
+ _qrdata->ecc_level = ecc_level;
+ }
+ free(block_data);
+ return ret;
+}
+
+/*Searches for an arrangement of these three finder centers that yields a valid
+ configuration.
+ _c: On input, the three finder centers to consider in any order.
+ Return: The detected version number, or a negative value on error.*/
+static int qr_reader_try_configuration(qr_reader *_reader,
+ qr_code_data *_qrdata,
+ const unsigned char *_img, int _width,
+ int _height, qr_finder_center *_c[3])
+{
+ int ci[7];
+ unsigned maxd;
+ int ccw;
+ int i0;
+ int i;
+ /*Sort the points in counter-clockwise order.*/
+ ccw = qr_point_ccw(_c[0]->pos, _c[1]->pos, _c[2]->pos);
+ /*Colinear points can't be the corners of a quadrilateral.*/
+ if (!ccw)
+ return -1;
+ /*Include a few extra copies of the cyclical list to avoid mods.*/
+ ci[6] = ci[3] = ci[0] = 0;
+ ci[4] = ci[1] = 1 + (ccw < 0);
+ ci[5] = ci[2] = 2 - (ccw < 0);
+ /*Assume the points farthest from each other are the opposite corners, and
+ find the top-left point.*/
+ maxd = qr_point_distance2(_c[1]->pos, _c[2]->pos);
+ i0 = 0;
+ for (i = 1; i < 3; i++) {
+ unsigned d;
+ d = qr_point_distance2(_c[ci[i + 1]]->pos, _c[ci[i + 2]]->pos);
+ if (d > maxd) {
+ i0 = i;
+ maxd = d;
+ }
+ }
+ /*However, try all three possible orderings, just to be sure (a severely
+ skewed projection could move opposite corners closer than adjacent).*/
+ for (i = i0; i < i0 + 3; i++) {
+ qr_aff aff;
+ qr_hom hom;
+ qr_finder ul;
+ qr_finder ur;
+ qr_finder dl;
+ qr_point bbox[4];
+ int res;
+ int ur_version;
+ int dl_version;
+ int fmt_info;
+ ul.c = _c[ci[i]];
+ ur.c = _c[ci[i + 1]];
+ dl.c = _c[ci[i + 2]];
+ /*Estimate the module size and version number from the two opposite corners.
+ The module size is not constant in the image, so we compute an affine
+ projection from the three points we have to a square domain, and
+ estimate it there.
+ Although it should be the same along both axes, we keep separate
+ estimates to account for any remaining projective distortion.*/
+ res = QR_INT_BITS - 2 - QR_FINDER_SUBPREC -
+ qr_ilog(QR_MAXI(_width, _height) - 1);
+ qr_aff_init(&aff, ul.c->pos, ur.c->pos, dl.c->pos, res);
+ qr_aff_unproject(ur.o, &aff, ur.c->pos[0], ur.c->pos[1]);
+ qr_finder_edge_pts_aff_classify(&ur, &aff);
+ if (qr_finder_estimate_module_size_and_version(&ur, 1 << res,
+ 1 << res) < 0)
+ continue;
+ qr_aff_unproject(dl.o, &aff, dl.c->pos[0], dl.c->pos[1]);
+ qr_finder_edge_pts_aff_classify(&dl, &aff);
+ if (qr_finder_estimate_module_size_and_version(&dl, 1 << res,
+ 1 << res) < 0)
+ continue;
+ /*If the estimated versions are significantly different, reject the
+ configuration.*/
+ if (abs(ur.eversion[1] - dl.eversion[0]) > QR_LARGE_VERSION_SLACK)
+ continue;
+ qr_aff_unproject(ul.o, &aff, ul.c->pos[0], ul.c->pos[1]);
+ qr_finder_edge_pts_aff_classify(&ul, &aff);
+ if (qr_finder_estimate_module_size_and_version(&ul, 1 << res,
+ 1 << res) < 0 ||
+ abs(ul.eversion[1] - ur.eversion[1]) > QR_LARGE_VERSION_SLACK ||
+ abs(ul.eversion[0] - dl.eversion[0]) > QR_LARGE_VERSION_SLACK) {
+ continue;
+ }
+#if defined(QR_DEBUG)
+ qr_finder_dump_aff_undistorted(&ul, &ur, &dl, &aff, _img, _width,
+ _height);
+#endif
+ /*If we made it this far, upgrade the affine homography to a full
+ homography.*/
+ if (qr_hom_fit(&hom, &ul, &ur, &dl, bbox, &aff, &_reader->isaac, _img,
+ _width, _height) < 0) {
+ continue;
+ }
+ memcpy(_qrdata->bbox, bbox, sizeof(bbox));
+ qr_hom_unproject(ul.o, &hom, ul.c->pos[0], ul.c->pos[1]);
+ qr_hom_unproject(ur.o, &hom, ur.c->pos[0], ur.c->pos[1]);
+ qr_hom_unproject(dl.o, &hom, dl.c->pos[0], dl.c->pos[1]);
+ qr_finder_edge_pts_hom_classify(&ur, &hom);
+ if (qr_finder_estimate_module_size_and_version(&ur, ur.o[0] - ul.o[0],
+ ur.o[0] - ul.o[0]) < 0) {
+ continue;
+ }
+ qr_finder_edge_pts_hom_classify(&dl, &hom);
+ if (qr_finder_estimate_module_size_and_version(&dl, dl.o[1] - ul.o[1],
+ dl.o[1] - ul.o[1]) < 0) {
+ continue;
+ }
+#if defined(QR_DEBUG)
+ qr_finder_dump_hom_undistorted(&ul, &ur, &dl, &hom, _img, _width,
+ _height);
+#endif
+ /*If we have a small version (less than 7), there's no encoded version
+ information.
+ If the estimated version on the two corners matches and is sufficiently
+ small, we assume this is the case.*/
+ if (ur.eversion[1] == dl.eversion[0] && ur.eversion[1] < 7) {
+ /*We used to do a whole bunch of extra geometric checks for small
+ versions, because with just an affine correction, it was fairly easy
+ to estimate two consistent module sizes given a random configuration.
+ However, now that we're estimating a full homography, these appear to
+ be unnecessary.*/
+#if 0
+ static const signed char LINE_TESTS[12][6]={
+ /*DL left, UL > 0, UR > 0*/
+ {2,0,0, 1,1, 1},
+ /*DL right, UL > 0, UR < 0*/
+ {2,1,0, 1,1,-1},
+ /*UR top, UL > 0, DL > 0*/
+ {1,2,0, 1,2, 1},
+ /*UR bottom, UL > 0, DL < 0*/
+ {1,3,0, 1,2,-1},
+ /*UR left, DL < 0, UL < 0*/
+ {1,0,2,-1,0,-1},
+ /*UR right, DL > 0, UL > 0*/
+ {1,1,2, 1,0, 1},
+ /*DL top, UR < 0, UL < 0*/
+ {2,2,1,-1,0,-1},
+ /*DL bottom, UR > 0, UL > 0*/
+ {2,3,1, 1,0, 1},
+ /*UL left, DL > 0, UR > 0*/
+ {0,0,2, 1,1, 1},
+ /*UL right, DL > 0, UR < 0*/
+ {0,1,2, 1,1,-1},
+ /*UL top, UR > 0, DL > 0*/
+ {0,2,1, 1,2, 1},
+ /*UL bottom, UR > 0, DL < 0*/
+ {0,3,1, 1,2,-1}
+ };
+ qr_finder *f[3];
+ int j;
+ /*Start by decoding the format information.
+ This is cheap, but unlikely to reject invalid configurations.
+ 56.25% of all bitstrings are valid, and we mix and match several pieces
+ until we find a valid combination, so our real chances of finding a
+ valid codeword in random bits are even higher.*/
+ fmt_info=qr_finder_fmt_info_decode(&ul,&ur,&dl,&aff,_img,_width,_height);
+ if(fmt_info<0)continue;
+ /*Now we fit lines to the edges of each finder pattern and check to make
+ sure the centers of the other finder patterns lie on the proper side.*/
+ f[0]=&ul;
+ f[1]=&ur;
+ f[2]=&dl;
+ for(j=0;j<12;j++){
+ const signed char *t;
+ qr_line l0;
+ int *p;
+ t=LINE_TESTS[j];
+ qr_finder_ransac(f[t[0]],&aff,&_reader->isaac,t[1]);
+ /*We may not have enough points to fit a line accurately here.
+ If not, we just skip the test.*/
+ if(qr_line_fit_finder_edge(l0,f[t[0]],t[1],res)<0)continue;
+ p=f[t[2]]->c->pos;
+ if(qr_line_eval(l0,p[0],p[1])*t[3]<0)break;
+ p=f[t[4]]->c->pos;
+ if(qr_line_eval(l0,p[0],p[1])*t[5]<0)break;
+ }
+ if(j<12)continue;
+ /*All tests passed.*/
+#endif
+ ur_version = ur.eversion[1];
+ } else {
+ /*If the estimated versions are significantly different, reject the
+ configuration.*/
+ if (abs(ur.eversion[1] - dl.eversion[0]) > QR_LARGE_VERSION_SLACK)
+ continue;
+ /*Otherwise we try to read the actual version data from the image.
+ If the real version is not sufficiently close to our estimated version,
+ then we assume there was an unrecoverable decoding error (so many bit
+ errors we were within 3 errors of another valid code), and throw that
+ value away.
+ If no decoded version could be sufficiently close, we don't even try.*/
+ if (ur.eversion[1] >= 7 - QR_LARGE_VERSION_SLACK) {
+ ur_version = qr_finder_version_decode(&ur, &hom, _img, _width,
+ _height, 0);
+ if (abs(ur_version - ur.eversion[1]) > QR_LARGE_VERSION_SLACK)
+ ur_version = -1;
+ } else
+ ur_version = -1;
+ if (dl.eversion[0] >= 7 - QR_LARGE_VERSION_SLACK) {
+ dl_version = qr_finder_version_decode(&dl, &hom, _img, _width,
+ _height, 1);
+ if (abs(dl_version - dl.eversion[0]) > QR_LARGE_VERSION_SLACK)
+ dl_version = -1;
+ } else
+ dl_version = -1;
+ /*If we got at least one valid version, or we got two and they match,
+ then we found a valid configuration.*/
+ if (ur_version >= 0) {
+ if (dl_version >= 0 && dl_version != ur_version)
+ continue;
+ } else if (dl_version < 0)
+ continue;
+ else
+ ur_version = dl_version;
+ }
+ qr_finder_edge_pts_hom_classify(&ul, &hom);
+ if (qr_finder_estimate_module_size_and_version(&ul, ur.o[0] - dl.o[0],
+ dl.o[1] - ul.o[1]) < 0 ||
+ abs(ul.eversion[1] - ur.eversion[1]) > QR_SMALL_VERSION_SLACK ||
+ abs(ul.eversion[0] - dl.eversion[0]) > QR_SMALL_VERSION_SLACK) {
+ continue;
+ }
+ fmt_info = qr_finder_fmt_info_decode(&ul, &ur, &dl, &hom, _img, _width,
+ _height);
+ if (fmt_info < 0 ||
+ qr_code_decode(_qrdata, &_reader->gf, ul.c->pos, ur.c->pos,
+ dl.c->pos, ur_version, fmt_info, _img, _width,
+ _height) < 0) {
+ /*The code may be flipped.
+ Try again, swapping the UR and DL centers.
+ We should get a valid version either way, so it's relatively cheap to
+ check this, as we've already filtered out a lot of invalid
+ configurations.*/
+ QR_SWAP2I(hom.inv[0][0], hom.inv[1][0]);
+ QR_SWAP2I(hom.inv[0][1], hom.inv[1][1]);
+ QR_SWAP2I(hom.fwd[0][0], hom.fwd[0][1]);
+ QR_SWAP2I(hom.fwd[1][0], hom.fwd[1][1]);
+ QR_SWAP2I(hom.fwd[2][0], hom.fwd[2][1]);
+ QR_SWAP2I(ul.o[0], ul.o[1]);
+ QR_SWAP2I(ul.size[0], ul.size[1]);
+ QR_SWAP2I(ur.o[0], ur.o[1]);
+ QR_SWAP2I(ur.size[0], ur.size[1]);
+ QR_SWAP2I(dl.o[0], dl.o[1]);
+ QR_SWAP2I(dl.size[0], dl.size[1]);
+#if defined(QR_DEBUG)
+ qr_finder_dump_hom_undistorted(&ul, &dl, &ur, &hom, _img, _width,
+ _height);
+#endif
+ fmt_info = qr_finder_fmt_info_decode(&ul, &dl, &ur, &hom, _img,
+ _width, _height);
+ if (fmt_info < 0)
+ continue;
+ QR_SWAP2I(bbox[1][0], bbox[2][0]);
+ QR_SWAP2I(bbox[1][1], bbox[2][1]);
+ memcpy(_qrdata->bbox, bbox, sizeof(bbox));
+ if (qr_code_decode(_qrdata, &_reader->gf, ul.c->pos, dl.c->pos,
+ ur.c->pos, ur_version, fmt_info, _img, _width,
+ _height) < 0) {
+ continue;
+ }
+ }
+ return ur_version;
+ }
+ return -1;
+}
+
+void qr_reader_match_centers(qr_reader *_reader, qr_code_data_list *_qrlist,
+ qr_finder_center *_centers, int _ncenters,
+ const unsigned char *_img, int _width, int _height)
+{
+ /*The number of centers should be small, so an O(n^3) exhaustive search of
+ which ones go together should be reasonable.*/
+ unsigned char *mark;
+ int nfailures_max;
+ int nfailures;
+ int i;
+ int j;
+ int k;
+ mark = (unsigned char *)calloc(_ncenters, sizeof(*mark));
+ nfailures_max = QR_MAXI(8192, _width * _height >> 9);
+ nfailures = 0;
+ for (i = 0; i < _ncenters; i++) {
+ /*TODO: We might be able to accelerate this step significantly by
+ considering the remaining finder centers in a more intelligent order,
+ based on the first finder center we just chose.*/
+ for (j = i + 1; i <_ncenters && !mark[i] && j < _ncenters; j++) {
+ for (k = j + 1; j<_ncenters && !mark[j] && k < _ncenters; k++)
+ if (!mark[k]) {
+ qr_finder_center *c[3];
+ qr_code_data qrdata;
+ int version;
+ c[0] = _centers + i;
+ c[1] = _centers + j;
+ c[2] = _centers + k;
+ version = qr_reader_try_configuration(_reader, &qrdata,
+ _img, _width, _height,
+ c);
+ if (version >= 0) {
+ int ninside;
+ int l;
+ /*Add the data to the list.*/
+ qr_code_data_list_add(_qrlist, &qrdata);
+ /*Convert the bounding box we're returning to the user to normal
+ image coordinates.*/
+ for (l = 0; l < 4; l++) {
+ _qrlist->qrdata[_qrlist->nqrdata - 1].bbox[l][0] >>=
+ QR_FINDER_SUBPREC;
+ _qrlist->qrdata[_qrlist->nqrdata - 1].bbox[l][1] >>=
+ QR_FINDER_SUBPREC;
+ }
+ /*Mark these centers as used.*/
+ mark[i] = mark[j] = mark[k] = 1;
+ /*Find any other finder centers located inside this code.*/
+ for (l = ninside = 0; l < _ncenters; l++)
+ if (!mark[l]) {
+ if (qr_point_ccw(qrdata.bbox[0], qrdata.bbox[1],
+ _centers[l].pos) >= 0 &&
+ qr_point_ccw(qrdata.bbox[1], qrdata.bbox[3],
+ _centers[l].pos) >= 0 &&
+ qr_point_ccw(qrdata.bbox[3], qrdata.bbox[2],
+ _centers[l].pos) >= 0 &&
+ qr_point_ccw(qrdata.bbox[2], qrdata.bbox[0],
+ _centers[l].pos) >= 0) {
+ mark[l] = 2;
+ ninside++;
+ }
+ }
+ if (ninside >= 3) {
+ /*We might have a "Double QR": a code inside a code.
+ Copy the relevant centers to a new array and do a search confined
+ to that subset.*/
+ qr_finder_center *inside;
+ inside = (qr_finder_center *)malloc(
+ ninside * sizeof(*inside));
+ for (l = ninside = 0; l < _ncenters; l++) {
+ if (mark[l] == 2)
+ *&inside[ninside++] = *&_centers[l];
+ }
+ qr_reader_match_centers(_reader, _qrlist, inside,
+ ninside, _img, _width,
+ _height);
+ free(inside);
+ }
+ /*Mark _all_ such centers used: codes cannot partially overlap.*/
+ for (l = 0; l < _ncenters; l++)
+ if (mark[l] == 2)
+ mark[l] = 1;
+ nfailures = 0;
+ } else if (++nfailures > nfailures_max) {
+ /*Give up.
+ We're unlikely to find a valid code in all this clutter, and we
+ could spent quite a lot of time trying.*/
+ i = j = k = _ncenters;
+ }
+ }
+ }
+ }
+ free(mark);
+}
+
+int _zbar_qr_found_line(qr_reader *reader, int dir, const qr_finder_line *line)
+{
+ /* minimally intrusive brute force version */
+ qr_finder_lines *lines = &reader->finder_lines[dir];
+
+ if (lines->nlines >= lines->clines) {
+ lines->clines *= 2;
+ lines->lines =
+ realloc(lines->lines, ++lines->clines * sizeof(*lines->lines));
+ }
+
+ memcpy(lines->lines + lines->nlines++, line, sizeof(*line));
+
+ return (0);
+}
+
+static inline void qr_svg_centers(const qr_finder_center *centers, int ncenters)
+{
+ int i, j;
+ svg_path_start("centers", 1, 0, 0);
+ for (i = 0; i < ncenters; i++)
+ svg_path_moveto(SVG_ABS, centers[i].pos[0], centers[i].pos[1]);
+ svg_path_end();
+
+ svg_path_start("edge-pts", 1, 0, 0);
+ for (i = 0; i < ncenters; i++) {
+ const qr_finder_center *cen = centers + i;
+ for (j = 0; j < cen->nedge_pts; j++)
+ svg_path_moveto(SVG_ABS, cen->edge_pts[j].pos[0],
+ cen->edge_pts[j].pos[1]);
+ }
+ svg_path_end();
+}
+
+int _zbar_qr_decode(qr_reader *reader, zbar_image_scanner_t *iscn,
+ zbar_image_t *img)
+{
+ int nqrdata = 0, ncenters;
+ qr_finder_edge_pt *edge_pts = NULL;
+ qr_finder_center *centers = NULL;
+
+ if (reader->finder_lines[0].nlines < 9 ||
+ reader->finder_lines[1].nlines < 9)
+ return (0);
+
+ svg_group_start("finder", 0, 1. / (1 << QR_FINDER_SUBPREC), 0, 0, 0);
+
+ ncenters = qr_finder_centers_locate(&centers, &edge_pts, reader, 0, 0);
+
+ zprintf(14, "%dx%d finders, %d centers:\n", reader->finder_lines[0].nlines,
+ reader->finder_lines[1].nlines, ncenters);
+ qr_svg_centers(centers, ncenters);
+
+ if (ncenters >= 3) {
+ void *bin = qr_binarize(img->data, img->width, img->height);
+
+ qr_code_data_list qrlist;
+ qr_code_data_list_init(&qrlist);
+
+ qr_reader_match_centers(reader, &qrlist, centers, ncenters, bin,
+ img->width, img->height);
+
+ if (qrlist.nqrdata > 0)
+ nqrdata = qr_code_data_list_extract_text(&qrlist, iscn, img);
+
+ qr_code_data_list_clear(&qrlist);
+ free(bin);
+ }
+ svg_group_end();
+
+ if (centers)
+ free(centers);
+ if (edge_pts)
+ free(edge_pts);
+ return (nqrdata);
+}