Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmatic access to completed code bits? #11

Open
MrSurly opened this issue Feb 8, 2018 · 4 comments
Open

Programmatic access to completed code bits? #11

MrSurly opened this issue Feb 8, 2018 · 4 comments

Comments

@MrSurly
Copy link

MrSurly commented Feb 8, 2018

There's no easy programmatic way to get the barcode bits, in case you want to implement your own renderer (e.g. SVG). get_ascii() is clearly intended to be directly printed using a font that is approximately 2:1 height:width, since it returns two elements per column.

In the end I did something like this:

    e = DataMatrixEncoder(data)
    r = DataMatrixRenderer(e.matrix, e.regions)

    h = len(r.matrix)
    w = len(r.matrix[0])
    for y,line in enumerate(r.matrix):
        for x,bit in enumerate(line):
            pass
@mmulqueen
Copy link
Owner

@MrSurly I'd say the way you've done it is the way to go. It's essentially what DataMatrixRenderer.get_buffer() and DataMatrixRenderer.get_ascii() does.

If you want to submit a PR for a new interface, happy to look at it though.

@klausmcm
Copy link

klausmcm commented Mar 9, 2022

I have changed the Code128 code to this to make it easier to get a barcode of a given size (showing only code with most relevant changes). Dependencies are pint and numpy. Would there be interest in this?

class Code128:
    """Top-level class which handles the overall process of encoding input string and outputting the result."""

    def __init__(self, text, quiet_zone_width):
        """Constructor for a Code128 barcode.

        :param text: The text to be encoded.
        :type text: str
        :param quiet_zone_width: The width in modules for each quiet zone. The barcode has a leading and trailing quiet zone.
        :type quiet_zone_width: int
        """

        self._text = text
        encoder = TextEncoder()

        self._encoded_text = encoder.encode(
            self._text
        )  # 1 is a black bar and 0 is a white bar
        logging.debug("Encoded text is %s", self._encoded_text)

        self._checksum = self._calculate_checksum()
        logging.debug("Checksum is %d", self._checksum)

        self._bars = encoder.get_bars(self._encoded_text, self._checksum)
        self._bars = np.tile(
            np.array(
                [0] * quiet_zone_width + list(self._bars) + [0] * quiet_zone_width,
                dtype=np.uint8,
            ),
            (1, 1),
        )  # create a 2D array - width is the length of all the bars and height is 1
        logging.debug("Bars: %s", self._bars)

        self._resized_bars = np.array([[]])

    def _calculate_checksum(self):
        """Calculate the check sum of the encoded text.

        Checksum is based on the input text and the starting code, and a mod103 algorithm is used
        """

        checksum = self._encoded_text[0]

        for index, char in enumerate(self._encoded_text):
            if index > 0:
                checksum += index * char

        return checksum % 103

    def resize_barcode(self, width, height, dpi):
        """Scale the barcode to the given lengths.

        The dimensions of the resized barcode will always match exactly the given lengths.

        If rounding for the width occurs, the barcode will be padded with whitespace to match the exact given width.

        :param width: The desired width of the barcode.
        :type width: str or int
        :param height: The desired height of the barcode.
        :type height: str or int
        :param dpi: The dpi to apply to the barcode. Used for converting the lengths to pixels.
        :type dpi: tuple(int, int)
        """
        dpi_width, dpi_height = dpi
        width = utility.convert_to_pixels(width, dpi_width)
        height = utility.convert_to_pixels(height, dpi_height)
        width_multiplier = width // len(
            self._bars[0]
        )  # width multiplier must be an int else the proportions of the bars will not be maintained

        # calculate the required leading and trailing whitespace to exactly match the given width
        padding = width - (width_multiplier * len(self._bars[0]))
        padding_left = padding // 2
        padding_right = padding - padding_left

        resized_barcode = np.repeat(
            self._bars, width_multiplier, 1
        )  # stretch horizontally
        resized_barcode = np.concatenate(
            (
                np.array([[0 for _ in range(padding_left)]], dtype=np.uint8),
                resized_barcode,
                np.array([[0 for _ in range(padding_right)]], dtype=np.uint8),
            ),
            1,
        )  # add padding to the left and right
        resized_barcode = np.repeat(resized_barcode, height, 0)  # stretch vertically
        self._resized_bars = resized_barcode

    def get_barcode_array(self):
        return self._bars

    def get_resized_barcode_array(self):
        return self._resized_bars

@mmulqueen
Copy link
Owner

I don't plan to merge anything that adds numpy as a dependency, but your code may be useful to someone else so please leave it here for anyone who's interested or you can fork this project.

@klausmcm
Copy link

No problem, I may also give standard lists a try with list comprehensions which may perform well enough. This may also be interesting for resolving #15.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants