or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated

docs

index.md
tile.json

tessl/github-zxing-cpp--zxing-cpp

tessl install tessl/github-zxing-cpp--zxing-cpp@2.3.0

Open-source, multi-format linear/matrix barcode image processing library implemented in C++

gtin.mddocs/reference/

GTIN Utilities

The ZXing::GTIN namespace provides utilities for working with Global Trade Item Numbers (GTIN) and GS1 standards. These functions are useful for processing retail barcodes like UPC and EAN.

Namespace

All GTIN utilities are in the ZXing::GTIN namespace:

namespace ZXing::GTIN {
    // Check digit computation
    template <typename T>
    T ComputeCheckDigit(const std::basic_string<T>& digits,
                        bool skipTail = false);

    // Check digit validation
    template <typename T>
    bool IsCheckDigitValid(const std::basic_string<T>& s);

    // Country/origin lookup
    std::string LookupCountryIdentifier(const std::string& GTIN,
                                        const BarcodeFormat format = BarcodeFormat::None);

    // EAN add-on support
    std::string EanAddOn(const Barcode& barcode);
    std::string IssueNr(const std::string& ean2AddOn);
    std::string Price(const std::string& ean5AddOn);
}

Check Digit Computation

Computing Check Digits

GTIN check digits use modulo-10 algorithm:

#include "ZXing/GTIN.h"

// Compute check digit for EAN-13 (12 digits + check)
std::string ean12 = "400638133393";
char checkDigit = ZXing::GTIN::ComputeCheckDigit(ean12);
std::cout << "Check digit: " << checkDigit << "\n";  // "1"

std::string fullEan13 = ean12 + checkDigit;
std::cout << "Full EAN-13: " << fullEan13 << "\n";  // "4006381333931"

Template Support

Works with different string types:

// char strings
std::string digits = "12345678901";
char check = ZXing::GTIN::ComputeCheckDigit(digits);

// Wide character strings
std::wstring wdigits = L"12345678901";
wchar_t wcheck = ZXing::GTIN::ComputeCheckDigit(wdigits);

Skip Tail Option

When computing for partial numbers:

// Skip last digit during computation (useful for in-place calculation)
std::string partialEan = "40063813339X";
char check = ZXing::GTIN::ComputeCheckDigit(partialEan, true);

Check Digit Validation

Validating GTIN Numbers

#include "ZXing/GTIN.h"

// Validate EAN-13
std::string ean13 = "4006381333931";
if (ZXing::GTIN::IsCheckDigitValid(ean13)) {
    std::cout << "Valid EAN-13\n";
} else {
    std::cout << "Invalid check digit\n";
}

// Validate UPC-A
std::string upca = "012345678905";
if (ZXing::GTIN::IsCheckDigitValid(upca)) {
    std::cout << "Valid UPC-A\n";
}

Validating from Barcode

auto barcode = ZXing::ReadBarcode(image);

if (barcode.format() == ZXing::BarcodeFormat::EAN13) {
    std::string code = barcode.text();

    if (ZXing::GTIN::IsCheckDigitValid(code)) {
        std::cout << "Valid GTIN\n";
    } else {
        std::cerr << "Check digit validation failed\n";
        // May indicate scanning error or damaged barcode
    }
}

Country Identification

Looking Up Country of Origin

#include "ZXing/GTIN.h"

auto barcode = ZXing::ReadBarcode(image);

if (barcode.isValid()) {
    std::string country = ZXing::GTIN::LookupCountryIdentifier(
        barcode.text(), barcode.format());

    if (!country.empty()) {
        std::cout << "Country/Origin: " << country << "\n";
    } else {
        std::cout << "Country unknown or not applicable\n";
    }
}

Country Prefix Examples

Common GS1 prefixes:

