Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zxing-cpp/core/src/WriteBarcode.cpp @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* | |
| 2 * Copyright 2024 Axel Waggershauser | |
| 3 */ | |
| 4 // SPDX-License-Identifier: Apache-2.0 | |
| 5 | |
| 6 #ifdef ZXING_EXPERIMENTAL_API | |
| 7 | |
| 8 #include "WriteBarcode.h" | |
| 9 #include "BitMatrix.h" | |
| 10 | |
| 11 #if !defined(ZXING_READERS) && !defined(ZXING_WRITERS) | |
| 12 #include "Version.h" | |
| 13 #endif | |
| 14 | |
| 15 #include <sstream> | |
| 16 | |
| 17 #ifdef ZXING_USE_ZINT | |
| 18 | |
| 19 #include <zint.h> | |
| 20 | |
| 21 #else | |
| 22 | |
| 23 struct zint_symbol {}; | |
| 24 | |
| 25 #endif // ZXING_USE_ZINT | |
| 26 | |
| 27 namespace ZXing { | |
| 28 | |
| 29 struct CreatorOptions::Data | |
| 30 { | |
| 31 BarcodeFormat format; | |
| 32 bool readerInit = false; | |
| 33 bool forceSquareDataMatrix = false; | |
| 34 std::string ecLevel; | |
| 35 | |
| 36 // symbol size (qrcode, datamatrix, etc), map from I, 'WxH' | |
| 37 // structured_append (idx, cnt, ID) | |
| 38 | |
| 39 mutable unique_zint_symbol zint; | |
| 40 | |
| 41 #ifndef __cpp_aggregate_paren_init | |
| 42 Data(BarcodeFormat f) : format(f) {} | |
| 43 #endif | |
| 44 }; | |
| 45 | |
| 46 #define ZX_PROPERTY(TYPE, NAME) \ | |
| 47 TYPE CreatorOptions::NAME() const noexcept { return d->NAME; } \ | |
| 48 CreatorOptions& CreatorOptions::NAME(TYPE v)& { return d->NAME = std::move(v), *this; } \ | |
| 49 CreatorOptions&& CreatorOptions::NAME(TYPE v)&& { return d->NAME = std::move(v), std::move(*this); } | |
| 50 | |
| 51 ZX_PROPERTY(BarcodeFormat, format) | |
| 52 ZX_PROPERTY(bool, readerInit) | |
| 53 ZX_PROPERTY(bool, forceSquareDataMatrix) | |
| 54 ZX_PROPERTY(std::string, ecLevel) | |
| 55 | |
| 56 #undef ZX_PROPERTY | |
| 57 | |
| 58 CreatorOptions::CreatorOptions(BarcodeFormat format) : d(std::make_unique<Data>(format)) {} | |
| 59 CreatorOptions::~CreatorOptions() = default; | |
| 60 CreatorOptions::CreatorOptions(CreatorOptions&&) = default; | |
| 61 CreatorOptions& CreatorOptions::operator=(CreatorOptions&&) = default; | |
| 62 | |
| 63 | |
| 64 struct WriterOptions::Data | |
| 65 { | |
| 66 int scale = 0; | |
| 67 int sizeHint = 0; | |
| 68 int rotate = 0; | |
| 69 bool withHRT = false; | |
| 70 bool withQuietZones = true; | |
| 71 }; | |
| 72 | |
| 73 #define ZX_PROPERTY(TYPE, NAME) \ | |
| 74 TYPE WriterOptions::NAME() const noexcept { return d->NAME; } \ | |
| 75 WriterOptions& WriterOptions::NAME(TYPE v)& { return d->NAME = std::move(v), *this; } \ | |
| 76 WriterOptions&& WriterOptions::NAME(TYPE v)&& { return d->NAME = std::move(v), std::move(*this); } | |
| 77 | |
| 78 ZX_PROPERTY(int, scale) | |
| 79 ZX_PROPERTY(int, sizeHint) | |
| 80 ZX_PROPERTY(int, rotate) | |
| 81 ZX_PROPERTY(bool, withHRT) | |
| 82 ZX_PROPERTY(bool, withQuietZones) | |
| 83 | |
| 84 #undef ZX_PROPERTY | |
| 85 | |
| 86 WriterOptions::WriterOptions() : d(std::make_unique<Data>()) {} | |
| 87 WriterOptions::~WriterOptions() = default; | |
| 88 WriterOptions::WriterOptions(WriterOptions&&) = default; | |
| 89 WriterOptions& WriterOptions::operator=(WriterOptions&&) = default; | |
| 90 | |
| 91 static bool IsLinearCode(BarcodeFormat format) | |
| 92 { | |
| 93 return BarcodeFormats(BarcodeFormat::LinearCodes).testFlag(format); | |
| 94 } | |
| 95 | |
| 96 static std::string ToSVG(ImageView iv) | |
| 97 { | |
| 98 if (!iv.data()) | |
| 99 return {}; | |
| 100 | |
| 101 // see https://stackoverflow.com/questions/10789059/create-qr-code-in-vector-image/60638350#60638350 | |
| 102 | |
| 103 std::ostringstream res; | |
| 104 | |
| 105 res << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | |
| 106 << "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 " << iv.width() << " " << iv.height() | |
| 107 << "\" stroke=\"none\">\n" | |
| 108 << "<path d=\""; | |
| 109 | |
| 110 for (int y = 0; y < iv.height(); ++y) | |
| 111 for (int x = 0; x < iv.width(); ++x) | |
| 112 if (*iv.data(x, y) == 0) | |
| 113 res << "M" << x << "," << y << "h1v1h-1z"; | |
| 114 | |
| 115 res << "\"/>\n</svg>"; | |
| 116 | |
| 117 return res.str(); | |
| 118 } | |
| 119 | |
| 120 static Image ToImage(BitMatrix bits, bool isLinearCode, const WriterOptions& opts) | |
| 121 { | |
| 122 bits.flipAll(); | |
| 123 auto symbol = Inflate(std::move(bits), opts.sizeHint(), | |
| 124 isLinearCode ? std::clamp(opts.sizeHint() / 2, 50, 300) : opts.sizeHint(), | |
| 125 opts.withQuietZones() ? 10 : 0); | |
| 126 auto bitmap = ToMatrix<uint8_t>(symbol); | |
| 127 auto iv = Image(symbol.width(), symbol.height()); | |
| 128 std::memcpy(const_cast<uint8_t*>(iv.data()), bitmap.data(), iv.width() * iv.height()); | |
| 129 return iv; | |
| 130 } | |
| 131 | |
| 132 } // namespace ZXing | |
| 133 | |
| 134 | |
| 135 #ifdef ZXING_WRITERS | |
| 136 | |
| 137 #ifdef ZXING_USE_ZINT | |
| 138 #include "ECI.h" | |
| 139 #include "ReadBarcode.h" | |
| 140 | |
| 141 #include <charconv> | |
| 142 #include <zint.h> | |
| 143 | |
| 144 namespace ZXing { | |
| 145 | |
| 146 struct BarcodeFormatZXing2Zint | |
| 147 { | |
| 148 BarcodeFormat zxing; | |
| 149 int zint; | |
| 150 }; | |
| 151 | |
| 152 static constexpr BarcodeFormatZXing2Zint barcodeFormatZXing2Zint[] = { | |
| 153 {BarcodeFormat::Aztec, BARCODE_AZTEC}, | |
| 154 {BarcodeFormat::Codabar, BARCODE_CODABAR}, | |
| 155 {BarcodeFormat::Code39, BARCODE_CODE39}, | |
| 156 {BarcodeFormat::Code93, BARCODE_CODE93}, | |
| 157 {BarcodeFormat::Code128, BARCODE_CODE128}, | |
| 158 {BarcodeFormat::DataBar, BARCODE_DBAR_OMN}, | |
| 159 {BarcodeFormat::DataBarExpanded, BARCODE_DBAR_EXP}, | |
| 160 {BarcodeFormat::DataBarLimited, BARCODE_DBAR_LTD}, | |
| 161 {BarcodeFormat::DataMatrix, BARCODE_DATAMATRIX}, | |
| 162 {BarcodeFormat::DXFilmEdge, BARCODE_DXFILMEDGE}, | |
| 163 {BarcodeFormat::EAN8, BARCODE_EANX}, | |
| 164 {BarcodeFormat::EAN13, BARCODE_EANX}, | |
| 165 {BarcodeFormat::ITF, BARCODE_C25INTER}, | |
| 166 {BarcodeFormat::MaxiCode, BARCODE_MAXICODE}, | |
| 167 {BarcodeFormat::MicroQRCode, BARCODE_MICROQR}, | |
| 168 {BarcodeFormat::PDF417, BARCODE_PDF417}, | |
| 169 {BarcodeFormat::QRCode, BARCODE_QRCODE}, | |
| 170 {BarcodeFormat::RMQRCode, BARCODE_RMQR}, | |
| 171 {BarcodeFormat::UPCA, BARCODE_UPCA}, | |
| 172 {BarcodeFormat::UPCE, BARCODE_UPCE}, | |
| 173 }; | |
| 174 | |
| 175 struct String2Int | |
| 176 { | |
| 177 const char* str; | |
| 178 int val; | |
| 179 }; | |
| 180 | |
| 181 static int ParseECLevel(int symbology, std::string_view s) | |
| 182 { | |
| 183 constexpr std::string_view EC_LABELS_QR[4] = {"L", "M", "Q", "H"}; | |
| 184 | |
| 185 int res = 0; | |
| 186 if (Contains({BARCODE_QRCODE, BARCODE_MICROQR, BARCODE_RMQR}, symbology)) | |
| 187 if ((res = IndexOf(EC_LABELS_QR, s) != -1)) | |
| 188 return res + 1; | |
| 189 | |
| 190 if (std::from_chars(s.data(), s.data() + s.size() - (s.back() == '%'), res).ec != std::errc{}) | |
| 191 throw std::invalid_argument("Invalid ecLevel: '" + std::string(s) + "'"); | |
| 192 | |
| 193 auto findClosestECLevel = [](const std::vector<int>& list, int val) { | |
| 194 int mIdx = -2, mAbs = 100; | |
| 195 for (int i = 0; i < Size(list); ++i) | |
| 196 if (int abs = std::abs(val - list[i]); abs < mAbs) { | |
| 197 mIdx = i; | |
| 198 mAbs = abs; | |
| 199 } | |
| 200 return mIdx + 1; | |
| 201 }; | |
| 202 | |
| 203 if (s.back()=='%'){ | |
| 204 switch (symbology) { | |
| 205 case BARCODE_QRCODE: | |
| 206 case BARCODE_MICROQR: | |
| 207 case BARCODE_RMQR: | |
| 208 return findClosestECLevel({20, 37, 55, 65}, res); | |
| 209 case BARCODE_AZTEC: | |
| 210 return findClosestECLevel({10, 23, 26, 50}, res); | |
| 211 case BARCODE_PDF417: | |
| 212 // TODO: do something sensible with PDF417? | |
| 213 default: | |
| 214 return -1; | |
| 215 } | |
| 216 } | |
| 217 | |
| 218 return res; | |
| 219 }; | |
| 220 | |
| 221 zint_symbol* CreatorOptions::zint() const | |
| 222 { | |
| 223 auto& zint = d->zint; | |
| 224 | |
| 225 if (!zint) { | |
| 226 #ifdef PRINT_DEBUG | |
| 227 printf("zint version: %d, sizeof(zint_symbol): %ld\n", ZBarcode_Version(), sizeof(zint_symbol)); | |
| 228 #endif | |
| 229 zint.reset(ZBarcode_Create()); | |
| 230 | |
| 231 auto i = FindIf(barcodeFormatZXing2Zint, [zxing = format()](auto& v) { return v.zxing == zxing; }); | |
| 232 if (i == std::end(barcodeFormatZXing2Zint)) | |
| 233 throw std::invalid_argument("unsupported barcode format: " + ToString(format())); | |
| 234 zint->symbology = i->zint; | |
| 235 | |
| 236 zint->scale = 0.5f; | |
| 237 | |
| 238 if (!ecLevel().empty()) | |
| 239 zint->option_1 = ParseECLevel(zint->symbology, ecLevel()); | |
| 240 } | |
| 241 | |
| 242 return zint.get(); | |
| 243 } | |
| 244 | |
| 245 #define CHECK(ZINT_CALL) \ | |
| 246 if (int err = (ZINT_CALL); err >= ZINT_ERROR) \ | |
| 247 throw std::invalid_argument(zint->errtxt); | |
| 248 | |
| 249 Barcode CreateBarcode(const void* data, int size, int mode, const CreatorOptions& opts) | |
| 250 { | |
| 251 auto zint = opts.zint(); | |
| 252 | |
| 253 zint->input_mode = mode; | |
| 254 zint->output_options |= OUT_BUFFER_INTERMEDIATE | BARCODE_QUIET_ZONES; | |
| 255 | |
| 256 if (mode == DATA_MODE && ZBarcode_Cap(zint->symbology, ZINT_CAP_ECI)) | |
| 257 zint->eci = static_cast<int>(ECI::Binary); | |
| 258 | |
| 259 CHECK(ZBarcode_Encode_and_Buffer(zint, (uint8_t*)data, size, 0)); | |
| 260 | |
| 261 #ifdef PRINT_DEBUG | |
| 262 printf("create symbol with size: %dx%d\n", zint->width, zint->rows); | |
| 263 #endif | |
| 264 | |
| 265 #ifdef ZXING_READERS | |
| 266 auto buffer = std::vector<uint8_t>(zint->bitmap_width * zint->bitmap_height); | |
| 267 std::transform(zint->bitmap, zint->bitmap + zint->bitmap_width * zint->bitmap_height, buffer.data(), | |
| 268 [](unsigned char v) { return (v == '0') * 0xff; }); | |
| 269 | |
| 270 auto res = ReadBarcode({buffer.data(), zint->bitmap_width, zint->bitmap_height, ImageFormat::Lum}, | |
| 271 ReaderOptions().setFormats(opts.format()).setIsPure(true).setBinarizer(Binarizer::BoolCast)); | |
| 272 #else | |
| 273 //TODO: replace by proper construction from encoded data from within zint | |
| 274 auto res = Barcode(std::string((const char*)data, size), 0, 0, 0, opts.format(), {}); | |
| 275 #endif | |
| 276 | |
| 277 auto bits = BitMatrix(zint->bitmap_width, zint->bitmap_height); | |
| 278 std::transform(zint->bitmap, zint->bitmap + zint->bitmap_width * zint->bitmap_height, bits.row(0).begin(), | |
| 279 [](unsigned char v) { return (v == '1') * BitMatrix::SET_V; }); | |
| 280 res.symbol(std::move(bits)); | |
| 281 res.zint(std::move(opts.d->zint)); | |
| 282 | |
| 283 return res; | |
| 284 } | |
| 285 | |
| 286 Barcode CreateBarcodeFromText(std::string_view contents, const CreatorOptions& opts) | |
| 287 { | |
| 288 return CreateBarcode(contents.data(), contents.size(), UNICODE_MODE, opts); | |
| 289 } | |
| 290 | |
| 291 #if __cplusplus > 201703L | |
| 292 Barcode CreateBarcodeFromText(std::u8string_view contents, const CreatorOptions& opts) | |
| 293 { | |
| 294 return CreateBarcode(contents.data(), contents.size(), UNICODE_MODE, opts); | |
| 295 } | |
| 296 #endif | |
| 297 | |
| 298 Barcode CreateBarcodeFromBytes(const void* data, int size, const CreatorOptions& opts) | |
| 299 { | |
| 300 return CreateBarcode(data, size, DATA_MODE, opts); | |
| 301 } | |
| 302 | |
| 303 // Writer ======================================================================== | |
| 304 | |
| 305 struct SetCommonWriterOptions | |
| 306 { | |
| 307 zint_symbol* zint; | |
| 308 | |
| 309 SetCommonWriterOptions(zint_symbol* zint, const WriterOptions& opts) : zint(zint) | |
| 310 { | |
| 311 zint->show_hrt = opts.withHRT(); | |
| 312 | |
| 313 zint->output_options &= ~OUT_BUFFER_INTERMEDIATE; | |
| 314 zint->output_options |= opts.withQuietZones() ? BARCODE_QUIET_ZONES : BARCODE_NO_QUIET_ZONES; | |
| 315 | |
| 316 if (opts.scale()) | |
| 317 zint->scale = opts.scale() / 2.f; | |
| 318 else if (opts.sizeHint()) { | |
| 319 int size = std::max(zint->width, zint->rows); | |
| 320 zint->scale = std::max(1, int(float(opts.sizeHint()) / size)) / 2.f; | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 // reset the defaults such that consecutive write calls don't influence each other | |
| 325 ~SetCommonWriterOptions() { zint->scale = 0.5f; } | |
| 326 }; | |
| 327 | |
| 328 } // ZXing | |
| 329 | |
| 330 #else // ZXING_USE_ZINT | |
| 331 | |
| 332 #include "MultiFormatWriter.h" | |
| 333 #include "ReadBarcode.h" | |
| 334 | |
| 335 namespace ZXing { | |
| 336 | |
| 337 zint_symbol* CreatorOptions::zint() const { return nullptr; } | |
| 338 | |
| 339 static Barcode CreateBarcode(BitMatrix&& bits, const CreatorOptions& opts) | |
| 340 { | |
| 341 auto img = ToMatrix<uint8_t>(bits); | |
| 342 | |
| 343 auto res = ReadBarcode({img.data(), img.width(), img.height(), ImageFormat::Lum}, | |
| 344 ReaderOptions().setFormats(opts.format()).setIsPure(true).setBinarizer(Binarizer::BoolCast)); | |
| 345 res.symbol(std::move(bits)); | |
| 346 return res; | |
| 347 } | |
| 348 | |
| 349 Barcode CreateBarcodeFromText(std::string_view contents, const CreatorOptions& opts) | |
| 350 { | |
| 351 auto writer = MultiFormatWriter(opts.format()).setMargin(0); | |
| 352 if (!opts.ecLevel().empty()) | |
| 353 writer.setEccLevel(std::stoi(opts.ecLevel())); | |
| 354 writer.setEncoding(CharacterSet::UTF8); // write UTF8 (ECI value 26) for maximum compatibility | |
| 355 | |
| 356 return CreateBarcode(writer.encode(std::string(contents), 0, IsLinearCode(opts.format()) ? 50 : 0), opts); | |
| 357 } | |
| 358 | |
| 359 #if __cplusplus > 201703L | |
| 360 Barcode CreateBarcodeFromText(std::u8string_view contents, const CreatorOptions& opts) | |
| 361 { | |
| 362 return CreateBarcodeFromText({reinterpret_cast<const char*>(contents.data()), contents.size()}, opts); | |
| 363 } | |
| 364 #endif | |
| 365 | |
| 366 Barcode CreateBarcodeFromBytes(const void* data, int size, const CreatorOptions& opts) | |
| 367 { | |
| 368 std::wstring bytes; | |
| 369 for (uint8_t c : std::basic_string_view<uint8_t>((uint8_t*)data, size)) | |
| 370 bytes.push_back(c); | |
| 371 | |
| 372 auto writer = MultiFormatWriter(opts.format()).setMargin(0); | |
| 373 if (!opts.ecLevel().empty()) | |
| 374 writer.setEccLevel(std::stoi(opts.ecLevel())); | |
| 375 writer.setEncoding(CharacterSet::BINARY); | |
| 376 | |
| 377 return CreateBarcode(writer.encode(bytes, 0, IsLinearCode(opts.format()) ? 50 : 0), opts); | |
| 378 } | |
| 379 | |
| 380 } // namespace ZXing | |
| 381 | |
| 382 #endif // ZXING_USE_ZINT | |
| 383 | |
| 384 #else // ZXING_WRITERS | |
| 385 | |
| 386 namespace ZXing { | |
| 387 | |
| 388 zint_symbol* CreatorOptions::zint() const { return nullptr; } | |
| 389 | |
| 390 Barcode CreateBarcodeFromText(std::string_view, const CreatorOptions&) | |
| 391 { | |
| 392 throw std::runtime_error("This build of zxing-cpp does not support creating barcodes."); | |
| 393 } | |
| 394 | |
| 395 #if __cplusplus > 201703L | |
| 396 Barcode CreateBarcodeFromText(std::u8string_view, const CreatorOptions&) | |
| 397 { | |
| 398 throw std::runtime_error("This build of zxing-cpp does not support creating barcodes."); | |
| 399 } | |
| 400 #endif | |
| 401 | |
| 402 Barcode CreateBarcodeFromBytes(const void*, int, const CreatorOptions&) | |
| 403 { | |
| 404 throw std::runtime_error("This build of zxing-cpp does not support creating barcodes."); | |
| 405 } | |
| 406 | |
| 407 } // namespace ZXing | |
| 408 | |
| 409 #endif // ZXING_WRITERS | |
| 410 | |
| 411 namespace ZXing { | |
| 412 | |
| 413 std::string WriteBarcodeToSVG(const Barcode& barcode, [[maybe_unused]] const WriterOptions& opts) | |
| 414 { | |
| 415 auto zint = barcode.zint(); | |
| 416 | |
| 417 if (!zint) | |
| 418 return ToSVG(barcode.symbol()); | |
| 419 | |
| 420 #if defined(ZXING_WRITERS) && defined(ZXING_USE_ZINT) | |
| 421 auto resetOnExit = SetCommonWriterOptions(zint, opts); | |
| 422 | |
| 423 zint->output_options |= BARCODE_MEMORY_FILE;// | EMBED_VECTOR_FONT; | |
| 424 strcpy(zint->outfile, "null.svg"); | |
| 425 | |
| 426 CHECK(ZBarcode_Print(zint, opts.rotate())); | |
| 427 | |
| 428 return std::string(reinterpret_cast<const char*>(zint->memfile), zint->memfile_size); | |
| 429 #else | |
| 430 return {}; // unreachable code | |
| 431 #endif | |
| 432 } | |
| 433 | |
| 434 Image WriteBarcodeToImage(const Barcode& barcode, [[maybe_unused]] const WriterOptions& opts) | |
| 435 { | |
| 436 auto zint = barcode.zint(); | |
| 437 | |
| 438 if (!zint) | |
| 439 return ToImage(barcode._symbol->copy(), IsLinearCode(barcode.format()), opts); | |
| 440 | |
| 441 #if defined(ZXING_WRITERS) && defined(ZXING_USE_ZINT) | |
| 442 auto resetOnExit = SetCommonWriterOptions(zint, opts); | |
| 443 | |
| 444 CHECK(ZBarcode_Buffer(zint, opts.rotate())); | |
| 445 | |
| 446 #ifdef PRINT_DEBUG | |
| 447 printf("write symbol with size: %dx%d\n", zint->bitmap_width, zint->bitmap_height); | |
| 448 #endif | |
| 449 auto iv = Image(zint->bitmap_width, zint->bitmap_height); | |
| 450 auto* src = zint->bitmap; | |
| 451 auto* dst = const_cast<uint8_t*>(iv.data()); | |
| 452 for(int y = 0; y < iv.height(); ++y) | |
| 453 for(int x = 0, w = iv.width(); x < w; ++x, src += 3) | |
| 454 *dst++ = RGBToLum(src[0], src[1], src[2]); | |
| 455 | |
| 456 return iv; | |
| 457 #else | |
| 458 return {}; // unreachable code | |
| 459 #endif | |
| 460 } | |
| 461 | |
| 462 std::string WriteBarcodeToUtf8(const Barcode& barcode, [[maybe_unused]] const WriterOptions& options) | |
| 463 { | |
| 464 auto iv = barcode.symbol(); | |
| 465 if (!iv.data()) | |
| 466 return {}; | |
| 467 | |
| 468 constexpr auto map = std::array{" ", "▀", "▄", "█"}; | |
| 469 std::ostringstream res; | |
| 470 bool inverted = false; // TODO: take from WriterOptions | |
| 471 | |
| 472 for (int y = 0; y < iv.height(); y += 2) { | |
| 473 for (int x = 0; x < iv.width(); ++x) { | |
| 474 int tp = bool(*iv.data(x, y)) ^ inverted; | |
| 475 int bt = (iv.height() == 1 && tp) || (y + 1 < iv.height() && (bool(*iv.data(x, y + 1)) ^ inverted)); | |
| 476 res << map[tp | (bt << 1)]; | |
| 477 } | |
| 478 res << '\n'; | |
| 479 } | |
| 480 | |
| 481 return res.str(); | |
| 482 } | |
| 483 | |
| 484 } // namespace ZXing | |
| 485 | |
| 486 #endif // ZXING_EXPERIMENTAL_API |
