Houjie
2025-07-24 52a3ff1bce1417b39f6872d8e8cb378e9c2ccc6f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
"use strict";
/*
 * Copyright 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
var BitArray_1 = require("../common/BitArray");
var DecodeHintType_1 = require("../DecodeHintType");
var ResultMetadataType_1 = require("../ResultMetadataType");
var ResultPoint_1 = require("../ResultPoint");
var NotFoundException_1 = require("../NotFoundException");
/**
 * Encapsulates functionality and implementation that is common to all families
 * of one-dimensional barcodes.
 *
 * @author dswitkin@google.com (Daniel Switkin)
 * @author Sean Owen
 */
var OneDReader = /** @class */ (function () {
    function OneDReader() {
    }
    /*
    @Override
    public Result decode(BinaryBitmap image) throws NotFoundException, FormatException {
      return decode(image, null);
    }
    */
    // Note that we don't try rotation without the try harder flag, even if rotation was supported.
    // @Override
    OneDReader.prototype.decode = function (image, hints) {
        try {
            return this.doDecode(image, hints);
        }
        catch (nfe) {
            var tryHarder = hints && (hints.get(DecodeHintType_1.default.TRY_HARDER) === true);
            if (tryHarder && image.isRotateSupported()) {
                var rotatedImage = image.rotateCounterClockwise();
                var result = this.doDecode(rotatedImage, hints);
                // Record that we found it rotated 90 degrees CCW / 270 degrees CW
                var metadata = result.getResultMetadata();
                var orientation_1 = 270;
                if (metadata !== null && (metadata.get(ResultMetadataType_1.default.ORIENTATION) === true)) {
                    // But if we found it reversed in doDecode(), add in that result here:
                    orientation_1 = (orientation_1 + metadata.get(ResultMetadataType_1.default.ORIENTATION) % 360);
                }
                result.putMetadata(ResultMetadataType_1.default.ORIENTATION, orientation_1);
                // Update result points
                var points = result.getResultPoints();
                if (points !== null) {
                    var height = rotatedImage.getHeight();
                    for (var i = 0; i < points.length; i++) {
                        points[i] = new ResultPoint_1.default(height - points[i].getY() - 1, points[i].getX());
                    }
                }
                return result;
            }
            else {
                throw new NotFoundException_1.default();
            }
        }
    };
    // @Override
    OneDReader.prototype.reset = function () {
        // do nothing
    };
    /**
     * We're going to examine rows from the middle outward, searching alternately above and below the
     * middle, and farther out each time. rowStep is the number of rows between each successive
     * attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then
     * middle + rowStep, then middle - (2 * rowStep), etc.
     * rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily
     * decided that moving up and down by about 1/16 of the image is pretty good; we try more of the
     * image if "trying harder".
     *
     * @param image The image to decode
     * @param hints Any hints that were requested
     * @return The contents of the decoded barcode
     * @throws NotFoundException Any spontaneous errors which occur
     */
    OneDReader.prototype.doDecode = function (image, hints) {
        var width = image.getWidth();
        var height = image.getHeight();
        var row = new BitArray_1.default(width);
        var tryHarder = hints && (hints.get(DecodeHintType_1.default.TRY_HARDER) === true);
        var rowStep = Math.max(1, height >> (tryHarder ? 8 : 5));
        var maxLines;
        if (tryHarder) {
            maxLines = height; // Look at the whole image, not just the center
        }
        else {
            maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image
        }
        var middle = Math.trunc(height / 2);
        for (var x = 0; x < maxLines; x++) {
            // Scanning from the middle out. Determine which row we're looking at next:
            var rowStepsAboveOrBelow = Math.trunc((x + 1) / 2);
            var isAbove = (x & 0x01) === 0; // i.e. is x even?
            var rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow);
            if (rowNumber < 0 || rowNumber >= height) {
                // Oops, if we run off the top or bottom, stop
                break;
            }
            // Estimate black point for this row and load it:
            try {
                row = image.getBlackRow(rowNumber, row);
            }
            catch (ignored) {
                continue;
            }
            var _loop_1 = function (attempt) {
                if (attempt === 1) { // trying again?
                    row.reverse(); // reverse the row and continue
                    // This means we will only ever draw result points *once* in the life of this method
                    // since we want to avoid drawing the wrong points after flipping the row, and,
                    // don't want to clutter with noise from every single row scan -- just the scans
                    // that start on the center line.
                    if (hints && (hints.get(DecodeHintType_1.default.NEED_RESULT_POINT_CALLBACK) === true)) {
                        var newHints_1 = new Map();
                        hints.forEach(function (hint, key) { return newHints_1.set(key, hint); });
                        newHints_1.delete(DecodeHintType_1.default.NEED_RESULT_POINT_CALLBACK);
                        hints = newHints_1;
                    }
                }
                try {
                    // Look for a barcode
                    var result = this_1.decodeRow(rowNumber, row, hints);
                    // We found our barcode
                    if (attempt === 1) {
                        // But it was upside down, so note that
                        result.putMetadata(ResultMetadataType_1.default.ORIENTATION, 180);
                        // And remember to flip the result points horizontally.
                        var points = result.getResultPoints();
                        if (points !== null) {
                            points[0] = new ResultPoint_1.default(width - points[0].getX() - 1, points[0].getY());
                            points[1] = new ResultPoint_1.default(width - points[1].getX() - 1, points[1].getY());
                        }
                    }
                    return { value: result };
                }
                catch (re) {
                    // continue -- just couldn't decode this row
                }
            };
            var this_1 = this;
            // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to
            // handle decoding upside down barcodes.
            for (var attempt = 0; attempt < 2; attempt++) {
                var state_1 = _loop_1(attempt);
                if (typeof state_1 === "object")
                    return state_1.value;
            }
        }
        throw new NotFoundException_1.default();
    };
    /**
     * Records the size of successive runs of white and black pixels in a row, starting at a given point.
     * The values are recorded in the given array, and the number of runs recorded is equal to the size
     * of the array. If the row starts on a white pixel at the given start point, then the first count
     * recorded is the run of white pixels starting from that point; likewise it is the count of a run
     * of black pixels if the row begin on a black pixels at that point.
     *
     * @param row row to count from
     * @param start offset into row to start at
     * @param counters array into which to record counts
     * @throws NotFoundException if counters cannot be filled entirely from row before running out
     *  of pixels
     */
    OneDReader.recordPattern = function (row, start, counters) {
        var numCounters = counters.length;
        for (var index = 0; index < numCounters; index++)
            counters[index] = 0;
        var end = row.getSize();
        if (start >= end) {
            throw new NotFoundException_1.default();
        }
        var isWhite = !row.get(start);
        var counterPosition = 0;
        var i = start;
        while (i < end) {
            if (row.get(i) !== isWhite) {
                counters[counterPosition]++;
            }
            else {
                if (++counterPosition === numCounters) {
                    break;
                }
                else {
                    counters[counterPosition] = 1;
                    isWhite = !isWhite;
                }
            }
            i++;
        }
        // If we read fully the last section of pixels and filled up our counters -- or filled
        // the last counter but ran off the side of the image, OK. Otherwise, a problem.
        if (!(counterPosition === numCounters || (counterPosition === numCounters - 1 && i === end))) {
            throw new NotFoundException_1.default();
        }
    };
    OneDReader.recordPatternInReverse = function (row, start, counters) {
        // This could be more efficient I guess
        var numTransitionsLeft = counters.length;
        var last = row.get(start);
        while (start > 0 && numTransitionsLeft >= 0) {
            if (row.get(--start) !== last) {
                numTransitionsLeft--;
                last = !last;
            }
        }
        if (numTransitionsLeft >= 0) {
            throw new NotFoundException_1.default();
        }
        OneDReader.recordPattern(row, start + 1, counters);
    };
    /**
     * Determines how closely a set of observed counts of runs of black/white values matches a given
     * target pattern. This is reported as the ratio of the total variance from the expected pattern
     * proportions across all pattern elements, to the length of the pattern.
     *
     * @param counters observed counters
     * @param pattern expected pattern
     * @param maxIndividualVariance The most any counter can differ before we give up
     * @return ratio of total variance between counters and pattern compared to total pattern size
     */
    OneDReader.patternMatchVariance = function (counters, pattern, maxIndividualVariance) {
        var numCounters = counters.length;
        var total = 0;
        var patternLength = 0;
        for (var i = 0; i < numCounters; i++) {
            total += counters[i];
            patternLength += pattern[i];
        }
        if (total < patternLength) {
            // If we don't even have one pixel per unit of bar width, assume this is too small
            // to reliably match, so fail:
            return Number.POSITIVE_INFINITY;
        }
        var unitBarWidth = total / patternLength;
        maxIndividualVariance *= unitBarWidth;
        var totalVariance = 0.0;
        for (var x = 0; x < numCounters; x++) {
            var counter = counters[x];
            var scaledPattern = pattern[x] * unitBarWidth;
            var variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter;
            if (variance > maxIndividualVariance) {
                return Number.POSITIVE_INFINITY;
            }
            totalVariance += variance;
        }
        return totalVariance / total;
    };
    return OneDReader;
}());
exports.default = OneDReader;