// "000" - "019" : USA and Canada
// "020" - "029" : Restricted distribution (coupons, etc.)
// "030" - "039" : USA
// "040" - "049" : Restricted distribution
// "050" - "059" : Coupons
// "060" - "099" : USA and Canada
// "100" - "139" : USA
// "200" - "299" : Restricted distribution
// "300" - "379" : France and Monaco
// "380"         : Bulgaria
// "383"         : Slovenia
// "385"         : Croatia
// "400" - "440" : Germany
// "450" - "459" : Japan
// "460" - "469" : Russia
// "470"         : Kyrgyzstan
// "471"         : Taiwan
// "474"         : Estonia
// "475"         : Latvia
// "476"         : Azerbaijan
// "477"         : Lithuania
// "478"         : Uzbekistan
// "479"         : Sri Lanka
// "480"         : Philippines
// "481"         : Belarus
// "482"         : Ukraine
// "484"         : Moldova
// "485"         : Armenia
// "486"         : Georgia
// "487"         : Kazakhstan
// "488"         : Tajikistan
// "489"         : Hong Kong
// "490" - "499" : Japan
// "500" - "509" : UK
// "520" - "521" : Greece
// "528"         : Lebanon
// "529"         : Cyprus
// "530"         : Albania
// "531"         : Macedonia
// "535"         : Malta
// "539"         : Ireland
// "540" - "549" : Belgium and Luxembourg
// "560"         : Portugal
// "569"         : Iceland
// "570" - "579" : Denmark
// "590"         : Poland
// "594"         : Romania
// "599"         : Hungary
// "600" - "601" : South Africa
// "603"         : Ghana
// "604"         : Senegal
// "608"         : Bahrain
// "609"         : Mauritius
// "611"         : Morocco
// "613"         : Algeria
// "615"         : Nigeria
// "616"         : Kenya
// "618"         : Ivory Coast
// "619"         : Tunisia
// "620"         : Tanzania
// "621"         : Syria
// "622"         : Egypt
// "623"         : Brunei
// "624"         : Libya
// "625"         : Jordan
// "626"         : Iran
// "627"         : Kuwait
// "628"         : Saudi Arabia
// "629"         : United Arab Emirates
// "640" - "649" : Finland
// "690" - "699" : China
// "700" - "709" : Norway
// "729"         : Israel
// "730" - "739" : Sweden
// "740"         : Guatemala
// "741"         : El Salvador
// "742"         : Honduras
// "743"         : Nicaragua
// "744"         : Costa Rica
// "745"         : Panama
// "746"         : Dominican Republic
// "750"         : Mexico
// "754" - "755" : Canada
// "759"         : Venezuela
// "760" - "769" : Switzerland
// "770" - "771" : Colombia
// "773"         : Uruguay
// "775"         : Peru
// "777"         : Bolivia
// "778" - "779" : Argentina
// "780"         : Chile
// "784"         : Paraguay
// "786"         : Ecuador
// "789" - "790" : Brazil
// "800" - "839" : Italy
// "840" - "849" : Spain
// "850"         : Cuba
// "858"         : Slovakia
// "859"         : Czech Republic
// "860"         : Serbia
// "865"         : Mongolia
// "867"         : North Korea
// "868" - "869" : Turkey
// "870" - "879" : Netherlands
// "880"         : South Korea
// "884"         : Cambodia
// "885"         : Thailand
// "888"         : Singapore
// "890"         : India
// "893"         : Vietnam
// "896"         : Pakistan
// "899"         : Indonesia
// "900" - "919" : Austria
// "930" - "939" : Australia
// "940" - "949" : New Zealand
// "955"         : Malaysia
// "958"         : Macau
// "977"         : ISSN (Serial publications)
// "978" - "979" : ISBN (Books)
// "980"         : Refund receipts
// "981" - "984" : Common Currency Coupons
// "990" - "999" : Coupons

std::string code = "4006381333931";  // Starts with "400"
std::string country = ZXing::GTIN::LookupCountryIdentifier(code);
// Returns: "Germany"

Format-Specific Lookup

