Skip to content

Commit

Permalink
Merge pull request #82 from putzio/Barcode-with-text-bellow-it
Browse files Browse the repository at this point in the history
barcode with text
  • Loading branch information
maresb authored Dec 7, 2023
2 parents ed2919a + 6224363 commit 3dd2ec0
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 73 deletions.
46 changes: 25 additions & 21 deletions src/dymoprint/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@
from PIL import Image, ImageOps

from . import __version__
from .constants import DEFAULT_MARGIN_PX, PIXELS_PER_MM, USE_QR, e_qrcode
from .constants import (
AVAILABLE_BARCODES,
DEFAULT_MARGIN_PX,
PIXELS_PER_MM,
USE_QR,
e_qrcode,
)
from .dymo_print_engines import DymoRenderEngine, print_label
from .font_config import font_filename
from .metadata import our_metadata
Expand Down Expand Up @@ -117,26 +123,17 @@ def parse_args():
)
parser.add_argument(
"-c",
choices=[
"code39",
"code128",
"ean",
"ean13",
"ean8",
"gs1",
"gtin",
"isbn",
"isbn10",
"isbn13",
"issn",
"jan",
"pzn",
"upc",
"upca",
],
"--barcode",
choices=AVAILABLE_BARCODES,
default=False,
help="Printing the first text parameter as barcode",
)
parser.add_argument(
"--barcode-text",
choices=AVAILABLE_BARCODES,
default=False,
help="Printing the first text parameter as barcode and text under it",
)
parser.add_argument("-p", "--picture", help="Print the specified picture")
parser.add_argument(
"-m",
Expand Down Expand Up @@ -184,7 +181,7 @@ def main():
if args.qr and not USE_QR:
die("Error: %s" % e_qrcode)

if args.c and args.qr:
if args.barcode and args.qr:
die("Error: can not print both QR and Barcode on the same label (yet)")

if args.fixed_length is not None and (
Expand All @@ -203,8 +200,15 @@ def main():
if args.qr:
bitmaps.append(render_engine.render_qr(labeltext.pop(0)))

elif args.c:
bitmaps.append(render_engine.render_barcode(labeltext.pop(0), args.c))
elif args.barcode:
bitmaps.append(render_engine.render_barcode(labeltext.pop(0), args.barcode))

elif args.barcode_text:
bitmaps.append(
render_engine.render_barcode_with_text(
labeltext.pop(0), args.barcode_text, FONT_FILENAME, args.f
)
)

if labeltext:
bitmaps.append(
Expand Down
18 changes: 18 additions & 0 deletions src/dymoprint/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,21 @@

DEFAULT_FONT_DIR = Path(dymoprint.resources.fonts.__file__).parent
ICON_DIR = Path(dymoprint.resources.icons.__file__).parent

AVAILABLE_BARCODES = [
"code39",
"code128",
"ean",
"ean13",
"ean8",
"gs1",
"gtin",
"isbn",
"isbn10",
"isbn13",
"issn",
"jan",
"pzn",
"upc",
"upca",
]
86 changes: 70 additions & 16 deletions src/dymoprint/dymo_print_engines.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,34 +30,34 @@ def render_empty(self, label_len: int = 1) -> Image.Image:

def render_test(self, width: int = 100) -> Image.Image:
"""Render a test pattern"""
canvas = Image.new("1", (10+width+2+40, width))
canvas = Image.new("1", (10 + width + 2 + 40, width))

# 5 vertical lines
for x in range(0,9,2):
for x in range(0, 9, 2):
for y in range(canvas.height):
canvas.putpixel((x, y), 1)

# checkerboard pattern
cb = Image.new("1", (width, width))
ss = 1;
while ss <= (width/2):
for x in range(ss-1,2*ss-1):
for y in range(0,width):
if ((math.floor(y/ss) % 2) == 0):
cb.putpixel((x,y), 1)
ss = 1
while ss <= (width / 2):
for x in range(ss - 1, 2 * ss - 1):
for y in range(0, width):
if (math.floor(y / ss) % 2) == 0:
cb.putpixel((x, y), 1)
ss *= 2
canvas.paste(cb, (10,0))
canvas.paste(cb, (10, 0))

# a bunch of horizontal lines, on top and bottom
hl = Image.new("1", (20, 9))
for y in range(0,9,2):
for y in range(0, 9, 2):
for x in range(20):
hl.putpixel((x, y), 1)
canvas.paste(hl, (10+width+2,0))
canvas.paste(hl, (10+width+2,width-9))
canvas.paste(hl, (10+width+2+20,1))
canvas.paste(hl, (10+width+2+20,width-9-1))
canvas.paste(hl, (10 + width + 2, 0))
canvas.paste(hl, (10 + width + 2, width - 9))
canvas.paste(hl, (10 + width + 2 + 20, 1))
canvas.paste(hl, (10 + width + 2 + 20, width - 9 - 1))

return canvas

def render_qr(self, qr_input_text: str) -> Image.Image:
Expand Down Expand Up @@ -119,13 +119,66 @@ def render_barcode(
)
return code_bitmap

def render_barcode_with_text(
self,
barcode_input_text,
bar_code_type,
font_file_name: str,
frame_width,
font_size_ratio=0.9,
align="center",
):
"""
Renders a barcode image with the text below it.
Args:
barcode_input_text (str): The input text to be encoded in the barcode.
bar_code_type (str): The type of barcode to be rendered.
font_file_name (str): The name of the font file to be used.
frame_width (int): The width of the frame around the text.
font_size_ratio (float): The ratio of font size to line height. Default
is 1.
Returns:
Image: A barcode with text image.
"""
assert align in ("left", "center", "right")
# Generate barcode
code_bitmap = self.render_barcode(barcode_input_text, bar_code_type)

# Generate text
text_bitmap = self.render_text(
text_lines=barcode_input_text,
font_file_name=font_file_name,
frame_width_px=frame_width,
font_size_ratio=font_size_ratio,
align=align,
label_height_px=code_bitmap.height // 3,
)

# Define the x and y of the upper-left corner of the text
# to be pasted onto the barcode
text_x = code_bitmap.height - text_bitmap.height - 1
if align == "left":
text_y = 0
elif align == "center":
text_y = code_bitmap.width // 2 - text_bitmap.width // 2
elif align == "right":
text_y = code_bitmap.width - text_bitmap.width
else:
raise ValueError(f"Invalid align value: {align}")

code_bitmap.paste(text_bitmap, (text_y, text_x))
return code_bitmap

def render_text(
self,
text_lines: str | list[str],
font_file_name: str,
frame_width_px: int,
font_size_ratio: float = 0.9,
align: str = "left",
label_height_px: int | None = None,
) -> Image.Image:
"""Render text to image.
Expand All @@ -139,7 +192,8 @@ def render_text(
text_lines = [" "]

# create an empty label image
label_height_px = DymoLabeler.max_bytes_per_line(self.tape_size_mm) * 8
if label_height_px is None:
label_height_px = DymoLabeler.max_bytes_per_line(self.tape_size_mm) * 8
line_height = float(label_height_px) / len(text_lines)
font_size_px = int(round(line_height * font_size_ratio))

Expand Down
3 changes: 2 additions & 1 deletion src/dymoprint/gui.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys
import traceback
from typing import Optional

from PIL import Image, ImageOps, ImageQt
from PyQt6 import QtCore
Expand All @@ -26,7 +27,7 @@


class DymoPrintWindow(QWidget):
label_bitmap: Image.Image | None
label_bitmap: Optional[Image.Image]

def __init__(self):
super().__init__()
Expand Down
Loading

0 comments on commit 3dd2ec0

Please sign in to comment.