1 /*
2 * Copyright 2016 Huy Cuong Nguyen
3 * Copyright 2016 ZXing authors
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "PDFWriter.h"
19 #include "PDFEncoder.h"
20 #include "BitMatrix.h"
21
22 #include <utility>
23
24 namespace ZXing {
25 namespace Pdf417 {
26
27 /**
28 * default white space (margin) around the code
29 */
30 static const int WHITE_SPACE = 30;
31
32 /**
33 * default error correction level
34 */
35 static const int DEFAULT_ERROR_CORRECTION_LEVEL = 2;
36
37 /**
38 * Takes and rotates the it 90 degrees
39 */
RotateArray(const std::vector<std::vector<bool>> & input,std::vector<std::vector<bool>> & output)40 static void RotateArray(const std::vector<std::vector<bool>>& input, std::vector<std::vector<bool>>& output)
41 {
42 size_t height = input.size();
43 size_t width = input[0].size();
44 output.resize(width);
45 for (size_t i = 0; i < width; ++i) {
46 output[i].resize(height);
47 }
48 for (size_t ii = 0; ii < height; ++ii) {
49 // This makes the direction consistent on screen when rotating the screen
50 size_t inverseii = height - ii - 1;
51 for (size_t jj = 0; jj < width; ++jj) {
52 output[jj][inverseii] = input[ii][jj];
53 }
54 }
55 }
56
57 /**
58 * This takes an array holding the values of the PDF 417
59 *
60 * @param input a byte array of information with 0 is black, and 1 is white
61 * @param margin border around the barcode
62 * @return BitMatrix of the input
63 */
BitMatrixFromBitArray(const std::vector<std::vector<bool>> & input,int margin)64 static BitMatrix BitMatrixFromBitArray(const std::vector<std::vector<bool>>& input, int margin)
65 {
66 // Creates the bitmatrix with extra space for whitespace
67 int width = Size(input[0]);
68 int height = Size(input);
69 BitMatrix result(width + 2 * margin, height + 2 * margin);
70 for (int y = 0, yOutput = static_cast<int>(result.height()) - margin - 1; y < height; y++, yOutput--) {
71 for (int x = 0; x < width; ++x) {
72 // Zero is white in the bytematrix
73 if (input[y][x]) {
74 result.set(x + margin, yOutput);
75 }
76 }
77 }
78 return result;
79 }
80
81 BitMatrix
encode(const std::wstring & contents,int width,int height) const82 Writer::encode(const std::wstring& contents, int width, int height) const
83 {
84 int margin = _margin >= 0 ? _margin : WHITE_SPACE;
85 int ecLevel = _ecLevel >= 0 ? _ecLevel : DEFAULT_ERROR_CORRECTION_LEVEL;
86
87 BarcodeMatrix resultMatrix = _encoder->generateBarcodeLogic(contents, ecLevel);
88 int aspectRatio = 4;
89 std::vector<std::vector<bool>> originalScale;
90 resultMatrix.getScaledMatrix(1, aspectRatio, originalScale);
91 bool rotated = false;
92 if ((height > width) != (originalScale[0].size() < originalScale.size())) {
93 std::vector<std::vector<bool>> temp;
94 RotateArray(originalScale, temp);
95 originalScale = temp;
96 rotated = true;
97 }
98
99 int scaleX = width / Size(originalScale[0]);
100 int scaleY = height / Size(originalScale);
101
102 int scale;
103 if (scaleX < scaleY) {
104 scale = scaleX;
105 }
106 else {
107 scale = scaleY;
108 }
109
110 if (scale > 1) {
111 std::vector<std::vector<bool>> scaledMatrix;
112 resultMatrix.getScaledMatrix(scale, scale * aspectRatio, scaledMatrix);
113 if (rotated) {
114 std::vector<std::vector<bool>> temp;
115 RotateArray(scaledMatrix, temp);
116 scaledMatrix = temp;
117 }
118 return BitMatrixFromBitArray(scaledMatrix, margin);
119 }
120 else {
121 return BitMatrixFromBitArray(originalScale, margin);
122 }
123 }
124
Writer()125 Writer::Writer()
126 {
127 _encoder.reset(new Encoder);
128 }
129
Writer(Writer && other)130 Writer::Writer(Writer &&other) noexcept:
131 _margin(other._margin),
132 _ecLevel(other._ecLevel),
133 _encoder(std::move(other._encoder))
134 {
135 }
136
~Writer()137 Writer::~Writer()
138 {
139 }
140
141 Writer&
setDimensions(int minCols,int maxCols,int minRows,int maxRows)142 Writer::setDimensions(int minCols, int maxCols, int minRows, int maxRows)
143 {
144 _encoder->setDimensions(minCols, maxCols, minRows, maxRows);
145 return *this;
146 }
147
148 Writer&
setCompaction(Compaction compaction)149 Writer::setCompaction(Compaction compaction)
150 {
151 _encoder->setCompaction(compaction);
152 return *this;
153 }
154
155 /**
156 * @param compact if true, enables compaction
157 */
158 Writer&
setCompact(bool compact)159 Writer::setCompact(bool compact)
160 {
161 _encoder->setCompact(compact);
162 return *this;
163 }
164
165 /**
166 * @param encoding sets character encoding to use
167 */
168 Writer&
setEncoding(CharacterSet encoding)169 Writer::setEncoding(CharacterSet encoding)
170 {
171 _encoder->setEncoding(encoding);
172 return *this;
173 }
174
175
176 } // Pdf417
177 } // ZXing
178