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

Dev #5

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
54 changes: 1 addition & 53 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,56 +39,4 @@ jobs:
# Push Docker Image to Docker Hub
- name: Push Docker Image
run: |
docker push ${{ secrets.DOCKER_USERNAME }}/brother_ql_app:${{ env.IMAGE_TAG }}

release:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
# Checkout des Codes
- name: Checkout code
uses: actions/checkout@v3

# Git konfigurieren
- name: Configure Git
run: |
git config --global user.email "ci@github-actions.com"
git config --global user.name "GitHub Actions CI"

# Git-Version setzen und neuen Release-Tag erstellen
- name: Set up Git and Release Version
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git fetch --tags

# Aktuellsten Tag finden
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "1.0.0")

# Neue Version basierend auf dem letzten Tag erstellen
NEW_VERSION=$(echo $VERSION | awk -F. -v OFS=. '{$NF++; print}')

# Überprüfen, ob der neue Tag bereits existiert
if git rev-parse "refs/tags/$NEW_VERSION" >/dev/null 2>&1; then
echo "Tag $NEW_VERSION already exists. Skipping tag creation."
exit 0
fi

# Neuen Tag erstellen und pushen
git tag -a $NEW_VERSION -m "Release $NEW_VERSION"
git push origin $NEW_VERSION

# Speichern der neuen Version für nachfolgende Schritte
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV

# GitHub Release erstellen
- name: Create GitHub Release
uses: actions/create-release@v1
with:
tag_name: ${{ env.NEW_VERSION }}
release_name: "Release ${{ env.NEW_VERSION }}"
body: "Automated release of version ${{ env.NEW_VERSION }}."
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
docker push ${{ secrets.DOCKER_USERNAME }}/brother_ql_app:${{ env.IMAGE_TAG }}
82 changes: 82 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Release Workflow

on:
push:
branches:
- main
- dev

jobs:
release:
runs-on: ubuntu-latest

steps:
# Checkout des Codes
- name: Checkout code
uses: actions/checkout@v3

# Git konfigurieren
- name: Configure Git
run: |
git config --global user.email "ci@github-actions.com"
git config --global user.name "GitHub Actions CI"

# Versionsnummer und Release Notes aus changelog.md extrahieren
- name: Extract Version and Release Notes
id: changelog
run: |
# Datei prüfen
if [ ! -f changelog.md ]; then
echo "ERROR: changelog.md not found!" >&2
exit 1
fi