// Without format (auto-detect)
std::string country1 = ZXing::GTIN::LookupCountryIdentifier("4006381333931");

// With explicit format
std::string country2 = ZXing::GTIN::LookupCountryIdentifier(
    "4006381333931", ZXing::BarcodeFormat::EAN13);

EAN Add-On Symbols

Extracting Add-On

EAN-13 and EAN-8 can have 2-digit or 5-digit add-on symbols:

#include "ZXing/GTIN.h"

auto barcode = ZXing::ReadBarcode(image);

if (barcode.format() == ZXing::BarcodeFormat::EAN13 ||
    barcode.format() == ZXing::BarcodeFormat::EAN8) {

    std::string addOn = ZXing::GTIN::EanAddOn(barcode);

    if (!addOn.empty()) {
        std::cout << "Add-on: " << addOn << "\n";

        if (addOn.length() == 2) {
            std::cout << "EAN-2 add-on (magazine issue)\n";
        } else if (addOn.length() == 5) {
            std::cout << "EAN-5 add-on (book price)\n";
        }
    } else {
        std::cout << "No add-on present\n";
    }
}

Detecting Add-On in ReaderOptions

// Configure reader to look for add-ons
auto options = ZXing::ReaderOptions()
    .setFormats(ZXing::BarcodeFormat::EAN13)
    .setEanAddOnSymbol(ZXing::EanAddOnSymbol::Read);

auto barcode = ZXing::ReadBarcode(image, options);

std::string addOn = ZXing::GTIN::EanAddOn(barcode);

Magazine Issue Numbers (EAN-2)

Extracting Issue Number

EAN-2 add-ons encode magazine issue numbers:

#include "ZXing/GTIN.h"

auto barcode = ZXing::ReadBarcode(image);
std::string addOn = ZXing::GTIN::EanAddOn(barcode);

if (addOn.length() == 2) {
    std::string issue = ZXing::GTIN::IssueNr(addOn);
    std::cout << "Magazine issue: " << issue << "\n";
}

Issue Number Format

// EAN-2 values represent issue numbers
// "01" = Issue 1
// "52" = Issue 52 (weekly publication)
// "12" = Issue 12 (monthly publication)

std::string issue = ZXing::GTIN::IssueNr("06");
// Returns: "6"

Book Prices (EAN-5)

Extracting Price

EAN-5 add-ons encode book prices:

#include "ZXing/GTIN.h"

auto barcode = ZXing::ReadBarcode(image);
std::string addOn = ZXing::GTIN::EanAddOn(barcode);

if (addOn.length() == 5) {
    std::string price = ZXing::GTIN::Price(addOn);
    if (!price.empty()) {
        std::cout << "Price: " << price << "\n";
    }
}

Price Format

EAN-5 encoding:

  • First digit: currency code
  • Remaining 4 digits: price
// "51299" = $12.99 USD
// "51995" = $19.95 USD
// "50000" = Free or no price
// "59999" = $99.99 USD (max)

std::string price1 = ZXing::GTIN::Price("51299");
// Returns: "$12.99" or "12.99" depending on implementation

std::string price2 = ZXing::GTIN::Price("50000");
// Returns: "" (no price)

Currency Codes

// First digit of EAN-5 indicates currency:
// 0 = Pound Sterling (£)
// 1 = (Not used)
// 2 = (Not used)
// 3 = Australian Dollar (A$)
// 4 = New Zealand Dollar (NZ$)
// 5 = US Dollar ($)
// 6 = Canadian Dollar (C$)
// 7 = (Not used)
// 8 = (Not used)
// 9 = (Reserved)

GTIN Formats

Supported Formats

// GTIN-8  (EAN-8)   : 8 digits
// GTIN-12 (UPC-A)   : 12 digits
// GTIN-13 (EAN-13)  : 13 digits
// GTIN-14 (ITF-14)  : 14 digits (shipping containers)

