1 /*
2 * Copyright 2016 Nu-book Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 #include "BarcodeFormat.h"
18 #include "BitMatrix.h"
19 #include "ByteMatrix.h"
20 #include "MultiFormatWriter.h"
21 #include "TextUtfEncoding.h"
22 
23 #include <algorithm>
24 #include <cctype>
25 #include <cstdlib>
26 #include <cstring>
27 #include <iostream>
28 #include <stdexcept>
29 #include <string>
30 
31 #define STB_IMAGE_WRITE_IMPLEMENTATION
32 #include "stb_image_write.h"
33 
34 using namespace ZXing;
35 
PrintUsage(const char * exePath)36 static void PrintUsage(const char* exePath)
37 {
38 	std::cout << "Usage: " << exePath << " [-size <width>x<height>] [-margin <margin>] [-encoding <encoding>] [-ecc <level>] <format> <text> <output>\n"
39 	          << "    -size      Size of generated image\n"
40 	          << "    -margin    Margin around barcode\n"
41 	          << "    -encoding  Encoding used to encode input text\n"
42 	          << "    -ecc       Error correction level, [0-8]\n"
43 	          << "\n"
44 			  << "Supported formats are:\n";
45 	for (auto f : BarcodeFormats::all()) {
46 		std::cout << "    " << ToString(f) << "\n";
47 	}
48 	std::cout << "Format can be lowercase letters, with or without '-'.\n";
49 }
50 
ParseSize(std::string str,int * width,int * height)51 static bool ParseSize(std::string str, int* width, int* height)
52 {
53 	std::transform(str.begin(), str.end(), str.begin(), [](char c) { return (char)std::tolower(c); });
54 	auto xPos = str.find('x');
55 	if (xPos != std::string::npos) {
56 		*width = std::stoi(str.substr(0, xPos));
57 		*height = std::stoi(str.substr(xPos + 1));
58 		return true;
59 	}
60 	return false;
61 }
62 
ParseOptions(int argc,char * argv[],int * width,int * height,int * margin,int * eccLevel,BarcodeFormat * format,std::string * text,std::string * filePath)63 static bool ParseOptions(int argc, char* argv[], int* width, int* height, int* margin, int* eccLevel, BarcodeFormat* format, std::string* text, std::string* filePath)
64 {
65 	int nonOptArgCount = 0;
66 	for (int i = 1; i < argc; ++i) {
67 		if (strcmp(argv[i], "-size") == 0) {
68 			if (++i == argc)
69 				return false;
70 			if (!ParseSize(argv[i], width, height)) {
71 				std::cerr << "Invalid size specification: " << argv[i] << std::endl;
72 				return false;
73 			}
74 		}
75 		else if (strcmp(argv[i], "-margin") == 0) {
76 			if (++i == argc)
77 				return false;
78 			*margin = std::stoi(argv[i]);
79 		}
80 		else if (strcmp(argv[i], "-ecc") == 0) {
81 			if (++i == argc)
82 				return false;
83 			*eccLevel = std::stoi(argv[i]);
84 		}
85 		else if (nonOptArgCount == 0) {
86 			*format = BarcodeFormatFromString(argv[i]);
87 			if (*format == BarcodeFormat::None) {
88 				std::cerr << "Unrecognized format: " << argv[i] << std::endl;
89 				return false;
90 			}
91 			++nonOptArgCount;
92 		}
93 		else if (nonOptArgCount == 1) {
94 			*text = argv[i];
95 			++nonOptArgCount;
96 		}
97 		else if (nonOptArgCount == 2) {
98 			*filePath = argv[i];
99 			++nonOptArgCount;
100 		}
101 		else {
102 			return false;
103 		}
104 	}
105 
106 	return nonOptArgCount == 3;
107 }
108 
GetExtension(const std::string & path)109 static std::string GetExtension(const std::string& path)
110 {
111 	auto fileNameStart = path.find_last_of("/\\");
112 	auto fileName = fileNameStart == std::string::npos ? path : path.substr(fileNameStart + 1);
113 	auto extStart = fileName.find_last_of('.');
114 	auto ext = extStart == std::string::npos ? "" : fileName.substr(extStart + 1);
115 	std::transform(ext.begin(), ext.end(), ext.begin(), [](char c) { return std::tolower(c); });
116 	return ext;
117 }
118 
main(int argc,char * argv[])119 int main(int argc, char* argv[])
120 {
121 	int width = 100, height = 100;
122 	int margin = 10;
123 	int eccLevel = -1;
124 	std::string text, filePath;
125 	BarcodeFormat format;
126 
127 	if (!ParseOptions(argc, argv, &width, &height, &margin, &eccLevel, &format, &text, &filePath)) {
128 		PrintUsage(argv[0]);
129 		return -1;
130 	}
131 
132 	try {
133 		auto writer = MultiFormatWriter(format).setMargin(margin).setEccLevel(eccLevel);
134 		auto bitmap = ToMatrix<uint8_t>(writer.encode(TextUtfEncoding::FromUtf8(text), width, height));
135 
136 		auto ext = GetExtension(filePath);
137 		int success = 0;
138 		if (ext == "" || ext == "png") {
139 			success = stbi_write_png(filePath.c_str(), bitmap.width(), bitmap.height(), 1, bitmap.data(), 0);
140 		}
141 		else if (ext == "jpg" || ext == "jpeg") {
142 			success = stbi_write_jpg(filePath.c_str(), bitmap.width(), bitmap.height(), 1, bitmap.data(), 0);
143 		}
144 
145 		if (!success) {
146 			std::cerr << "Failed to write image: " << filePath << std::endl;
147 			return -1;
148 		}
149 	}
150 	catch (const std::exception& e) {
151 		std::cerr << e.what() << std::endl;
152 		return -1;
153 	}
154 
155 	return 0;
156 }
157