python-barcode icon indicating copy to clipboard operation
python-barcode copied to clipboard

GS1 always starts with Character Set B

Open noperator-zz opened this issue 4 years ago • 7 comments

Some codes can be encoded entirely with code C, but Code128() initializes self._charset = "B" unconditionally. Also, due to the (non-numeric) FNC 1 character at the start of a GS1 barcode, the library will always start with character set B anyway, even if self._charset was set to "C". https://github.com/WhyNotHugo/python-barcode/blob/83a0b4e87755f8dcb22c9cf35c52f6f3ae7a6993/barcode/codex.py#L175

The effect is that a switch to Code C is added after FNC 1, when it could have just started with character set C instead.

Expected (ignore the slash): START C -> FNC 1 -> 12 -> 00 -> 13 -> 00 -> 85 image

Actual: START B -> FNC 1 -> CODE C -> 12 -> 00 -> 13 -> 00 -> 85 gs128

import barcode
from barcode.writer import ImageWriter
sn = 1200130085
# START B -> FNC 1 -> CODE C -> barcode (code C)
code = barcode.get("gs1_128", str(sn), writer=ImageWriter())
code.save("gs128")

noperator-zz avatar Jun 23 '21 22:06 noperator-zz

Similar issue with Code128, it starts with charset B so it will never switch to charset A as A is a subset of B (for alphanumeric barcodes, at least).

I think there are some characters in charset A which are not included in charset B, so I think we will just need something a bit more sophisticated (both for GS1 and Code128) than just starting in one charset and changing if that does not support.

I sort of think we should just have these exposed via the constructor, with automatic resolution used only if not explicitly specified there.

audoh-tickitto avatar Jul 06 '21 10:07 audoh-tickitto

Yup, makes sense. The "next charset" should be evaluated at the rather than hardcoded.

WhyNotHugo avatar Jul 16 '21 12:07 WhyNotHugo

@WhyNotHugo Any timeline for a fix on this? I'm happy to submit a PR.

lhopkins avatar Jul 27 '22 00:07 lhopkins

PRs welcome

WhyNotHugo avatar Jul 28 '22 08:07 WhyNotHugo

any updates for this bug ?

QW-Is-Here avatar Oct 18 '22 07:10 QW-Is-Here

I recently tried to implement code to generate SSCC barcodes using this library, and since you can stay in char set C (since SSCC only contains numbers) i tried it by making the following class, which is a modification of the Code128 class with minimal changes to the existing code. This is neither a real solution (just a workaround for my case), nor clean (as you can probably remove most if not all of the contents of the method '_maybe_switch_charset'), but as far as I checked it seemed to generate the barcodes i want. Feel free to confirm if this class behaves properly for SSCC codes in case it is useful to you.

class Gs1_128_SSCC(barcode.codex.Code128): # ...\Lib\site-packages\barcode\codex.py """ Code128 SSCC implementation. - 28/09/2022 Ken Tanaka """

name = "GS1-128-SSCC"

FNC1_CHAR = "\xf1"

def __init__(self, code, writer = None):
	code = self.FNC1_CHAR + code
	super().__init__(code, writer)
	#######################MODIFIED#######################
	self._charset = "C"
	#######################MODIFIED#######################

def get_fullcode(self):
	return super().get_fullcode()[1: ]

def _maybe_switch_charset(self, pos):
	char = self.code[pos]
	next_ = self.code[pos: pos + 10]

	def look_next():
		digits = 0
		for c in next_:
			if c.isdigit():
				digits += 1
			else:
				break
		return digits > 3

	codes = []
	#######################MODIFIED#######################
	if self._charset == "C" and char == self.FNC1_CHAR:
		pass
	elif self._charset == "C" and not char.isdigit():
	#######################MODIFIED#######################
		if char in barcode.charsets.code128.B:
			codes = self._new_charset("B")
		elif char in barcode.charsets.code128.A:
			codes = self._new_charset("A")
		if len(self._buffer) == 1:
			codes.append(self._convert(self._buffer[0]))
			self._buffer = ""
	elif self._charset == "B":
		if look_next():
			codes = self._new_charset("C")
		elif char not in barcode.charsets.code128.B:
			if char in barcode.charsets.code128.A:
				codes = self._new_charset("A")
	elif self._charset == "A":
		if look_next():
			codes = self._new_charset("C")
		elif char not in barcode.charsets.code128.A:
			if char in barcode.charsets.code128.B:
				codes = self._new_charset("B")
	return codes

Kendlings avatar Oct 19 '22 15:10 Kendlings