123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- try:
- from pylibdmtx import pylibdmtx
- except ImportError:
- pylibdmtx = None
- __all__ = ()
- else:
- __all__=('DataMatrix',)
- from reportlab.graphics.barcode.common import Barcode
- from reportlab.lib.utils import asBytes
- from reportlab.platypus.paraparser import _num as paraparser_num
- from reportlab.graphics.widgetbase import Widget
- from reportlab.lib.validators import isColor, isString, isColorOrNone, isNumber, isBoxAnchor
- from reportlab.lib.attrmap import AttrMap, AttrMapValue
- from reportlab.lib.colors import toColor
- from reportlab.graphics.shapes import Group, Rect
- def _numConv(x):
- return x if isinstance(x,(int,float)) else paraparser_num(x)
- class _DMTXCheck(object):
- @classmethod
- def pylibdmtx_check(cls):
- if not pylibdmtx:
- raise ValueError('The %s class requires package pylibdmtx' % cls.__name__)
- class DataMatrix(Barcode,_DMTXCheck):
- def __init__(self, value='', **kwds):
- self.pylibdmtx_check()
- self._recalc = True
- self.value = value
- self.cellSize = kwds.pop('cellSize','5x5')
- self.size = kwds.pop('size','SquareAuto')
- self.encoding = kwds.pop('encoding','Ascii')
- self.anchor = kwds.pop('anchor','sw')
- self.color = kwds.pop('color',(0,0,0))
- self.bgColor = kwds.pop('bgColor',None)
- self.x = kwds.pop('x',0)
- self.y = kwds.pop('y',0)
- self.border = kwds.pop('border',5)
- @property
- def value(self):
- return self._value
- @value.setter
- def value(self,v):
- self._value = asBytes(v)
- self._recalc = True
- @property
- def size(self):
- return self._size
- @size.setter
- def size(self,v):
- self._size = self._checkVal('size', v, pylibdmtx.ENCODING_SIZE_NAMES)
- self._recalc = True
- @property
- def border(self):
- return self._border
- @border.setter
- def border(self,v):
- self._border = _numConv(v)
- self._recalc = True
- @property
- def x(self):
- return self._x
- @x.setter
- def x(self,v):
- self._x = _numConv(v)
- self._recalc = True
- @property
- def y(self):
- return self._y
- @y.setter
- def y(self,v):
- self._y = _numConv(v)
- self._recalc = True
- @property
- def cellSize(self):
- return self._cellSize
- @size.setter
- def cellSize(self,v):
- self._cellSize = v
- self._recalc = True
- @property
- def encoding(self):
- return self._encoding
- @encoding.setter
- def encoding(self,v):
- self._encoding = self._checkVal('encoding', v, pylibdmtx.ENCODING_SCHEME_NAMES)
- self._recalc = True
- @property
- def anchor(self):
- return self._anchor
- @anchor.setter
- def anchor(self,v):
- self._anchor = self._checkVal('anchor', v, ('n','ne','e','se','s','sw','w','nw','c'))
- self._recalc = True
- def recalc(self):
- if not self._recalc: return
- data = self._value
- size = self._size
- encoding = self._encoding
- e = pylibdmtx.encode(data, size=size, scheme=encoding)
- iW = e.width
- iH = e.height
- p = e.pixels
- iCellSize = 5
- bpp = 3 #bytes per pixel
- rowLen = iW*bpp
- cellLen = iCellSize*bpp
- assert len(p)//rowLen == iH
- matrix = list(filter(None,
- (''.join(
- (('x' if p[j:j+bpp] != b'\xff\xff\xff' else ' ')
- for j in range(i,i+rowLen,cellLen))).strip()
- for i in range(0,iH*rowLen,rowLen*iCellSize))))
- self._nRows = len(matrix)
- self._nCols = len(matrix[-1])
- self._matrix = '\n'.join(matrix)
- cellWidth = self._cellSize
- if cellWidth:
- cellWidth = cellWidth.split('x')
- if len(cellWidth)>2:
- raise ValueError('cellSize needs to be distance x distance not %r' % self._cellSize)
- elif len(cellWidth)==2:
- cellWidth, cellHeight = cellWidth
- else:
- cellWidth = cellHeight = cellWidth[0]
- cellWidth = _numConv(cellWidth)
- cellHeight = _numConv(cellHeight)
- else:
- cellWidth = cellHeight = iCellSize
- self._cellWidth = cellWidth
- self._cellHeight = cellHeight
- self._recalc = False
- self._bord = max(self.border,cellWidth,cellHeight)
- self._width = cellWidth*self._nCols + 2*self._bord
- self._height = cellHeight*self._nRows + 2*self._bord
- @property
- def matrix(self):
- self.recalc()
- return self._matrix
- @property
- def width(self):
- self.recalc()
- return self._width
- @property
- def height(self):
- self.recalc()
- return self._height
- @property
- def cellWidth(self):
- self.recalc()
- return self._cellWidth
- @property
- def cellHeight(self):
- self.recalc()
- return self._cellHeight
- def draw(self):
- self.recalc()
- canv = self.canv
- w = self.width
- h = self.height
- x = self.x
- y = self.y
- b = self._bord
- anchor = self.anchor
- if anchor in ('nw','n','ne'):
- y -= h
- elif anchor in ('c','e','w'):
- y -= h//2
- if anchor in ('ne','e','se'):
- x -= w
- elif anchor in ('n','c','s'):
- x -= w//2
- canv.saveState()
- if self.bgColor:
- canv.setFillColor(toColor(self.bgColor))
- canv.rect(x, y-h, w, h, fill=1, stroke=0)
- canv.setFillColor(toColor(self.color))
- canv.setStrokeColor(None)
- cellWidth = self.cellWidth
- cellHeight = self.cellHeight
- yr = y - b - cellHeight
- x += b
- for row in self.matrix.split('\n'):
- xr = x
- for c in row:
- if c=='x':
- canv.rect(xr, yr, cellWidth, cellHeight, fill=1, stroke=0)
- xr += cellWidth
- yr -= cellHeight
- canv.restoreState()
-
- class DataMatrixWidget(Widget,_DMTXCheck):
- codeName = "DataMatrix"
- _attrMap = AttrMap(
- BASE = Widget,
- value = AttrMapValue(isString, desc='Datamatrix data'),
- x = AttrMapValue(isNumber, desc='x-coord'),
- y = AttrMapValue(isNumber, desc='y-coord'),
- color = AttrMapValue(isColor, desc='foreground color'),
- bgColor = AttrMapValue(isColorOrNone, desc='background color'),
- encoding = AttrMapValue(isString, desc='encoding'),
- size = AttrMapValue(isString, desc='size'),
- cellSize = AttrMapValue(isString, desc='cellSize'),
- anchor = AttrMapValue(isBoxAnchor, desc='anchor pooint for x,y'),
- )
- _defaults = dict(
- x = ('0',_numConv),
- y = ('0',_numConv),
- color = ('black',toColor),
- bgColor = (None,lambda _: toColor(_) if _ is not None else _),
- encoding = ('Ascii',None),
- size = ('SquareAuto',None),
- cellSize = ('5x5',None),
- anchor = ('sw', None),
- )
- def __init__(self,value='Hello Cruel World!', **kwds):
- self.pylibdmtx_check()
- self.value = value
- for k,(d,c) in self._defaults.items():
- v = kwds.pop(k,d)
- if c: v = c(v)
- setattr(self,k,v)
- def rect(self, x, y, w, h, fill=1, stroke=0):
- self._gadd(Rect(x,y,w,h,strokeColor=None,fillColor=self._fillColor))
- def saveState(self,*args,**kwds):
- pass
- restoreState = setStrokeColor = saveState
- def setFillColor(self,c):
- self._fillColor = c
- def draw(self):
- m = DataMatrix(value=self.value,**{k: getattr(self,k) for k in self._defaults})
- m.canv = self
- m.y += m.height
- g = Group()
- self._gadd = g.add
- m.draw()
- return g
|