main.js aktualisiert
This commit is contained in:
119
main.js
119
main.js
@@ -1,68 +1,79 @@
|
|||||||
// main.js
|
// main.js
|
||||||
const { app, BrowserWindow } = require('electron');
|
const { app, BrowserWindow, Menu } = require('electron');
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
const fsp = require("fs").promises;
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const chokidar = require("chokidar");
|
const chokidar = require("chokidar");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
|
|
||||||
let OUT_DIR; // endgültiger Eingangsordner (wird in app.whenReady gesetzt)
|
let OUT_DIR; // Eingangsordner für ZPL
|
||||||
let IMG_DIR; // Ausgabeordner für PNGs (History)
|
let IMG_DIR; // Ausgabeordner für PNGs (History)
|
||||||
|
|
||||||
let win;
|
let win;
|
||||||
|
let watcher;
|
||||||
|
let busy = false;
|
||||||
|
|
||||||
|
/* --- Fenstererstellung --- */
|
||||||
function createWindow() {
|
function createWindow() {
|
||||||
win = new BrowserWindow({
|
win = new BrowserWindow({
|
||||||
width: 1000,
|
width: 1000,
|
||||||
height: 800,
|
height: 800,
|
||||||
webPreferences: { nodeIntegration: true, contextIsolation: false }
|
icon: path.join(__dirname, "assets/icon.ico"),
|
||||||
|
webPreferences: { nodeIntegration: true, contextIsolation: false },
|
||||||
|
show: false // Fenster erst zeigen, wenn fertig
|
||||||
});
|
});
|
||||||
|
|
||||||
win.loadFile(path.join(__dirname, "index.html"));
|
win.loadFile(path.join(__dirname, "index.html"));
|
||||||
|
win.once("ready-to-show", () => win.show());
|
||||||
|
|
||||||
|
// Menü entfernen (File, Edit usw.)
|
||||||
|
Menu.setApplicationMenu(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
/* --- App Start --- */
|
||||||
// Versuche zuerst C:\ZIR_Output (praktisch für Windows Local Port)
|
app.whenReady().then(async () => {
|
||||||
const preferedRoot = "C:\\ZIR_Output";
|
const preferedRoot = "C:\\ZIR_Output";
|
||||||
let dataDir = app.getPath("userData"); // fallback
|
let dataDir = app.getPath("userData"); // fallback
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Versuch: C:\ZIR_Output anlegen (falls möglich)
|
await fsp.mkdir(preferedRoot, { recursive: true });
|
||||||
if (!fs.existsSync(preferedRoot)) {
|
|
||||||
fs.mkdirSync(preferedRoot, { recursive: true });
|
|
||||||
}
|
|
||||||
OUT_DIR = preferedRoot;
|
OUT_DIR = preferedRoot;
|
||||||
} catch (e) {
|
} catch {
|
||||||
// Falls es schiefgeht (Rechte), fallback in userData
|
|
||||||
OUT_DIR = path.join(dataDir, "ZIR_Input");
|
OUT_DIR = path.join(dataDir, "ZIR_Input");
|
||||||
|
await fsp.mkdir(OUT_DIR, { recursive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMG_DIR im userData (schützt vor Schreibrechten)
|
|
||||||
IMG_DIR = path.join(dataDir, "zpl_out");
|
IMG_DIR = path.join(dataDir, "zpl_out");
|
||||||
|
await fsp.mkdir(IMG_DIR, { recursive: true });
|
||||||
|
|
||||||
// Ordner anlegen, falls nicht existierend
|
console.log("ZIR Input:", OUT_DIR);
|
||||||
try { if (!fs.existsSync(OUT_DIR)) fs.mkdirSync(OUT_DIR, { recursive: true }); } catch(e) {}
|
console.log("ZIR Output:", IMG_DIR);
|
||||||
try { if (!fs.existsSync(IMG_DIR)) fs.mkdirSync(IMG_DIR, { recursive: true }); } catch(e) {}
|
|
||||||
|
|
||||||
console.log("ZIR Input (Eingangsordner):", OUT_DIR);
|
|
||||||
console.log("ZIR Output (PNG-Ordner):", IMG_DIR);
|
|
||||||
|
|
||||||
createWindow();
|
createWindow();
|
||||||
|
|
||||||
const watcher = chokidar.watch(OUT_DIR, { ignoreInitial: true, awaitWriteFinish: {stabilityThreshold: 500, pollInterval: 100} });
|
// Watcher verzögert starten (macht Start schneller)
|
||||||
|
setTimeout(startWatcher, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') app.quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
/* --- Watcher --- */
|
||||||
|
function startWatcher() {
|
||||||
|
watcher = chokidar.watch(OUT_DIR, {
|
||||||
|
ignoreInitial: true,
|
||||||
|
awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 }
|
||||||
|
});
|
||||||
|
|
||||||
watcher.on("add", file => {
|
watcher.on("add", file => {
|
||||||
if (!file.toLowerCase().endsWith(".zpl")) return;
|
if (file.toLowerCase().endsWith(".zpl")) processFile(file);
|
||||||
processFile(file);
|
|
||||||
});
|
});
|
||||||
watcher.on("change", file => {
|
watcher.on("change", file => {
|
||||||
if (!file.toLowerCase().endsWith(".zpl")) return;
|
if (file.toLowerCase().endsWith(".zpl")) processFile(file);
|
||||||
processFile(file);
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) createWindow(); });
|
|
||||||
});
|
|
||||||
|
|
||||||
app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(); });
|
|
||||||
|
|
||||||
/* --- Helferfunktionen --- */
|
/* --- Helferfunktionen --- */
|
||||||
|
|
||||||
function extractZPL(raw) {
|
function extractZPL(raw) {
|
||||||
const start = raw.indexOf("^XA");
|
const start = raw.indexOf("^XA");
|
||||||
const end = raw.lastIndexOf("^XZ");
|
const end = raw.lastIndexOf("^XZ");
|
||||||
@@ -111,17 +122,15 @@ async function tryLabelaryRender(zpl, printerKey, widthInches, heightInches) {
|
|||||||
const resp = await axios.post(url, zpl, {
|
const resp = await axios.post(url, zpl, {
|
||||||
headers: { "Accept": "image/png" },
|
headers: { "Accept": "image/png" },
|
||||||
responseType: "arraybuffer",
|
responseType: "arraybuffer",
|
||||||
timeout: 15000
|
timeout: 10000
|
||||||
});
|
});
|
||||||
return { ok: true, buffer: resp.data };
|
return { ok: true, buffer: resp.data };
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const status = err.response ? err.response.status : null;
|
return { ok: false, status: err.response?.status, error: err.message };
|
||||||
return { ok: false, status, error: err.message };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Größen & Druckeroptionen --- */
|
/* --- Größen & Druckeroptionen --- */
|
||||||
|
|
||||||
const STANDARD_SIZES = [
|
const STANDARD_SIZES = [
|
||||||
{ w: 8.27, h: 11.69, name: "A4" },
|
{ w: 8.27, h: 11.69, name: "A4" },
|
||||||
{ w: 8.5, h: 11, name: "Letter" },
|
{ w: 8.5, h: 11, name: "Letter" },
|
||||||
@@ -138,7 +147,6 @@ const PRINTER_OPTIONS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
/* --- Hauptverarbeitung --- */
|
/* --- Hauptverarbeitung --- */
|
||||||
let busy = false;
|
|
||||||
async function processFile(filePath) {
|
async function processFile(filePath) {
|
||||||
if (busy) {
|
if (busy) {
|
||||||
setTimeout(() => processFile(filePath), 400);
|
setTimeout(() => processFile(filePath), 400);
|
||||||
@@ -147,16 +155,13 @@ async function processFile(filePath) {
|
|||||||
busy = true;
|
busy = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log("Verarbeite:", filePath);
|
let raw = await fsp.readFile(filePath, "utf-8");
|
||||||
let raw = fs.readFileSync(filePath, "utf-8");
|
|
||||||
raw = cleanControlChars(raw);
|
raw = cleanControlChars(raw);
|
||||||
let zpl = extractZPL(raw);
|
let zpl = extractZPL(raw);
|
||||||
|
|
||||||
const { pw, ll } = parsePWLL(zpl);
|
const { pw, ll } = parsePWLL(zpl);
|
||||||
const { maxX, maxY } = parseMaxFO(zpl);
|
const { maxX, maxY } = parseMaxFO(zpl);
|
||||||
console.log("Parsed PW/LL:", pw, ll, "maxFO:", maxX, maxY);
|
|
||||||
|
|
||||||
// sizesToTry aufbauen (Priorität: PW/LL -> geschätzte große Formate -> Standardgrößen)
|
|
||||||
const sizesToTry = [];
|
const sizesToTry = [];
|
||||||
|
|
||||||
if (pw && ll) {
|
if (pw && ll) {
|
||||||
@@ -171,11 +176,10 @@ async function processFile(filePath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const estDefaultDPI = 203;
|
const estDefaultDPI = 203;
|
||||||
const estWIn = maxX ? dotsToInches(maxX + 100, estDefaultDPI) : null; // margin
|
const estWIn = maxX ? dotsToInches(maxX + 100, estDefaultDPI) : null;
|
||||||
const estHIn = maxY ? dotsToInches(maxY + 100, estDefaultDPI) : null;
|
const estHIn = maxY ? dotsToInches(maxY + 100, estDefaultDPI) : null;
|
||||||
|
|
||||||
if (estWIn && estHIn) {
|
if (estWIn && estHIn && (estWIn > 6 || estHIn > 8)) {
|
||||||
if (estWIn > 6 || estHIn > 8 || estWIn > 8 || estHIn > 6) {
|
|
||||||
for (const p of PRINTER_OPTIONS) {
|
for (const p of PRINTER_OPTIONS) {
|
||||||
sizesToTry.push({ w: 8.27, h: 11.69, printer: p, name: "A4" });
|
sizesToTry.push({ w: 8.27, h: 11.69, printer: p, name: "A4" });
|
||||||
sizesToTry.push({ w: 11.69, h: 8.27, printer: p, name: "A4_rot" });
|
sizesToTry.push({ w: 11.69, h: 8.27, printer: p, name: "A4_rot" });
|
||||||
@@ -183,16 +187,16 @@ async function processFile(filePath) {
|
|||||||
sizesToTry.push({ w: 11, h: 8.5, printer: p, name: "Letter_rot" });
|
sizesToTry.push({ w: 11, h: 8.5, printer: p, name: "Letter_rot" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const p of PRINTER_OPTIONS) {
|
for (const p of PRINTER_OPTIONS) {
|
||||||
for (const s of STANDARD_SIZES) {
|
for (const s of STANDARD_SIZES) {
|
||||||
const exists = sizesToTry.some(x => Math.abs(x.w - s.w) < 0.01 && Math.abs(x.h - s.h) < 0.01 && x.printer.key === p.key);
|
const exists = sizesToTry.some(x =>
|
||||||
if (!exists) sizesToTry.push({ w: s.w, h: s.h, printer: p, name: s.name || `${s.w}x${s.h}` });
|
Math.abs(x.w - s.w) < 0.01 && Math.abs(x.h - s.h) < 0.01 && x.printer.key === p.key
|
||||||
|
);
|
||||||
|
if (!exists) sizesToTry.push({ w: s.w, h: s.h, printer: p, name: s.name });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplikate entfernen & Reihenfolge behalten
|
|
||||||
const uniqSizes = [];
|
const uniqSizes = [];
|
||||||
const seen = new Set();
|
const seen = new Set();
|
||||||
for (const s of sizesToTry) {
|
for (const s of sizesToTry) {
|
||||||
@@ -200,38 +204,29 @@ async function processFile(filePath) {
|
|||||||
if (!seen.has(key)) { seen.add(key); uniqSizes.push(s); }
|
if (!seen.has(key)) { seen.add(key); uniqSizes.push(s); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Versuche rendern
|
|
||||||
let renderResult = null;
|
let renderResult = null;
|
||||||
for (const s of uniqSizes) {
|
for (const s of uniqSizes) {
|
||||||
const wStr = fmtInches(s.w);
|
renderResult = await tryLabelaryRender(zpl, s.printer.key, fmtInches(s.w), fmtInches(s.h));
|
||||||
const hStr = fmtInches(s.h);
|
if (renderResult.ok) break;
|
||||||
console.log(`Versuche rendern: printer=${s.printer.key} size=${wStr}x${hStr} (${s.name || ""})`);
|
|
||||||
renderResult = await tryLabelaryRender(zpl, s.printer.key, wStr, hStr);
|
|
||||||
if (renderResult.ok) { console.log(`Erfolg mit ${s.printer.key} ${wStr}x${hStr}`); break; }
|
|
||||||
else { console.log(`Fehler (${renderResult.status}) mit ${s.printer.key} ${wStr}x${hStr}`); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!renderResult || !renderResult.ok) {
|
if (!renderResult?.ok) {
|
||||||
console.error("Alle Render-Versuche fehlgeschlagen, Abbruch.");
|
console.error("Rendering fehlgeschlagen");
|
||||||
busy = false;
|
busy = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PNG speichern — neue Datei mit Timestamp (History)
|
|
||||||
const pngBuffer = renderResult.buffer;
|
const pngBuffer = renderResult.buffer;
|
||||||
const timestamp = Date.now();
|
const timestamp = Date.now();
|
||||||
const outFile = path.join(IMG_DIR, `label-${timestamp}.png`);
|
const outFile = path.join(IMG_DIR, `label-${timestamp}.png`);
|
||||||
fs.writeFileSync(outFile, pngBuffer);
|
await fsp.writeFile(outFile, pngBuffer);
|
||||||
console.log("PNG erstellt:", outFile);
|
|
||||||
|
|
||||||
// ZPL-Datei löschen (optional)
|
try { await fsp.unlink(filePath); } catch {}
|
||||||
try { fs.unlinkSync(filePath); } catch(e){ console.warn("Konnte ZPL nicht löschen:", e.message); }
|
|
||||||
|
|
||||||
// Fenster benachrichtigen (sende neuen PNG-Pfad)
|
|
||||||
win.webContents.send("show-png", outFile);
|
win.webContents.send("show-png", outFile);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Fehler beim Rendern:", err && err.message ? err.message : err);
|
console.error("Fehler beim Rendern:", err.message);
|
||||||
} finally {
|
} finally {
|
||||||
busy = false;
|
busy = false;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user