# Branch prüfen
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
# Reguläres Release (erstes "## Release")
VERSION=$(grep -m 1 '^## Release ' changelog.md | awk '{print $3}')
NOTES=$(awk '/^## Release / {if (NR > 1) exit; next} {print}' changelog.md)
elif [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then
# Beta-Release (erstes "## Beta Release")
VERSION=$(grep -m 1 '^## Beta Release ' changelog.md | awk '{print $4}')
NOTES=$(awk '/^## Beta Release / {if (NR > 1) exit; next} {print}' changelog.md)
else
echo "ERROR: Unsupported branch ${{ github.ref }}" >&2
exit 1
fi

if [ -z "$VERSION" ]; then
echo "ERROR: Could not extract version from changelog.md" >&2
exit 1
fi

echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "NOTES<<EOF" >> $GITHUB_ENV
echo "$NOTES" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV

# Überprüfen, ob der Tag existiert
- name: Check if Tag Already Exists
run: |
if git rev-parse "refs/tags/${{ env.VERSION }}" >/dev/null 2>&1; then
echo "Tag ${{ env.VERSION }} already exists. Skipping release."
exit 0
fi

# Neuen Git-Tag erstellen und pushen
- name: Create and Push Tag
run: |
git tag -a ${{ env.VERSION }} -m "Release ${{ env.VERSION }}"
git push origin ${{ env.VERSION }}

# GitHub Release erstellen
- name: Create GitHub Release
uses: actions/create-release@v1
with:
tag_name: ${{ env.VERSION }}
release_name: "Release ${{ env.VERSION }}"
body: ${{ env.NOTES }}
draft: false
prerelease: ${{ github.ref == 'refs/heads/dev' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
8 changes: 5 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# Basis-Image mit Python 3.10
FROM python:3.10-slim

# Arbeitsverzeichnis setzen
WORKDIR /app

# Systemabhängigkeiten für Pillow und Fonts
# Systemabhängigkeiten installieren (für Pillow und Fonts)
RUN apt-get update && apt-get install -y \
libfreetype6 libjpeg62-turbo zlib1g-dev \
fonts-dejavu-core && \
rm -rf /var/lib/apt/lists/*

# Abhängigkeiten installieren
# Anforderungen kopieren und Python-Abhängigkeiten installieren
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Anwendung kopieren
# Anwendungscode kopieren
COPY . .

# Flask-Anwendung starten
Expand Down
114 changes: 68 additions & 46 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,44 @@
from brother_ql.conversion import convert
from brother_ql.backends import backend_factory
import os
import json

app = Flask(__name__)

# Standard-Druckerkonfiguration
PRINTER_URI = os.getenv("PRINTER_URI", "tcp://192.168.1.100")
PRINTER_MODEL = os.getenv("PRINTER_MODEL", "QL-800")
LABEL_SIZE = "62"
FONT_SIZE = 50 # Standard-Schriftgröße
# Standard-Dateipfad für Settings
SETTINGS_FILE = "settings.json"
FONT_PATH = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"

# Standard-Einstellungen
DEFAULT_SETTINGS = {
"printer_uri": "tcp://192.168.1.100",
"printer_model": "QL-800",
"label_size": "62",
"font_size": 50,
"alignment": "left",
"rotate": "0", # Optionen: "0", "90", "180", "270"
"threshold": 70.0, # Schwellenwert für Schwarz-Weiß-Konvertierung
"dither": False, # Dithering verwenden oder nicht
"compress": False, # Kompression verwenden oder nicht
"red": True # Zweifarbiger Druck (Schwarz/Rot) verwenden
}

# Einstellungen laden/speichern
def load_settings():
"""Lädt die Einstellungen aus einer JSON-Datei."""
if os.path.exists(SETTINGS_FILE):
with open(SETTINGS_FILE, "r") as f:
return json.load(f)
return DEFAULT_SETTINGS.copy()

def save_settings(settings):
"""Speichert die Einstellungen in eine JSON-Datei."""
with open(SETTINGS_FILE, "w") as f:
json.dump(settings, f, indent=4)

# Globale Einstellungen initialisieren
settings = load_settings()

class TextParser(HTMLParser):
"""Parst HTML und speichert Text mit Formatierungen."""
def __init__(self):
Expand All @@ -26,17 +54,15 @@ def __init__(self):
def handle_starttag(self, tag, attrs):
self.current_tag = tag
self.current_attrs = dict(attrs)

# <br> Tag erkennen
if tag == "br":
self.parts.append({"text": "<br>", "font": None, "color": None, "align": None})

def handle_data(self, data):
color = self.current_attrs.get("color", "black")
font = ImageFont.truetype(FONT_PATH, FONT_SIZE) # Schriftgröße aus globaler Variable
font = ImageFont.truetype(FONT_PATH, settings["font_size"])
bold = self.current_tag == "b"
if bold:
font = ImageFont.truetype(FONT_PATH, FONT_SIZE + 5) # Bold-Schrift
font = ImageFont.truetype(FONT_PATH, settings["font_size"] + 5)
self.parts.append({"text": data.strip(), "font": font, "color": color, "align": None})

def handle_endtag(self, tag):
Expand All @@ -47,54 +73,53 @@ def handle_endtag(self, tag):
def index():
return render_template("index.html")

@app.route("/settings", methods=["GET"])
def get_settings():
"""Gibt die gespeicherten Einstellungen zurück."""
return jsonify(settings)

@app.route("/update_settings", methods=["POST"])
def update_settings():
"""Einstellungen aktualisieren."""
global LABEL_SIZE, FONT_SIZE
LABEL_SIZE = request.form.get("label_size", LABEL_SIZE)
FONT_SIZE = int(request.form.get("font_size", FONT_SIZE)) # Schriftgröße aktualisieren
return jsonify({"success": True, "message": "Einstellungen aktualisiert."})
"""Einstellungen aktualisieren und persistent speichern."""
global settings
settings["printer_uri"] = request.form.get("printer_uri", settings["printer_uri"])
settings["printer_model"] = request.form.get("printer_model", settings["printer_model"])
settings["label_size"] = request.form.get("label_size", settings["label_size"])
settings["font_size"] = int(request.form.get("font_size", settings["font_size"]))
settings["alignment"] = request.form.get("alignment", settings["alignment"])
settings["rotate"] = request.form.get("rotate", settings["rotate"])
settings["threshold"] = float(request.form.get("threshold", settings["threshold"]))
settings["dither"] = request.form.get("dither", str(settings["dither"])).lower() == "true"
settings["compress"] = request.form.get("compress", str(settings["compress"])).lower() == "true"
settings["red"] = request.form.get("red", str(settings["red"])).lower() == "true"

save_settings(settings)
return jsonify({"success": True, "message": "Einstellungen gespeichert."})

@app.route("/api/text/", methods=["POST"])
def api_text():
global FONT_SIZE, LABEL_SIZE # Global-Deklaration am Anfang

"""Verarbeitet und druckt den eingegebenen Text."""
data = request.json
text = data.get("text", "").strip()
label_size = data.get("settings", {}).get("label_size", LABEL_SIZE)
font_size = data.get("settings", {}).get("font_size", FONT_SIZE)
alignment = data.get("settings", {}).get("alignment", "left") # Neue Einstellung für Ausrichtung
alignment = data.get("settings", {}).get("alignment", settings["alignment"])

if not text:
return jsonify({"error": "Kein Text angegeben."}), 400

try:
# Temporär aktualisierte Schrift- und Label-Größe anwenden
original_font_size = FONT_SIZE
original_label_size = LABEL_SIZE
FONT_SIZE = int(font_size)
LABEL_SIZE = label_size

# Label erzeugen und drucken
image_path = create_label_image(text, alignment)
send_to_printer(image_path)

# Originale Werte wiederherstellen
FONT_SIZE = original_font_size
LABEL_SIZE = original_label_size

return jsonify({"success": True, "message": "Textdruckauftrag gesendet."})
except Exception as e:
return jsonify({"error": str(e)}), 500


def create_label_image(html_text, alignment="left"):
"""Erstellt ein Labelbild mit dynamischer Höhe und unterstützt Ausrichtung."""
width = 696
parser = TextParser()
parser.feed(html_text)

# Gruppieren der Zeilen
lines = []
current_line = []
for part in parser.parts:
Expand All @@ -107,7 +132,6 @@ def create_label_image(html_text, alignment="left"):
if current_line:
lines.append(current_line)

# Höhe berechnen
dummy_image = Image.new("RGB", (width, 10), "white")
dummy_draw = ImageDraw.Draw(dummy_image)

Expand All @@ -124,28 +148,26 @@ def create_label_image(html_text, alignment="left"):
ascent_values.append(ascent)
descent_values.append(descent)
text_width = dummy_draw.textbbox((0, 0), part["text"], font=font)[2]
line_width += text_width + 5 # 5 Pixel Abstand zwischen den Wörtern
line_width += text_width + 5
line_width -= 5
max_ascent = max(ascent_values, default=0)
max_descent = max(descent_values, default=0)
line_height = max_ascent + max_descent
line_metrics.append((line, max_ascent, max_descent, line_height, line_width))
total_height += line_height + line_spacing

total_height += 10 # Unterer Rand
total_height += 10

# Bild erstellen
image = Image.new("RGB", (width, total_height), "white")
draw = ImageDraw.Draw(image)

y = 10
for line, max_ascent, max_descent, line_height, line_width in line_metrics:
# Basierend auf der Ausrichtung x-Wert berechnen
if alignment == "center":
x = (width - line_width) // 2
elif alignment == "right":
x = width - line_width - 10
else: # Standard: left
else:
x = 10

for part in line:
Expand All @@ -163,19 +185,19 @@ def create_label_image(html_text, alignment="left"):

def send_to_printer(image_path):
"""Sendet das Label an den Drucker."""
qlr = BrotherQLRaster(PRINTER_MODEL)
qlr = BrotherQLRaster(settings["printer_model"])
qlr.exception_on_warning = True
instructions = convert(
qlr=qlr,
images=[image_path],
label=LABEL_SIZE,
rotate="0",
threshold=70.0,
dither=False,
compress=False,
red=True,
label=settings["label_size"],
rotate=settings["rotate"],
threshold=settings["threshold"],
dither=settings["dither"],
compress=settings["compress"],
red=settings["red"],
)
backend = backend_factory("network")["backend_class"](PRINTER_URI)
backend = backend_factory("network")["backend_class"](settings["printer_uri"])
backend.write(instructions)
backend.dispose()

Expand Down
Loading
Loading