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