=====
GS123
=====


.. image:: https://gitlab.com/serial-lab/gs123/badges/master/pipeline.svg
        :target: https://gitlab.com/serial-lab/gs123/commits/master

.. image:: https://gitlab.com/serial-lab/gs123/badges/master/coverage.svg
        :target: https://gitlab.com/serial-lab/gs123/pipelines

.. image:: https://badge.fury.io/py/gs123.svg
    :target: https://badge.fury.io/py/gs123



Set of python tools to convert various GS1 formats to and from others.
GS123 is an essential component of the QU4RTET Open Source EPCIS and is
used in various tasks throughout the platform.  GS123 can also be used
as a standalone component to convert barcode data to URNs, etc.

Documentation
-------------

Find the latest docs here:

https://serial-lab.gitlab.io/gs123/

Features
--------

* Converts GS1 barcode values to EPC URN values.
* Check digit calculation.
* Converts URN values to barcode values.
* Regular expressions to select barcode values in files.
* File conversion utilities.
* **GS1 Data Matrix barcode generation** (SVG and PNG output).

Installation
------------

.. code-block:: bash

    pip install gs123

For Data Matrix PNG output, also install Pillow:

.. code-block:: bash

    pip install gs123 Pillow

Quick Start
-----------

Barcode to URN Conversion
~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

    from gs123.conversion import BarcodeConverter

    # Parse a GS1 barcode (GTIN + Serial + Expiry + Lot)
    bc = BarcodeConverter(
        "(01)20614141073461(21)0000010020(17)261231(10)LOTA1",
        company_prefix_length=7,
    )

    print(bc.epc_urn)          # urn:epc:id:sgtin:0614141.207346.10020
    print(bc.gtin14)           # 20614141073461
    print(bc.serial_number)    # 10020
    print(bc.lot)              # LOTA1
    print(bc.expiration_date)  # 261231

URN to Barcode Conversion
~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

    from gs123.conversion import URNConverter

    converter = URNConverter("urn:epc:id:sgtin:0614141.207346.10020")

    # Get a barcode string with lot and expiry
    barcode = converter.get_barcode_value(
        lot="LOTA1",
        expiration="261231",
        parenthesis=True,
    )
    print(barcode)  # (01)20614141073461(21)10020(17)261231(10)LOTA1

Data Matrix Barcode Generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Generate GS1 Data Matrix barcodes for pharmaceutical serialization,
shipping labels, and traceability.  Uses the `ppf.datamatrix
<https://github.com/adrianschlatter/ppf.datamatrix>`_ library (MIT license)
for pure-Python encoding — no native libraries or Ghostscript required.

**From a GS1 element string:**

.. code-block:: python

    from gs123.datamatrix import GS1DataMatrix

    dm = GS1DataMatrix("(01)20614141073461(21)0000010020(17)261231(10)LOTA1")

    # Save as SVG (vector — crisp at any size, no extra deps)
    dm.save_svg("barcode.svg", scale=10)

    # Save as PNG (requires Pillow)
    dm.save_png("barcode.png", scale=10)

    # Get raw bytes for embedding in web pages, PDFs, etc.
    svg_str = dm.svg()
    png_bytes = dm.png()

**From an EPC URN:**

.. code-block:: python

    from gs123.datamatrix import GS1DataMatrix

    dm = GS1DataMatrix.from_urn(
        "urn:epc:id:sgtin:0614141.207346.10020",
        company_prefix_length=7,
        lot="LOTA1",
        expiration="261231",
    )
    dm.save_png("from_urn.png", scale=12)

**From a scanned barcode (round-trip):**

.. code-block:: python

    from gs123.datamatrix import GS1DataMatrix

    # Parse a scanned barcode and regenerate a clean Data Matrix
    dm = GS1DataMatrix.from_barcode(
        "(01)20614141073461(21)0000010020(17)261231(10)LOTA1",
        company_prefix_length=7,
    )
    dm.save_svg("regenerated.svg")

    # Override the lot for a repack scenario
    dm = GS1DataMatrix.from_barcode(
        "(01)20614141073461(21)0000010020(17)261231(10)LOTA1",
        company_prefix_length=7,
        lot="NEWLOT99",
    )

**SSCC-18 (shipping containers):**

.. code-block:: python

    from gs123.datamatrix import GS1DataMatrix

    dm = GS1DataMatrix.from_urn(
        "urn:epc:id:sscc:0614141.1234567890",
        company_prefix_length=7,
    )
    dm.save_png("sscc_label.png", scale=10)

**Batch generation:**

.. code-block:: python

    from gs123.datamatrix import GS1DataMatrix

    for serial in range(10001, 10021):
        urn = f"urn:epc:id:sgtin:0614141.207346.{serial}"
        dm = GS1DataMatrix.from_urn(
            urn,
            company_prefix_length=7,
            lot="BATCH2026A",
            expiration="271231",
        )
        dm.save_png(f"label_{serial}.png", scale=10)

**Inspect the module matrix:**

.. code-block:: python

    from gs123.datamatrix import GS1DataMatrix

    dm = GS1DataMatrix("(01)20614141073461(21)0000010020")
    rows, cols = dm.symbol_size  # (22, 22)
    matrix = dm.matrix           # list of lists, 1=dark 0=light

    # ASCII art
    for row in matrix:
        print("".join("██" if v else "  " for v in row))

Jupyter Notebook
----------------

A complete interactive demo is available at
``notebooks/datamatrix_demo.ipynb``.  It covers all of the above examples
with inline SVG and PNG rendering.

.. code-block:: bash

    pip install gs123 Pillow jupyter
    jupyter notebook notebooks/datamatrix_demo.ipynb

Dependencies
------------

* **Click** — CLI support
* **ppf.datamatrix** — Pure-Python Data Matrix encoder (`MIT license
  <https://github.com/adrianschlatter/ppf.datamatrix/blob/master/LICENSE>`_)
* **Pillow** *(optional)* — Required only for PNG output

License
-------

GNU General Public License v3 (GPLv3)