bool isGtinFormat(ZXing::BarcodeFormat format) {
    return format == ZXing::BarcodeFormat::EAN8 ||
           format == ZXing::BarcodeFormat::EAN13 ||
           format == ZXing::BarcodeFormat::UPCA ||
           format == ZXing::BarcodeFormat::UPCE ||
           format == ZXing::BarcodeFormat::ITF;
}

UPC-E Expansion

UPC-E is a compressed form of UPC-A:

// UPC-E: 6 digits (plus check digit)
// UPC-A: 12 digits

// ZXing automatically expands UPC-E to UPC-A format
auto barcode = ZXing::ReadBarcode(image);

if (barcode.format() == ZXing::BarcodeFormat::UPCE) {
    std::string expanded = barcode.text();
    // Returns expanded 12-digit UPC-A
    std::cout << "Expanded: " << expanded << "\n";
}

GS1 Application Identifiers

For DataBar and other GS1 formats:

if (barcode.contentType() == ZXing::ContentType::GS1) {
    std::cout << "GS1-formatted content\n";

    // Content uses GS1 Application Identifiers
    std::string gs1Data = barcode.text();

    // Parse GS1 AIs (application-specific parsing)
    // Common AIs:
    // (01) = GTIN
    // (10) = Batch/Lot number
    // (17) = Expiration date
    // (21) = Serial number
    // etc.
}

Complete Example

#include "ZXing/ReadBarcode.h"
#include "ZXing/GTIN.h"

void processRetailBarcode(const ZXing::ImageView& image) {
    auto options = ZXing::ReaderOptions()
        .setFormats(ZXing::BarcodeFormat::EAN13 |
                    ZXing::BarcodeFormat::EAN8 |
                    ZXing::BarcodeFormat::UPCA |
                    ZXing::BarcodeFormat::UPCE)
        .setEanAddOnSymbol(ZXing::EanAddOnSymbol::Read);

    auto barcode = ZXing::ReadBarcode(image, options);

    if (!barcode.isValid()) {
        std::cerr << "No barcode found\n";
        return;
    }

    // Get code
    std::string code = barcode.text();
    std::cout << "Code: " << code << "\n";

    // Validate check digit
    if (!ZXing::GTIN::IsCheckDigitValid(code)) {
        std::cerr << "Warning: Invalid check digit\n";
    }

    // Get country
    std::string country = ZXing::GTIN::LookupCountryIdentifier(
        code, barcode.format());
    if (!country.empty()) {
        std::cout << "Origin: " << country << "\n";
    }

    // Check for add-on
    std::string addOn = ZXing::GTIN::EanAddOn(barcode);
    if (!addOn.empty()) {
        std::cout << "Add-on: " << addOn << "\n";

        if (addOn.length() == 2) {
            std::cout << "Issue: " << ZXing::GTIN::IssueNr(addOn) << "\n";
        } else if (addOn.length() == 5) {
            std::string price = ZXing::GTIN::Price(addOn);
            if (!price.empty()) {
                std::cout << "Price: " << price << "\n";
            }
        }
    }
}

Best Practices

Always Validate Check Digits

// For critical applications, always validate
if (!ZXing::GTIN::IsCheckDigitValid(code)) {
    // Reject or flag for manual review
    logError("Invalid GTIN check digit");
}

Handle Missing Country Data

// Not all GTIN ranges have country assignments
std::string country = ZXing::GTIN::LookupCountryIdentifier(code);
if (country.empty()) {
    // May be restricted distribution, coupon, or other special code
    std::cout << "No country assignment\n";
}

Add-On is Optional

// Don't require add-on unless specifically needed
std::string addOn = ZXing::GTIN::EanAddOn(barcode);
if (addOn.empty()) {
    // Most products don't have add-ons - this is normal
}

Related

  • Barcode Formats - GTIN-related formats (EAN, UPC)
  • Barcode Results - Accessing barcode content
  • Reader Options - Configuring add-on detection
  • Barcode Reading - Reading retail barcodes