320 lines
11 KiB
Python
Executable File
320 lines
11 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from util import fprint
|
|
|
|
from PIL import Image
|
|
from PIL import ImageDraw
|
|
from PIL import ImageFont
|
|
#import cv2
|
|
import numpy as np
|
|
from util import find_data_file
|
|
import segno
|
|
import io
|
|
#import cairosvg
|
|
#import math
|
|
|
|
|
|
|
|
# Copied from http://en.wikipedia.org/wiki/Code_128
|
|
# Value Weights 128A 128B 128C
|
|
CODE128_CHART = """
|
|
0 212222 space space 00
|
|
1 222122 ! ! 01
|
|
2 222221 " " 02
|
|
3 121223 # # 03
|
|
4 121322 $ $ 04
|
|
5 131222 % % 05
|
|
6 122213 & & 06
|
|
7 122312 ' ' 07
|
|
8 132212 ( ( 08
|
|
9 221213 ) ) 09
|
|
10 221312 * * 10
|
|
11 231212 + + 11
|
|
12 112232 , , 12
|
|
13 122132 - - 13
|
|
14 122231 . . 14
|
|
15 113222 / / 15
|
|
16 123122 0 0 16
|
|
17 123221 1 1 17
|
|
18 223211 2 2 18
|
|
19 221132 3 3 19
|
|
20 221231 4 4 20
|
|
21 213212 5 5 21
|
|
22 223112 6 6 22
|
|
23 312131 7 7 23
|
|
24 311222 8 8 24
|
|
25 321122 9 9 25
|
|
26 321221 : : 26
|
|
27 312212 ; ; 27
|
|
28 322112 < < 28
|
|
29 322211 = = 29
|
|
30 212123 > > 30
|
|
31 212321 ? ? 31
|
|
32 232121 @ @ 32
|
|
33 111323 A A 33
|
|
34 131123 B B 34
|
|
35 131321 C C 35
|
|
36 112313 D D 36
|
|
37 132113 E E 37
|
|
38 132311 F F 38
|
|
39 211313 G G 39
|
|
40 231113 H H 40
|
|
41 231311 I I 41
|
|
42 112133 J J 42
|
|
43 112331 K K 43
|
|
44 132131 L L 44
|
|
45 113123 M M 45
|
|
46 113321 N N 46
|
|
47 133121 O O 47
|
|
48 313121 P P 48
|
|
49 211331 Q Q 49
|
|
50 231131 R R 50
|
|
51 213113 S S 51
|
|
52 213311 T T 52
|
|
53 213131 U U 53
|
|
54 311123 V V 54
|
|
55 311321 W W 55
|
|
56 331121 X X 56
|
|
57 312113 Y Y 57
|
|
58 312311 Z Z 58
|
|
59 332111 [ [ 59
|
|
60 314111 \ \ 60
|
|
61 221411 ] ] 61
|
|
62 431111 ^ ^ 62
|
|
63 111224 _ _ 63
|
|
64 111422 NUL ` 64
|
|
65 121124 SOH a 65
|
|
66 121421 STX b 66
|
|
67 141122 ETX c 67
|
|
68 141221 EOT d 68
|
|
69 112214 ENQ e 69
|
|
70 112412 ACK f 70
|
|
71 122114 BEL g 71
|
|
72 122411 BS h 72
|
|
73 142112 HT i 73
|
|
74 142211 LF j 74
|
|
75 241211 VT k 75
|
|
76 221114 FF l 76
|
|
77 413111 CR m 77
|
|
78 241112 SO n 78
|
|
79 134111 SI o 79
|
|
80 111242 DLE p 80
|
|
81 121142 DC1 q 81
|
|
82 121241 DC2 r 82
|
|
83 114212 DC3 s 83
|
|
84 124112 DC4 t 84
|
|
85 124211 NAK u 85
|
|
86 411212 SYN v 86
|
|
87 421112 ETB w 87
|
|
88 421211 CAN x 88
|
|
89 212141 EM y 89
|
|
90 214121 SUB z 90
|
|
91 412121 ESC { 91
|
|
92 111143 FS | 92
|
|
93 111341 GS } 93
|
|
94 131141 RS ~ 94
|
|
95 114113 US DEL 95
|
|
96 114311 FNC3 FNC3 96
|
|
97 411113 FNC2 FNC2 97
|
|
98 411311 ShiftB ShiftA 98
|
|
99 113141 CodeC CodeC 99
|
|
100 114131 CodeB FNC4 CodeB
|
|
101 311141 FNC4 CodeA CodeA
|
|
102 411131 FNC1 FNC1 FNC1
|
|
103 211412 StartA StartA StartA
|
|
104 211214 StartB StartB StartB
|
|
105 211232 StartC StartC StartC
|
|
106 2331112 Stop Stop Stop
|
|
""".split()
|
|
|
|
VALUES = [int(value) for value in CODE128_CHART[0::5]]
|
|
WEIGHTS = dict(zip(VALUES, CODE128_CHART[1::5]))
|
|
CODE128A = dict(zip(CODE128_CHART[2::5], VALUES))
|
|
CODE128B = dict(zip(CODE128_CHART[3::5], VALUES))
|
|
CODE128C = dict(zip(CODE128_CHART[4::5], VALUES))
|
|
|
|
for charset in (CODE128A, CODE128B):
|
|
charset[' '] = charset.pop('space')
|
|
|
|
|
|
|
|
def generate_code(data, show=False, check=False):
|
|
|
|
#img = code128_image(data)
|
|
img = qr_image(data)
|
|
if show:
|
|
img.show()
|
|
#img.show()
|
|
#print(data)
|
|
|
|
if(check):
|
|
from pyzbar.pyzbar import decode
|
|
from pyzbar.pyzbar import ZBarSymbol
|
|
print(decode(img, symbols=[ZBarSymbol.CODE128])[0].data.decode('ascii'))
|
|
|
|
#if(decode(img, symbols=[ZBarSymbol.CODE128])[0].data.decode('ascii') == data):
|
|
# return True
|
|
#else:
|
|
# return False
|
|
return img
|
|
|
|
def code128_format(data):
|
|
"""
|
|
Generate an optimal barcode from ASCII text
|
|
"""
|
|
text = str(data)
|
|
pos = 0
|
|
length = len(text)
|
|
|
|
# Start Code
|
|
if text[:2].isdigit():
|
|
charset = CODE128C
|
|
codes = [charset['StartC']]
|
|
else:
|
|
charset = CODE128B
|
|
codes = [charset['StartB']]
|
|
|
|
# Data
|
|
while pos < length:
|
|
if charset is CODE128C:
|
|
if text[pos:pos+2].isdigit() and length - pos > 1:
|
|
# Encode Code C two characters at a time
|
|
codes.append(int(text[pos:pos+2]))
|
|
pos += 2
|
|
else:
|
|
# Switch to Code B
|
|
codes.append(charset['CodeB'])
|
|
charset = CODE128B
|
|
elif text[pos:pos+4].isdigit() and length - pos >= 4:
|
|
# Switch to Code C
|
|
codes.append(charset['CodeC'])
|
|
charset = CODE128C
|
|
else:
|
|
# Encode Code B one character at a time
|
|
codes.append(charset[text[pos]])
|
|
pos += 1
|
|
|
|
# Checksum
|
|
checksum = 0
|
|
for weight, code in enumerate(codes):
|
|
checksum += max(weight, 1) * code
|
|
codes.append(checksum % 103)
|
|
|
|
# Stop Code
|
|
codes.append(charset['Stop'])
|
|
return codes
|
|
|
|
def code128_image(data, height=100, thickness=3, quiet_zone=False):
|
|
partnum = data
|
|
if not data[-1] == CODE128B['Stop']:
|
|
data = code128_format(data)
|
|
|
|
|
|
barcode_widths = []
|
|
for code in data:
|
|
for weight in WEIGHTS[code]:
|
|
barcode_widths.append(int(weight) * thickness)
|
|
width = sum(barcode_widths)
|
|
x = 0
|
|
|
|
|
|
if quiet_zone:
|
|
width += 20 * thickness
|
|
x = 10 * thickness
|
|
|
|
# Monochrome Image
|
|
img = Image.new('RGB', (int(width * 10), int(width * 10)), 'white')
|
|
draw = ImageDraw.Draw(img)
|
|
draw_bar = True
|
|
for bwidth in barcode_widths:
|
|
bwidth *= 4
|
|
if draw_bar:
|
|
draw.rectangle(((x + int(width * 3), width*6.25), (x + int(width * 3) + bwidth - 1, width*7)), fill='black')
|
|
draw_bar = not draw_bar
|
|
x += bwidth
|
|
|
|
#draw.arc(((width - width/5, width - width/5), (width*9 + width/5, width*9 + width/5)),0,360,fill='blue', width = int(width/8))
|
|
draw.arc(((width+int(width / 1.4), width+int(width / 1.4)), (width*9-int(width / 1.4), width*9-int(width / 1.4))),0,360,fill='blue', width = int(width/8))
|
|
font_path = find_data_file("OCRAEXT.TTF")
|
|
font_size = width/2
|
|
font = ImageFont.truetype(font_path, font_size)
|
|
text_width = font.getlength(partnum)
|
|
while text_width > width*4:
|
|
font_size -= 1
|
|
font = ImageFont.truetype(font_path, font_size)
|
|
text_width = font.getlength(partnum)
|
|
|
|
txtx = (int(width * 10) - text_width) / 2
|
|
txty = (int(width * 10)) / 2 + width / 2
|
|
|
|
draw.text((txtx,txty),partnum, "black", font)
|
|
return img
|
|
|
|
def qr_image(data, width=600):
|
|
partnum = data
|
|
|
|
|
|
|
|
# Monochrome Image
|
|
img = Image.new('RGB', (int(width * 10), int(width * 10)), 'white')
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
|
|
|
|
#svg_path = find_data_file("belden-logo.svg")
|
|
#with open(svg_path, 'rb') as svg_file:
|
|
# png_image = cairosvg.svg2png(file_obj=svg_file,dpi=width*30, scale=30, background_color="white")
|
|
#with open("output.png", 'wb') as file:
|
|
# file.write(png_image)
|
|
|
|
png_image_io = "belden-logo-superhires.png"
|
|
png_image_pillow = Image.open(png_image_io)
|
|
png_width, png_height = png_image_pillow.size
|
|
png_image_pillow = png_image_pillow.resize((int(width*4), int(width*4/png_width*png_height)))
|
|
png_width, png_height = png_image_pillow.size
|
|
# paste belden logo first because it has a big border that would cover stuff up
|
|
img.paste(png_image_pillow, (int(width*5-png_width/2), int(width*3.25 - png_height/2)))
|
|
|
|
# draw circle border
|
|
#draw.arc(((width - width/5, width - width/5), (width*9 + width/5, width*9 + width/5)),0,360,fill='blue', width = int(width/8))
|
|
draw.arc(((width+int(width / 1.4), width+int(width / 1.4)), (width*9-int(width / 1.4), width*9-int(width / 1.4))),0,360,fill=(0, 73,144), width = int(width/8))
|
|
|
|
font_path = find_data_file("GothamCond-Medium.otf")
|
|
font_size = width/2
|
|
font = ImageFont.truetype(font_path, font_size)
|
|
text_width = font.getlength(partnum[2:])
|
|
# shrink font dynamically if it's too long of a name
|
|
while text_width > width*4:
|
|
font_size -= 1
|
|
font = ImageFont.truetype(font_path, font_size)
|
|
text_width = font.getlength(partnum[2:])
|
|
|
|
txtx = (int(width * 10) - text_width) / 2
|
|
txty = (int(width * 7.5)) / 2
|
|
# draw part number text
|
|
draw.text((txtx,txty),partnum[2:], "black", font)
|
|
|
|
# Draw QR code
|
|
partnum = partnum.replace(" ", "%20")
|
|
qrcode = segno.make('HTTPS://BLDN.APP/' + partnum,micro=False,boost_error=False,error="L",mask=3)
|
|
out = io.BytesIO()
|
|
qrx, _ = qrcode.symbol_size(1,0)
|
|
qrcode.save(out, scale=width*3/qrx, kind="PNG", border=0)
|
|
qrimg = Image.open(out)
|
|
img.paste(qrimg, box=(int(width*3.5),int(width*4.5)))
|
|
img = img.crop((width+int(width / 1.4)-int(width/8),width+int(width / 1.4)-int(width/8),img.size[0] - (width+int(width / 1.4)-int(width/8)), img.size[1] - (width+int(width / 1.4)-int(width/8)) ))
|
|
img = img.resize((1200, 1200), Image.LANCZOS) # 1200 dpi
|
|
|
|
return img
|
|
|
|
if __name__ == "__main__":
|
|
#print(generate_code("BL10GXS13"))
|
|
#print(generate_code("BL10GXgd35j35S13"))
|
|
#print(generate_code("BL10GX54hS13"))
|
|
#print(generate_code("BL10Gj34qXS13", False, False))
|
|
#print(generate_code("BL104w5545dp7bfwp43643534/4563G-XS13"))
|
|
#adjust_image(cv2.imread('test_skew.jpg'))
|
|
path = "labels"
|
|
img = generate_code("BL10GXS13")
|
|
import os
|
|
os.makedirs(path, exist_ok=True)
|
|
img.save(path + "/" + "BL10GXS13" + ".png") |