@bobfrankston/brother-label 1.0.11 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC1B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAEzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IAGZ,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAC;CACjB;AA0BD,wBAAgB,SAAS,IAAI,aAAa,CAczC;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAI9D;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAGD,wBAAsB,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAuB3D;AAsVD,wBAAsB,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAInE;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAMvE"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC1B,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAEzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IAGZ,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,MAAM,CAAC;CACjB;AA0BD,wBAAgB,SAAS,IAAI,aAAa,CAczC;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,CAI9D;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAGD,wBAAsB,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAuB3D;AAsVD,wBAAsB,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAInE;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAMvE"}
package/api.js CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import * as fs from "fs";
6
6
  import * as path from "path";
7
+ import { fileURLToPath } from "url";
7
8
  import * as os from "os";
8
9
  import { renderHtmlFile, renderHtmlString, closeBrowser } from "./render.js";
9
10
  import { Jimp, loadFont, measureText, measureTextHeight } from "jimp";
@@ -134,7 +135,7 @@ async function renderText(text, tape) {
134
135
  const targetHeight = tapeSize.height;
135
136
  const lines = text.split("\\n").join("\n");
136
137
  // Load largest font for quality
137
- const fontDir = path.join(path.dirname(new URL(import.meta.url).pathname).replace(/^\/([A-Z]:)/, "$1"), "node_modules/@jimp/plugin-print/fonts/open-sans");
138
+ const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "node_modules/@jimp/plugin-print/fonts/open-sans");
138
139
  const fontPath = path.join(fontDir, "open-sans-128-black", "open-sans-128-black.fnt");
139
140
  const font = await loadFont(fontPath);
140
141
  // Measure text
@@ -187,7 +188,7 @@ async function renderQr(data, tape, labelText) {
187
188
  return image.getBuffer("image/png");
188
189
  }
189
190
  // QR + text label
190
- const fontDir = path.join(path.dirname(new URL(import.meta.url).pathname).replace(/^\/([A-Z]:)/, "$1"), "node_modules/@jimp/plugin-print/fonts/open-sans");
191
+ const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "node_modules/@jimp/plugin-print/fonts/open-sans");
191
192
  const fontPath = path.join(fontDir, "open-sans-64-black", "open-sans-64-black.fnt");
192
193
  const font = await loadFont(fontPath);
193
194
  const textWidth = measureText(font, labelText);
package/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Brother Label Printer API\r\n * Programmatic interface for printing labels on Brother P-touch printers\r\n */\r\n\r\nimport * as fs from \"fs\";\r\nimport * as path from \"path\";\r\nimport * as os from \"os\";\r\nimport { renderHtmlFile, renderHtmlString, closeBrowser } from \"./render.js\";\r\nimport { Jimp, loadFont, measureText, measureTextHeight } from \"jimp\";\r\nimport { spawn } from \"child_process\";\r\nimport QRCode from \"qrcode\";\r\n\r\n// Types\r\nexport type TapeSize = 6 | 9 | 12 | 18 | 24;\r\nexport type Orientation = \"landscape\" | \"portrait\";\r\n\r\nexport interface PrinterConfig {\r\n defaultTape?: TapeSize;\r\n defaultPrinter?: string;\r\n}\r\n\r\nexport interface PrinterInfo {\r\n name: string;\r\n}\r\n\r\nexport interface PrintOptions {\r\n // Content (exactly one required)\r\n text?: string;\r\n html?: string;\r\n htmlPath?: string;\r\n textFile?: string;\r\n imagePath?: string;\r\n imageBuffer?: Buffer;\r\n qr?: string; // QR code data to encode\r\n\r\n // Settings\r\n tape?: TapeSize;\r\n printer?: string;\r\n orientation?: Orientation;\r\n length?: number; // explicit length in mm\r\n basePath?: string; // base path for inline HTML resources\r\n aspect?: string; // width:height ratio for HTML (e.g., \"3.5:2\")\r\n qrLabel?: string; // optional text label beside QR code\r\n}\r\n\r\nexport interface PrintResult {\r\n image: Buffer;\r\n}\r\n\r\n// Constants\r\nconst CONFIG_PATH = path.join(os.homedir(), \".brother-label.json\");\r\nconst DEFAULT_PRINTER = \"Brother PT-P710BT\";\r\nconst PRINT_DPI = 300; // High resolution for quality output\r\n\r\n// Tape sizes: height is printable area in pixels at 300 DPI\r\nconst TAPE_SIZES: Record<TapeSize, { width: number; height: number }> = {\r\n 6: { width: 1137, height: 56 }, // 3.79\" x 0.19\" @ 300 DPI\r\n 9: { width: 1137, height: 84 }, // 3.79\" x 0.28\" @ 300 DPI\r\n 12: { width: 1137, height: 113 }, // 3.79\" x 0.38\" @ 300 DPI\r\n 18: { width: 1137, height: 169 }, // 3.79\" x 0.56\" @ 300 DPI\r\n 24: { width: 1137, height: 213 }, // 3.79\" x 0.71\" @ 300 DPI\r\n};\r\n\r\n// Brother CustomMediaSize names and widths in microns\r\nconst MEDIA_OPTIONS: Record<TapeSize, { name: string; width: number }> = {\r\n 6: { name: \"CustomMediaSize257\", width: 5900 },\r\n 9: { name: \"CustomMediaSize258\", width: 9000 },\r\n 12: { name: \"CustomMediaSize259\", width: 11900 },\r\n 18: { name: \"CustomMediaSize260\", width: 18100 },\r\n 24: { name: \"CustomMediaSize261\", width: 24000 },\r\n};\r\n\r\n// Config functions\r\nexport function getConfig(): PrinterConfig {\r\n try {\r\n if (fs.existsSync(CONFIG_PATH)) {\r\n const raw = JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\r\n // Handle legacy format where tape was stored as \"24mm\" string\r\n if (typeof raw.defaultTape === \"string\") {\r\n raw.defaultTape = parseInt(raw.defaultTape.replace(\"mm\", \"\"), 10) as TapeSize;\r\n }\r\n return raw;\r\n }\r\n } catch {\r\n // Ignore config errors\r\n }\r\n return {};\r\n}\r\n\r\nexport function setConfig(config: Partial<PrinterConfig>): void {\r\n const current = getConfig();\r\n const merged = { ...current, ...config };\r\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2));\r\n}\r\n\r\nexport function getConfigPath(): string {\r\n return CONFIG_PATH;\r\n}\r\n\r\n// Printer listing\r\nexport async function listPrinters(): Promise<PrinterInfo[]> {\r\n return new Promise((resolve, reject) => {\r\n const ps = spawn(\"powershell\", [\r\n \"-Command\",\r\n \"Get-Printer | Where-Object { $_.Name -like '*Brother*' -or $_.Name -like '*PT*' -or $_.Name -like '*QL*' } | Select-Object -ExpandProperty Name\"\r\n ], { stdio: \"pipe\" });\r\n\r\n let stdout = \"\";\r\n let stderr = \"\";\r\n ps.stdout.on(\"data\", (data) => { stdout += data.toString(); });\r\n ps.stderr.on(\"data\", (data) => { stderr += data.toString(); });\r\n\r\n ps.on(\"close\", (code) => {\r\n if (code !== 0) {\r\n reject(new Error(`Failed to list printers: ${stderr}`));\r\n return;\r\n }\r\n const printers = stdout.trim().split(\"\\n\")\r\n .filter(p => p.trim())\r\n .map(name => ({ name: name.trim() }));\r\n resolve(printers);\r\n });\r\n });\r\n}\r\n\r\n// Calculate HTML viewport dimensions from tape height and optional aspect ratio\r\nfunction getHtmlDimensions(tapeHeight: number, aspect?: string): { width?: number; height: number } {\r\n if (!aspect) {\r\n // Auto-detect width from content\r\n return { width: undefined, height: tapeHeight };\r\n }\r\n\r\n // Parse aspect ratio \"width:height\" or \"width/height\" (e.g., \"3.5:2\" or \"3.5/2\")\r\n const separator = aspect.includes(\"/\") ? \"/\" : \":\";\r\n const parts = aspect.split(separator);\r\n if (parts.length !== 2) {\r\n throw new Error(`Invalid aspect ratio: ${aspect}. Use format \"width:height\" or \"width/height\"`);\r\n }\r\n const aspectWidth = parseFloat(parts[0]);\r\n const aspectHeight = parseFloat(parts[1]);\r\n if (isNaN(aspectWidth) || isNaN(aspectHeight) || aspectHeight === 0) {\r\n throw new Error(`Invalid aspect ratio: ${aspect}. Use format \"width:height\" (e.g., \"3.5:2\")`);\r\n }\r\n\r\n // Scale so height fits tape, width is proportional\r\n const height = tapeHeight;\r\n const width = Math.round(tapeHeight * (aspectWidth / aspectHeight));\r\n return { width, height };\r\n}\r\n\r\n// Validation\r\nfunction validateOptions(options: PrintOptions): void {\r\n const contentFields = [\r\n options.text,\r\n options.html,\r\n options.htmlPath,\r\n options.textFile,\r\n options.imagePath,\r\n options.imageBuffer,\r\n options.qr,\r\n ].filter(f => f !== undefined);\r\n\r\n if (contentFields.length === 0) {\r\n throw new Error(\"No content provided. Specify one of: text, html, htmlPath, textFile, imagePath, imageBuffer, qr\");\r\n }\r\n if (contentFields.length > 1) {\r\n throw new Error(\"Multiple content options provided. Specify exactly one.\");\r\n }\r\n\r\n if (options.tape !== undefined && !TAPE_SIZES[options.tape]) {\r\n throw new Error(`Invalid tape size: ${options.tape}. Valid sizes: 6, 9, 12, 18, 24`);\r\n }\r\n}\r\n\r\n// Resolve effective settings from options + config + defaults\r\nfunction resolveSettings(options: PrintOptions): { tape: TapeSize; printer: string } {\r\n const config = getConfig();\r\n return {\r\n tape: options.tape ?? config.defaultTape ?? 24,\r\n printer: options.printer ?? config.defaultPrinter ?? DEFAULT_PRINTER,\r\n };\r\n}\r\n\r\n// Render text to image buffer\r\nasync function renderText(text: string, tape: TapeSize): Promise<Buffer> {\r\n const tapeSize = TAPE_SIZES[tape];\r\n const targetHeight = tapeSize.height;\r\n const lines = text.split(\"\\\\n\").join(\"\\n\");\r\n\r\n // Load largest font for quality\r\n const fontDir = path.join(path.dirname(new URL(import.meta.url).pathname).replace(/^\\/([A-Z]:)/, \"$1\"), \"node_modules/@jimp/plugin-print/fonts/open-sans\");\r\n const fontPath = path.join(fontDir, \"open-sans-128-black\", \"open-sans-128-black.fnt\");\r\n const font = await loadFont(fontPath);\r\n\r\n // Measure text\r\n const textWidth = measureText(font, lines);\r\n const textHeight = measureTextHeight(font, lines, textWidth + 100);\r\n\r\n // Create temp image for text\r\n const padding = 10;\r\n const imgWidth = textWidth + padding * 2;\r\n const imgHeight = textHeight + padding * 2;\r\n\r\n const tempImage = new Jimp({ width: imgWidth, height: imgHeight, color: 0xffffffff });\r\n tempImage.print({ font, x: padding, y: padding, text: lines });\r\n\r\n // Scale to fit tape height\r\n const scale = targetHeight / imgHeight;\r\n const finalWidth = Math.round(imgWidth * scale);\r\n const finalHeight = Math.round(imgHeight * scale);\r\n tempImage.resize({ w: finalWidth, h: finalHeight });\r\n\r\n // Create final image with padding\r\n const hPadding = Math.round(targetHeight * 0.2);\r\n const outputWidth = finalWidth + hPadding * 2;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n\r\n const xOffset = hPadding;\r\n const yOffset = Math.round((targetHeight - finalHeight) / 2);\r\n image.composite(tempImage, xOffset, yOffset);\r\n\r\n return image.getBuffer(\"image/png\");\r\n}\r\n\r\n// Render QR code to image buffer\r\nasync function renderQr(data: string, tape: TapeSize, labelText?: string): Promise<Buffer> {\r\n const tapeSize = TAPE_SIZES[tape];\r\n const targetHeight = tapeSize.height;\r\n const qrSize = Math.floor(targetHeight * 0.95);\r\n\r\n // Margins in pixels at PRINT_DPI (3mm left, 4mm right)\r\n const pxPerMm = PRINT_DPI / 25.4;\r\n const leftMargin = Math.round(3 * pxPerMm);\r\n const rightMargin = Math.round(4 * pxPerMm);\r\n\r\n // Generate QR code at high resolution\r\n const qrBuffer = await QRCode.toBuffer(data, {\r\n type: \"png\",\r\n width: qrSize,\r\n margin: 0,\r\n errorCorrectionLevel: \"M\",\r\n color: { dark: \"#000000\", light: \"#ffffff\" },\r\n });\r\n\r\n const qrImage = await Jimp.read(qrBuffer);\r\n\r\n if (!labelText) {\r\n // QR only\r\n const outputWidth = leftMargin + qrSize + rightMargin;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n const yOffset = Math.floor((targetHeight - qrSize) / 2);\r\n image.composite(qrImage, leftMargin, yOffset);\r\n return image.getBuffer(\"image/png\");\r\n }\r\n\r\n // QR + text label\r\n const fontDir = path.join(path.dirname(new URL(import.meta.url).pathname).replace(/^\\/([A-Z]:)/, \"$1\"), \"node_modules/@jimp/plugin-print/fonts/open-sans\");\r\n const fontPath = path.join(fontDir, \"open-sans-64-black\", \"open-sans-64-black.fnt\");\r\n const font = await loadFont(fontPath);\r\n\r\n const textWidth = measureText(font, labelText);\r\n const textHeight = measureTextHeight(font, labelText, textWidth + 50);\r\n\r\n // Scale text to fit beside QR\r\n const maxTextHeight = targetHeight * 0.8;\r\n const textScale = Math.min(1, maxTextHeight / textHeight);\r\n const scaledTextWidth = Math.round(textWidth * textScale);\r\n const scaledTextHeight = Math.round(textHeight * textScale);\r\n\r\n // Create text image\r\n const textImg = new Jimp({ width: textWidth + 20, height: textHeight + 20, color: 0xffffffff });\r\n textImg.print({ font, x: 10, y: 10, text: labelText });\r\n if (textScale < 1) {\r\n textImg.resize({ w: scaledTextWidth, h: scaledTextHeight });\r\n }\r\n\r\n // Compose: QR on left, text on right\r\n const gap = Math.floor(targetHeight * 0.15);\r\n const outputWidth = leftMargin + qrSize + gap + scaledTextWidth + rightMargin;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n\r\n const qrY = Math.floor((targetHeight - qrSize) / 2);\r\n image.composite(qrImage, leftMargin, qrY);\r\n\r\n const textY = Math.floor((targetHeight - scaledTextHeight) / 2);\r\n image.composite(textImg, leftMargin + qrSize + gap, textY);\r\n\r\n return image.getBuffer(\"image/png\");\r\n}\r\n\r\n// Render content to image buffer\r\nasync function renderContent(options: PrintOptions, tape: TapeSize): Promise<Buffer> {\r\n const tapeSize = TAPE_SIZES[tape];\r\n\r\n if (options.text !== undefined) {\r\n return renderText(options.text, tape);\r\n }\r\n\r\n if (options.textFile !== undefined) {\r\n const text = fs.readFileSync(options.textFile, \"utf-8\");\r\n return renderText(text, tape);\r\n }\r\n\r\n if (options.html !== undefined) {\r\n const { width, height } = getHtmlDimensions(tapeSize.height, options.aspect);\r\n const buffer = await renderHtmlString(options.html, { width, height, tapeMm: tape }, options.basePath);\r\n await closeBrowser();\r\n return buffer;\r\n }\r\n\r\n if (options.htmlPath !== undefined) {\r\n const { width, height } = getHtmlDimensions(tapeSize.height, options.aspect);\r\n const buffer = await renderHtmlFile(options.htmlPath, { width, height, tapeMm: tape });\r\n await closeBrowser();\r\n return buffer;\r\n }\r\n\r\n if (options.imagePath !== undefined) {\r\n return fs.readFileSync(options.imagePath);\r\n }\r\n\r\n if (options.imageBuffer !== undefined) {\r\n return options.imageBuffer;\r\n }\r\n\r\n if (options.qr !== undefined) {\r\n return renderQr(options.qr, tape, options.qrLabel);\r\n }\r\n\r\n throw new Error(\"No content to render\");\r\n}\r\n\r\n// Print single image buffer to printer\r\nasync function printBuffer(imageBuffer: Buffer, printer: string, tape: TapeSize): Promise<void> {\r\n const media = MEDIA_OPTIONS[tape];\r\n\r\n const tempPath = path.join(os.tmpdir(), `label-${Date.now()}.png`);\r\n fs.writeFileSync(tempPath, imageBuffer);\r\n\r\n try {\r\n await new Promise<void>((resolve, reject) => {\r\n const psScript = `\r\nAdd-Type -AssemblyName System.Drawing\r\nAdd-Type -AssemblyName System.Printing\r\nAdd-Type -AssemblyName ReachFramework\r\nAdd-Type -AssemblyName PresentationCore\r\n\r\n$img = [System.Drawing.Image]::FromFile('${tempPath.replace(/\\\\/g, \"\\\\\\\\\")}')\r\n\r\n$DPI = ${PRINT_DPI}\r\n$MICRONS_PER_INCH = 25400\r\n\r\n$labelLengthMicrons = [int]($img.Width / $DPI * $MICRONS_PER_INCH) + 3000 # +2mm offset +1mm buffer\r\n$tapeWidthMicrons = ${media.width}\r\n\r\n$imgWidthWpf = $img.Width / $DPI * 96\r\n$imgHeightWpf = $img.Height / $DPI * 96\r\n\r\n$ticketXml = @\"\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<psf:PrintTicket xmlns:psf=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework\"\r\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"1\"\r\n xmlns:psk=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords\"\r\n xmlns:ns0001=\"http://schemas.brother.info/mfc/printing/2006/11/printschemakeywords\">\r\n <psf:Feature name=\"psk:PageMediaSize\">\r\n <psf:Option name=\"ns0001:${media.name}\">\r\n <psf:ScoredProperty name=\"psk:MediaSizeWidth\">\r\n <psf:Value xsi:type=\"xsd:integer\">${media.width}</psf:Value>\r\n </psf:ScoredProperty>\r\n <psf:ScoredProperty name=\"psk:MediaSizeHeight\">\r\n <psf:ParameterRef name=\"psk:PageMediaSizeMediaSizeHeight\" />\r\n </psf:ScoredProperty>\r\n </psf:Option>\r\n </psf:Feature>\r\n <psf:ParameterInit name=\"psk:PageMediaSizeMediaSizeHeight\">\r\n <psf:Value xsi:type=\"xsd:integer\">$labelLengthMicrons</psf:Value>\r\n </psf:ParameterInit>\r\n <psf:Feature name=\"psk:PageOrientation\">\r\n <psf:Option name=\"psk:Landscape\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"ns0001:PageRollFeedToEndOfSheet\">\r\n <psf:Option name=\"ns0001:FeedToImageEdge\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"psk:PageMediaType\">\r\n <psf:Option name=\"psk:Label\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"ns0001:JobRollCutAtEndOfJob\">\r\n <psf:Option name=\"ns0001:Cut\" />\r\n </psf:Feature>\r\n</psf:PrintTicket>\r\n\"@\r\n\r\n$xmlBytes = [System.Text.Encoding]::UTF8.GetBytes($ticketXml)\r\n$memStream = New-Object System.IO.MemoryStream(,$xmlBytes)\r\n$ticket = New-Object System.Printing.PrintTicket($memStream)\r\n\r\n$server = New-Object System.Printing.LocalPrintServer\r\n$queue = $server.GetPrintQueue('${printer}')\r\n\r\n$xpsPath = [System.IO.Path]::GetTempFileName() + \".xps\"\r\n\r\n$pageWidth = $labelLengthMicrons / $MICRONS_PER_INCH * 96\r\n$pageHeight = $tapeWidthMicrons / $MICRONS_PER_INCH * 96\r\n\r\n$package = [System.IO.Packaging.Package]::Open($xpsPath, [System.IO.FileMode]::Create)\r\n$xpsDoc = New-Object System.Windows.Xps.Packaging.XpsDocument($package)\r\n$writer = [System.Windows.Xps.Packaging.XpsDocument]::CreateXpsDocumentWriter($xpsDoc)\r\n\r\n$visual = New-Object System.Windows.Media.DrawingVisual\r\n$dc = $visual.RenderOpen()\r\n\r\n$bitmapImg = New-Object System.Windows.Media.Imaging.BitmapImage\r\n$bitmapImg.BeginInit()\r\n$bitmapImg.UriSource = New-Object System.Uri('${tempPath.replace(/\\\\/g, \"\\\\\\\\\")}')\r\n$bitmapImg.EndInit()\r\n\r\n$yOffset = ($pageHeight - $imgHeightWpf) / 2\r\n$xOffset = 2 / 25.4 * 96 # 2mm left margin in WPF units\r\n$rect = New-Object System.Windows.Rect($xOffset, $yOffset, $imgWidthWpf, $imgHeightWpf)\r\n$dc.DrawImage($bitmapImg, $rect)\r\n$dc.Close()\r\n\r\n$writer.Write($visual, $ticket)\r\n\r\n$xpsDoc.Close()\r\n$package.Close()\r\n$img.Dispose()\r\n\r\n$xpsDocForPrint = New-Object System.Windows.Xps.Packaging.XpsDocument($xpsPath, [System.IO.FileAccess]::Read)\r\n$seq = $xpsDocForPrint.GetFixedDocumentSequence()\r\n\r\n$xpsWriter = [System.Printing.PrintQueue]::CreateXpsDocumentWriter($queue)\r\n$xpsWriter.Write($seq, $ticket)\r\n\r\n$xpsDocForPrint.Close()\r\nRemove-Item $xpsPath -ErrorAction SilentlyContinue\r\n`;\r\n\r\n const ps = spawn(\"powershell\", [\"-Command\", psScript], { stdio: \"pipe\" });\r\n\r\n let stdout = \"\";\r\n let stderr = \"\";\r\n ps.stdout.on(\"data\", (data) => { stdout += data.toString(); });\r\n ps.stderr.on(\"data\", (data) => { stderr += data.toString(); });\r\n\r\n ps.on(\"close\", (code) => {\r\n if (code === 0) {\r\n resolve();\r\n } else {\r\n reject(new Error(`Print failed: ${stderr}`));\r\n }\r\n });\r\n\r\n ps.on(\"error\", (err) => {\r\n reject(new Error(`Failed to print: ${err.message}`));\r\n });\r\n });\r\n } finally {\r\n if (fs.existsSync(tempPath)) {\r\n fs.unlinkSync(tempPath);\r\n }\r\n }\r\n}\r\n\r\n// Main API functions\r\nexport async function render(options: PrintOptions): Promise<Buffer> {\r\n validateOptions(options);\r\n const { tape } = resolveSettings(options);\r\n return renderContent(options, tape);\r\n}\r\n\r\nexport async function print(options: PrintOptions): Promise<PrintResult> {\r\n validateOptions(options);\r\n const { tape, printer } = resolveSettings(options);\r\n const image = await renderContent(options, tape);\r\n await printBuffer(image, printer, tape);\r\n return { image };\r\n}\r\n"]}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Brother Label Printer API\r\n * Programmatic interface for printing labels on Brother P-touch printers\r\n */\r\n\r\nimport * as fs from \"fs\";\r\nimport * as path from \"path\";\r\nimport { fileURLToPath } from \"url\";\r\nimport * as os from \"os\";\r\nimport { renderHtmlFile, renderHtmlString, closeBrowser } from \"./render.js\";\r\nimport { Jimp, loadFont, measureText, measureTextHeight } from \"jimp\";\r\nimport { spawn } from \"child_process\";\r\nimport QRCode from \"qrcode\";\r\n\r\n// Types\r\nexport type TapeSize = 6 | 9 | 12 | 18 | 24;\r\nexport type Orientation = \"landscape\" | \"portrait\";\r\n\r\nexport interface PrinterConfig {\r\n defaultTape?: TapeSize;\r\n defaultPrinter?: string;\r\n}\r\n\r\nexport interface PrinterInfo {\r\n name: string;\r\n}\r\n\r\nexport interface PrintOptions {\r\n // Content (exactly one required)\r\n text?: string;\r\n html?: string;\r\n htmlPath?: string;\r\n textFile?: string;\r\n imagePath?: string;\r\n imageBuffer?: Buffer;\r\n qr?: string; // QR code data to encode\r\n\r\n // Settings\r\n tape?: TapeSize;\r\n printer?: string;\r\n orientation?: Orientation;\r\n length?: number; // explicit length in mm\r\n basePath?: string; // base path for inline HTML resources\r\n aspect?: string; // width:height ratio for HTML (e.g., \"3.5:2\")\r\n qrLabel?: string; // optional text label beside QR code\r\n}\r\n\r\nexport interface PrintResult {\r\n image: Buffer;\r\n}\r\n\r\n// Constants\r\nconst CONFIG_PATH = path.join(os.homedir(), \".brother-label.json\");\r\nconst DEFAULT_PRINTER = \"Brother PT-P710BT\";\r\nconst PRINT_DPI = 300; // High resolution for quality output\r\n\r\n// Tape sizes: height is printable area in pixels at 300 DPI\r\nconst TAPE_SIZES: Record<TapeSize, { width: number; height: number }> = {\r\n 6: { width: 1137, height: 56 }, // 3.79\" x 0.19\" @ 300 DPI\r\n 9: { width: 1137, height: 84 }, // 3.79\" x 0.28\" @ 300 DPI\r\n 12: { width: 1137, height: 113 }, // 3.79\" x 0.38\" @ 300 DPI\r\n 18: { width: 1137, height: 169 }, // 3.79\" x 0.56\" @ 300 DPI\r\n 24: { width: 1137, height: 213 }, // 3.79\" x 0.71\" @ 300 DPI\r\n};\r\n\r\n// Brother CustomMediaSize names and widths in microns\r\nconst MEDIA_OPTIONS: Record<TapeSize, { name: string; width: number }> = {\r\n 6: { name: \"CustomMediaSize257\", width: 5900 },\r\n 9: { name: \"CustomMediaSize258\", width: 9000 },\r\n 12: { name: \"CustomMediaSize259\", width: 11900 },\r\n 18: { name: \"CustomMediaSize260\", width: 18100 },\r\n 24: { name: \"CustomMediaSize261\", width: 24000 },\r\n};\r\n\r\n// Config functions\r\nexport function getConfig(): PrinterConfig {\r\n try {\r\n if (fs.existsSync(CONFIG_PATH)) {\r\n const raw = JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\r\n // Handle legacy format where tape was stored as \"24mm\" string\r\n if (typeof raw.defaultTape === \"string\") {\r\n raw.defaultTape = parseInt(raw.defaultTape.replace(\"mm\", \"\"), 10) as TapeSize;\r\n }\r\n return raw;\r\n }\r\n } catch {\r\n // Ignore config errors\r\n }\r\n return {};\r\n}\r\n\r\nexport function setConfig(config: Partial<PrinterConfig>): void {\r\n const current = getConfig();\r\n const merged = { ...current, ...config };\r\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2));\r\n}\r\n\r\nexport function getConfigPath(): string {\r\n return CONFIG_PATH;\r\n}\r\n\r\n// Printer listing\r\nexport async function listPrinters(): Promise<PrinterInfo[]> {\r\n return new Promise((resolve, reject) => {\r\n const ps = spawn(\"powershell\", [\r\n \"-Command\",\r\n \"Get-Printer | Where-Object { $_.Name -like '*Brother*' -or $_.Name -like '*PT*' -or $_.Name -like '*QL*' } | Select-Object -ExpandProperty Name\"\r\n ], { stdio: \"pipe\" });\r\n\r\n let stdout = \"\";\r\n let stderr = \"\";\r\n ps.stdout.on(\"data\", (data) => { stdout += data.toString(); });\r\n ps.stderr.on(\"data\", (data) => { stderr += data.toString(); });\r\n\r\n ps.on(\"close\", (code) => {\r\n if (code !== 0) {\r\n reject(new Error(`Failed to list printers: ${stderr}`));\r\n return;\r\n }\r\n const printers = stdout.trim().split(\"\\n\")\r\n .filter(p => p.trim())\r\n .map(name => ({ name: name.trim() }));\r\n resolve(printers);\r\n });\r\n });\r\n}\r\n\r\n// Calculate HTML viewport dimensions from tape height and optional aspect ratio\r\nfunction getHtmlDimensions(tapeHeight: number, aspect?: string): { width?: number; height: number } {\r\n if (!aspect) {\r\n // Auto-detect width from content\r\n return { width: undefined, height: tapeHeight };\r\n }\r\n\r\n // Parse aspect ratio \"width:height\" or \"width/height\" (e.g., \"3.5:2\" or \"3.5/2\")\r\n const separator = aspect.includes(\"/\") ? \"/\" : \":\";\r\n const parts = aspect.split(separator);\r\n if (parts.length !== 2) {\r\n throw new Error(`Invalid aspect ratio: ${aspect}. Use format \"width:height\" or \"width/height\"`);\r\n }\r\n const aspectWidth = parseFloat(parts[0]);\r\n const aspectHeight = parseFloat(parts[1]);\r\n if (isNaN(aspectWidth) || isNaN(aspectHeight) || aspectHeight === 0) {\r\n throw new Error(`Invalid aspect ratio: ${aspect}. Use format \"width:height\" (e.g., \"3.5:2\")`);\r\n }\r\n\r\n // Scale so height fits tape, width is proportional\r\n const height = tapeHeight;\r\n const width = Math.round(tapeHeight * (aspectWidth / aspectHeight));\r\n return { width, height };\r\n}\r\n\r\n// Validation\r\nfunction validateOptions(options: PrintOptions): void {\r\n const contentFields = [\r\n options.text,\r\n options.html,\r\n options.htmlPath,\r\n options.textFile,\r\n options.imagePath,\r\n options.imageBuffer,\r\n options.qr,\r\n ].filter(f => f !== undefined);\r\n\r\n if (contentFields.length === 0) {\r\n throw new Error(\"No content provided. Specify one of: text, html, htmlPath, textFile, imagePath, imageBuffer, qr\");\r\n }\r\n if (contentFields.length > 1) {\r\n throw new Error(\"Multiple content options provided. Specify exactly one.\");\r\n }\r\n\r\n if (options.tape !== undefined && !TAPE_SIZES[options.tape]) {\r\n throw new Error(`Invalid tape size: ${options.tape}. Valid sizes: 6, 9, 12, 18, 24`);\r\n }\r\n}\r\n\r\n// Resolve effective settings from options + config + defaults\r\nfunction resolveSettings(options: PrintOptions): { tape: TapeSize; printer: string } {\r\n const config = getConfig();\r\n return {\r\n tape: options.tape ?? config.defaultTape ?? 24,\r\n printer: options.printer ?? config.defaultPrinter ?? DEFAULT_PRINTER,\r\n };\r\n}\r\n\r\n// Render text to image buffer\r\nasync function renderText(text: string, tape: TapeSize): Promise<Buffer> {\r\n const tapeSize = TAPE_SIZES[tape];\r\n const targetHeight = tapeSize.height;\r\n const lines = text.split(\"\\\\n\").join(\"\\n\");\r\n\r\n // Load largest font for quality\r\n const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), \"node_modules/@jimp/plugin-print/fonts/open-sans\");\r\n const fontPath = path.join(fontDir, \"open-sans-128-black\", \"open-sans-128-black.fnt\");\r\n const font = await loadFont(fontPath);\r\n\r\n // Measure text\r\n const textWidth = measureText(font, lines);\r\n const textHeight = measureTextHeight(font, lines, textWidth + 100);\r\n\r\n // Create temp image for text\r\n const padding = 10;\r\n const imgWidth = textWidth + padding * 2;\r\n const imgHeight = textHeight + padding * 2;\r\n\r\n const tempImage = new Jimp({ width: imgWidth, height: imgHeight, color: 0xffffffff });\r\n tempImage.print({ font, x: padding, y: padding, text: lines });\r\n\r\n // Scale to fit tape height\r\n const scale = targetHeight / imgHeight;\r\n const finalWidth = Math.round(imgWidth * scale);\r\n const finalHeight = Math.round(imgHeight * scale);\r\n tempImage.resize({ w: finalWidth, h: finalHeight });\r\n\r\n // Create final image with padding\r\n const hPadding = Math.round(targetHeight * 0.2);\r\n const outputWidth = finalWidth + hPadding * 2;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n\r\n const xOffset = hPadding;\r\n const yOffset = Math.round((targetHeight - finalHeight) / 2);\r\n image.composite(tempImage, xOffset, yOffset);\r\n\r\n return image.getBuffer(\"image/png\");\r\n}\r\n\r\n// Render QR code to image buffer\r\nasync function renderQr(data: string, tape: TapeSize, labelText?: string): Promise<Buffer> {\r\n const tapeSize = TAPE_SIZES[tape];\r\n const targetHeight = tapeSize.height;\r\n const qrSize = Math.floor(targetHeight * 0.95);\r\n\r\n // Margins in pixels at PRINT_DPI (3mm left, 4mm right)\r\n const pxPerMm = PRINT_DPI / 25.4;\r\n const leftMargin = Math.round(3 * pxPerMm);\r\n const rightMargin = Math.round(4 * pxPerMm);\r\n\r\n // Generate QR code at high resolution\r\n const qrBuffer = await QRCode.toBuffer(data, {\r\n type: \"png\",\r\n width: qrSize,\r\n margin: 0,\r\n errorCorrectionLevel: \"M\",\r\n color: { dark: \"#000000\", light: \"#ffffff\" },\r\n });\r\n\r\n const qrImage = await Jimp.read(qrBuffer);\r\n\r\n if (!labelText) {\r\n // QR only\r\n const outputWidth = leftMargin + qrSize + rightMargin;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n const yOffset = Math.floor((targetHeight - qrSize) / 2);\r\n image.composite(qrImage, leftMargin, yOffset);\r\n return image.getBuffer(\"image/png\");\r\n }\r\n\r\n // QR + text label\r\n const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), \"node_modules/@jimp/plugin-print/fonts/open-sans\");\r\n const fontPath = path.join(fontDir, \"open-sans-64-black\", \"open-sans-64-black.fnt\");\r\n const font = await loadFont(fontPath);\r\n\r\n const textWidth = measureText(font, labelText);\r\n const textHeight = measureTextHeight(font, labelText, textWidth + 50);\r\n\r\n // Scale text to fit beside QR\r\n const maxTextHeight = targetHeight * 0.8;\r\n const textScale = Math.min(1, maxTextHeight / textHeight);\r\n const scaledTextWidth = Math.round(textWidth * textScale);\r\n const scaledTextHeight = Math.round(textHeight * textScale);\r\n\r\n // Create text image\r\n const textImg = new Jimp({ width: textWidth + 20, height: textHeight + 20, color: 0xffffffff });\r\n textImg.print({ font, x: 10, y: 10, text: labelText });\r\n if (textScale < 1) {\r\n textImg.resize({ w: scaledTextWidth, h: scaledTextHeight });\r\n }\r\n\r\n // Compose: QR on left, text on right\r\n const gap = Math.floor(targetHeight * 0.15);\r\n const outputWidth = leftMargin + qrSize + gap + scaledTextWidth + rightMargin;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n\r\n const qrY = Math.floor((targetHeight - qrSize) / 2);\r\n image.composite(qrImage, leftMargin, qrY);\r\n\r\n const textY = Math.floor((targetHeight - scaledTextHeight) / 2);\r\n image.composite(textImg, leftMargin + qrSize + gap, textY);\r\n\r\n return image.getBuffer(\"image/png\");\r\n}\r\n\r\n// Render content to image buffer\r\nasync function renderContent(options: PrintOptions, tape: TapeSize): Promise<Buffer> {\r\n const tapeSize = TAPE_SIZES[tape];\r\n\r\n if (options.text !== undefined) {\r\n return renderText(options.text, tape);\r\n }\r\n\r\n if (options.textFile !== undefined) {\r\n const text = fs.readFileSync(options.textFile, \"utf-8\");\r\n return renderText(text, tape);\r\n }\r\n\r\n if (options.html !== undefined) {\r\n const { width, height } = getHtmlDimensions(tapeSize.height, options.aspect);\r\n const buffer = await renderHtmlString(options.html, { width, height, tapeMm: tape }, options.basePath);\r\n await closeBrowser();\r\n return buffer;\r\n }\r\n\r\n if (options.htmlPath !== undefined) {\r\n const { width, height } = getHtmlDimensions(tapeSize.height, options.aspect);\r\n const buffer = await renderHtmlFile(options.htmlPath, { width, height, tapeMm: tape });\r\n await closeBrowser();\r\n return buffer;\r\n }\r\n\r\n if (options.imagePath !== undefined) {\r\n return fs.readFileSync(options.imagePath);\r\n }\r\n\r\n if (options.imageBuffer !== undefined) {\r\n return options.imageBuffer;\r\n }\r\n\r\n if (options.qr !== undefined) {\r\n return renderQr(options.qr, tape, options.qrLabel);\r\n }\r\n\r\n throw new Error(\"No content to render\");\r\n}\r\n\r\n// Print single image buffer to printer\r\nasync function printBuffer(imageBuffer: Buffer, printer: string, tape: TapeSize): Promise<void> {\r\n const media = MEDIA_OPTIONS[tape];\r\n\r\n const tempPath = path.join(os.tmpdir(), `label-${Date.now()}.png`);\r\n fs.writeFileSync(tempPath, imageBuffer);\r\n\r\n try {\r\n await new Promise<void>((resolve, reject) => {\r\n const psScript = `\r\nAdd-Type -AssemblyName System.Drawing\r\nAdd-Type -AssemblyName System.Printing\r\nAdd-Type -AssemblyName ReachFramework\r\nAdd-Type -AssemblyName PresentationCore\r\n\r\n$img = [System.Drawing.Image]::FromFile('${tempPath.replace(/\\\\/g, \"\\\\\\\\\")}')\r\n\r\n$DPI = ${PRINT_DPI}\r\n$MICRONS_PER_INCH = 25400\r\n\r\n$labelLengthMicrons = [int]($img.Width / $DPI * $MICRONS_PER_INCH) + 3000 # +2mm offset +1mm buffer\r\n$tapeWidthMicrons = ${media.width}\r\n\r\n$imgWidthWpf = $img.Width / $DPI * 96\r\n$imgHeightWpf = $img.Height / $DPI * 96\r\n\r\n$ticketXml = @\"\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<psf:PrintTicket xmlns:psf=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework\"\r\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"1\"\r\n xmlns:psk=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords\"\r\n xmlns:ns0001=\"http://schemas.brother.info/mfc/printing/2006/11/printschemakeywords\">\r\n <psf:Feature name=\"psk:PageMediaSize\">\r\n <psf:Option name=\"ns0001:${media.name}\">\r\n <psf:ScoredProperty name=\"psk:MediaSizeWidth\">\r\n <psf:Value xsi:type=\"xsd:integer\">${media.width}</psf:Value>\r\n </psf:ScoredProperty>\r\n <psf:ScoredProperty name=\"psk:MediaSizeHeight\">\r\n <psf:ParameterRef name=\"psk:PageMediaSizeMediaSizeHeight\" />\r\n </psf:ScoredProperty>\r\n </psf:Option>\r\n </psf:Feature>\r\n <psf:ParameterInit name=\"psk:PageMediaSizeMediaSizeHeight\">\r\n <psf:Value xsi:type=\"xsd:integer\">$labelLengthMicrons</psf:Value>\r\n </psf:ParameterInit>\r\n <psf:Feature name=\"psk:PageOrientation\">\r\n <psf:Option name=\"psk:Landscape\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"ns0001:PageRollFeedToEndOfSheet\">\r\n <psf:Option name=\"ns0001:FeedToImageEdge\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"psk:PageMediaType\">\r\n <psf:Option name=\"psk:Label\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"ns0001:JobRollCutAtEndOfJob\">\r\n <psf:Option name=\"ns0001:Cut\" />\r\n </psf:Feature>\r\n</psf:PrintTicket>\r\n\"@\r\n\r\n$xmlBytes = [System.Text.Encoding]::UTF8.GetBytes($ticketXml)\r\n$memStream = New-Object System.IO.MemoryStream(,$xmlBytes)\r\n$ticket = New-Object System.Printing.PrintTicket($memStream)\r\n\r\n$server = New-Object System.Printing.LocalPrintServer\r\n$queue = $server.GetPrintQueue('${printer}')\r\n\r\n$xpsPath = [System.IO.Path]::GetTempFileName() + \".xps\"\r\n\r\n$pageWidth = $labelLengthMicrons / $MICRONS_PER_INCH * 96\r\n$pageHeight = $tapeWidthMicrons / $MICRONS_PER_INCH * 96\r\n\r\n$package = [System.IO.Packaging.Package]::Open($xpsPath, [System.IO.FileMode]::Create)\r\n$xpsDoc = New-Object System.Windows.Xps.Packaging.XpsDocument($package)\r\n$writer = [System.Windows.Xps.Packaging.XpsDocument]::CreateXpsDocumentWriter($xpsDoc)\r\n\r\n$visual = New-Object System.Windows.Media.DrawingVisual\r\n$dc = $visual.RenderOpen()\r\n\r\n$bitmapImg = New-Object System.Windows.Media.Imaging.BitmapImage\r\n$bitmapImg.BeginInit()\r\n$bitmapImg.UriSource = New-Object System.Uri('${tempPath.replace(/\\\\/g, \"\\\\\\\\\")}')\r\n$bitmapImg.EndInit()\r\n\r\n$yOffset = ($pageHeight - $imgHeightWpf) / 2\r\n$xOffset = 2 / 25.4 * 96 # 2mm left margin in WPF units\r\n$rect = New-Object System.Windows.Rect($xOffset, $yOffset, $imgWidthWpf, $imgHeightWpf)\r\n$dc.DrawImage($bitmapImg, $rect)\r\n$dc.Close()\r\n\r\n$writer.Write($visual, $ticket)\r\n\r\n$xpsDoc.Close()\r\n$package.Close()\r\n$img.Dispose()\r\n\r\n$xpsDocForPrint = New-Object System.Windows.Xps.Packaging.XpsDocument($xpsPath, [System.IO.FileAccess]::Read)\r\n$seq = $xpsDocForPrint.GetFixedDocumentSequence()\r\n\r\n$xpsWriter = [System.Printing.PrintQueue]::CreateXpsDocumentWriter($queue)\r\n$xpsWriter.Write($seq, $ticket)\r\n\r\n$xpsDocForPrint.Close()\r\nRemove-Item $xpsPath -ErrorAction SilentlyContinue\r\n`;\r\n\r\n const ps = spawn(\"powershell\", [\"-Command\", psScript], { stdio: \"pipe\" });\r\n\r\n let stdout = \"\";\r\n let stderr = \"\";\r\n ps.stdout.on(\"data\", (data) => { stdout += data.toString(); });\r\n ps.stderr.on(\"data\", (data) => { stderr += data.toString(); });\r\n\r\n ps.on(\"close\", (code) => {\r\n if (code === 0) {\r\n resolve();\r\n } else {\r\n reject(new Error(`Print failed: ${stderr}`));\r\n }\r\n });\r\n\r\n ps.on(\"error\", (err) => {\r\n reject(new Error(`Failed to print: ${err.message}`));\r\n });\r\n });\r\n } finally {\r\n if (fs.existsSync(tempPath)) {\r\n fs.unlinkSync(tempPath);\r\n }\r\n }\r\n}\r\n\r\n// Main API functions\r\nexport async function render(options: PrintOptions): Promise<Buffer> {\r\n validateOptions(options);\r\n const { tape } = resolveSettings(options);\r\n return renderContent(options, tape);\r\n}\r\n\r\nexport async function print(options: PrintOptions): Promise<PrintResult> {\r\n validateOptions(options);\r\n const { tape, printer } = resolveSettings(options);\r\n const image = await renderContent(options, tape);\r\n await printBuffer(image, printer, tape);\r\n return { image };\r\n}\r\n"]}
package/api.ts CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  import * as fs from "fs";
7
7
  import * as path from "path";
8
+ import { fileURLToPath } from "url";
8
9
  import * as os from "os";
9
10
  import { renderHtmlFile, renderHtmlString, closeBrowser } from "./render.js";
10
11
  import { Jimp, loadFont, measureText, measureTextHeight } from "jimp";
@@ -189,7 +190,7 @@ async function renderText(text: string, tape: TapeSize): Promise<Buffer> {
189
190
  const lines = text.split("\\n").join("\n");
190
191
 
191
192
  // Load largest font for quality
192
- const fontDir = path.join(path.dirname(new URL(import.meta.url).pathname).replace(/^\/([A-Z]:)/, "$1"), "node_modules/@jimp/plugin-print/fonts/open-sans");
193
+ const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "node_modules/@jimp/plugin-print/fonts/open-sans");
193
194
  const fontPath = path.join(fontDir, "open-sans-128-black", "open-sans-128-black.fnt");
194
195
  const font = await loadFont(fontPath);
195
196
 
@@ -255,7 +256,7 @@ async function renderQr(data: string, tape: TapeSize, labelText?: string): Promi
255
256
  }
256
257
 
257
258
  // QR + text label
258
- const fontDir = path.join(path.dirname(new URL(import.meta.url).pathname).replace(/^\/([A-Z]:)/, "$1"), "node_modules/@jimp/plugin-print/fonts/open-sans");
259
+ const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "node_modules/@jimp/plugin-print/fonts/open-sans");
259
260
  const fontPath = path.join(fontDir, "open-sans-64-black", "open-sans-64-black.fnt");
260
261
  const font = await loadFont(fontPath);
261
262
 
package/brother-print.js CHANGED
@@ -4,10 +4,10 @@ import { program } from "commander";
4
4
  import { exec, spawn } from "child_process";
5
5
  import * as fs from "fs";
6
6
  import * as path from "path";
7
+ import { fileURLToPath } from "url";
7
8
  import * as os from "os";
8
9
  import { renderHtmlFile, closeBrowser } from "./render.js";
9
10
  import QRCode from "qrcode";
10
- const __dirname = import.meta.dirname;
11
11
  const CONFIG_PATH = path.join(os.homedir(), ".brother-label.json");
12
12
  function loadConfig() {
13
13
  try {
@@ -26,7 +26,7 @@ function saveConfig(config) {
26
26
  // Available font sizes in jimp
27
27
  const FONT_SIZES = [128, 64, 32, 16, 14, 12, 10, 8];
28
28
  async function loadFontBySize(size) {
29
- const fontDir = path.join(__dirname, "node_modules/@jimp/plugin-print/fonts/open-sans");
29
+ const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "node_modules/@jimp/plugin-print/fonts/open-sans");
30
30
  const fontFolder = `open-sans-${size}-black`;
31
31
  const fontPath = path.join(fontDir, fontFolder, `${fontFolder}.fnt`);
32
32
  return loadFont(fontPath);
@@ -1 +1 @@
1
- {"version":3,"file":"brother-print.js","sourceRoot":"","sources":["brother-print.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\r\nimport { Jimp, loadFont, measureText, measureTextHeight, HorizontalAlign, VerticalAlign } from \"jimp\";\r\nimport { program } from \"commander\";\r\nimport { exec, spawn } from \"child_process\";\r\nimport * as fs from \"fs\";\r\nimport * as path from \"path\";\r\nimport * as os from \"os\";\r\nimport { renderHtmlFile, closeBrowser } from \"./render.js\";\r\nimport QRCode from \"qrcode\";\r\n\r\nconst __dirname = import.meta.dirname;\r\n\r\ninterface PrintOptions {\r\n printer: string;\r\n fontSize: number;\r\n width: number;\r\n height: number;\r\n tapeMm: number;\r\n}\r\n\r\ninterface Config {\r\n defaultTape?: string;\r\n defaultPrinter?: string;\r\n}\r\n\r\nconst CONFIG_PATH = path.join(os.homedir(), \".brother-label.json\");\r\n\r\nfunction loadConfig(): Config {\r\n try {\r\n if (fs.existsSync(CONFIG_PATH)) {\r\n return JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\r\n }\r\n } catch (err) {\r\n // Ignore config errors\r\n }\r\n return {};\r\n}\r\n\r\nfunction saveConfig(config: Config): void {\r\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));\r\n}\r\n\r\n// Available font sizes in jimp\r\nconst FONT_SIZES = [128, 64, 32, 16, 14, 12, 10, 8];\r\n\r\nasync function loadFontBySize(size: number): Promise<any> {\r\n const fontDir = path.join(__dirname, \"node_modules/@jimp/plugin-print/fonts/open-sans\");\r\n const fontFolder = `open-sans-${size}-black`;\r\n const fontPath = path.join(fontDir, fontFolder, `${fontFolder}.fnt`);\r\n return loadFont(fontPath);\r\n}\r\n\r\nasync function createLabelImage(text: string, options: PrintOptions): Promise<Buffer> {\r\n const lines = text.split(\"\\\\n\").join(\"\\n\");\r\n const targetHeight = options.height;\r\n\r\n // Use largest font for best quality, then scale down\r\n let font = await loadFontBySize(128);\r\n\r\n // Render text at large size first\r\n const textWidth = measureText(font, lines);\r\n const textHeight = measureTextHeight(font, lines, textWidth + 100);\r\n\r\n // Create image for text with small padding\r\n const padding = 10;\r\n const imgWidth = textWidth + padding * 2;\r\n const imgHeight = textHeight + padding * 2;\r\n\r\n const tempImage = new Jimp({ width: imgWidth, height: imgHeight, color: 0xffffffff });\r\n\r\n tempImage.print({\r\n font: font,\r\n x: padding,\r\n y: padding,\r\n text: lines,\r\n });\r\n\r\n // Scale to fit tape height (tape sizes already account for printable area)\r\n const scale = targetHeight / imgHeight;\r\n const finalWidth = Math.round(imgWidth * scale);\r\n const finalHeight = Math.round(imgHeight * scale);\r\n\r\n tempImage.resize({ w: finalWidth, h: finalHeight });\r\n\r\n // Create final image sized to content with small horizontal padding\r\n const hPadding = Math.round(targetHeight * 0.2); // ~20% of height as side margins\r\n const outputWidth = finalWidth + hPadding * 2;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n\r\n // Center both horizontally and vertically\r\n const xOffset = hPadding;\r\n const yOffset = Math.round((targetHeight - finalHeight) / 2);\r\n image.composite(tempImage, xOffset, yOffset);\r\n\r\n return image.getBuffer(\"image/png\");\r\n}\r\n\r\nasync function createQrLabelImage(data: string, options: PrintOptions, labelText?: string): Promise<Buffer> {\r\n const targetHeight = options.height;\r\n const qrSize = Math.floor(targetHeight * 0.95); // QR code is 95% of tape height\r\n\r\n // Margins in mm converted to pixels at PRINT_DPI\r\n // Left margin ~2mm, right margin ~4mm to account for printer feed\r\n const pxPerMm = PRINT_DPI / 25.4;\r\n const leftMargin = Math.round(2 * pxPerMm);\r\n const rightMargin = Math.round(4 * pxPerMm);\r\n\r\n // Generate QR code as PNG buffer at high resolution\r\n const qrBuffer = await QRCode.toBuffer(data, {\r\n type: \"png\",\r\n width: qrSize,\r\n margin: 0,\r\n errorCorrectionLevel: \"M\",\r\n color: { dark: \"#000000\", light: \"#ffffff\" },\r\n });\r\n\r\n const qrImage = await Jimp.read(qrBuffer);\r\n\r\n if (!labelText) {\r\n // QR only - create minimal label with margins\r\n const outputWidth = leftMargin + qrSize + rightMargin;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n const yOffset = Math.floor((targetHeight - qrSize) / 2);\r\n image.composite(qrImage, leftMargin, yOffset);\r\n return image.getBuffer(\"image/png\");\r\n }\r\n\r\n // QR + text label\r\n const font = await loadFontBySize(64);\r\n const textWidth = measureText(font, labelText);\r\n const textHeight = measureTextHeight(font, labelText, textWidth + 50);\r\n\r\n // Scale text to fit beside QR\r\n const maxTextHeight = targetHeight * 0.8;\r\n const textScale = Math.min(1, maxTextHeight / textHeight);\r\n const scaledTextWidth = Math.round(textWidth * textScale);\r\n const scaledTextHeight = Math.round(textHeight * textScale);\r\n\r\n // Create text image\r\n const textImg = new Jimp({ width: textWidth + 20, height: textHeight + 20, color: 0xffffffff });\r\n textImg.print({ font, x: 10, y: 10, text: labelText });\r\n if (textScale < 1) {\r\n textImg.resize({ w: scaledTextWidth, h: scaledTextHeight });\r\n }\r\n\r\n // Compose final image: QR on left, text on right\r\n const gap = Math.floor(targetHeight * 0.15);\r\n const outputWidth = leftMargin + qrSize + gap + scaledTextWidth + rightMargin;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n\r\n const qrY = Math.floor((targetHeight - qrSize) / 2);\r\n image.composite(qrImage, leftMargin, qrY);\r\n\r\n const textY = Math.floor((targetHeight - scaledTextHeight) / 2);\r\n image.composite(textImg, leftMargin + qrSize + gap, textY);\r\n\r\n return image.getBuffer(\"image/png\");\r\n}\r\n\r\nasync function printImage(imagePath: string, printerName: string, tapeMm: number): Promise<void> {\r\n // Map tape mm to Brother CustomMediaSize for PrintTicket\r\n const mediaOptions: Record<number, { name: string; width: number }> = {\r\n 6: { name: \"CustomMediaSize257\", width: 5900 },\r\n 9: { name: \"CustomMediaSize258\", width: 9000 },\r\n 12: { name: \"CustomMediaSize259\", width: 11900 },\r\n 18: { name: \"CustomMediaSize260\", width: 18100 },\r\n 24: { name: \"CustomMediaSize261\", width: 24000 },\r\n };\r\n const media = mediaOptions[tapeMm] || mediaOptions[12];\r\n\r\n return new Promise((resolve, reject) => {\r\n const psScript = `\r\nAdd-Type -AssemblyName System.Drawing\r\nAdd-Type -AssemblyName System.Printing\r\nAdd-Type -AssemblyName ReachFramework\r\nAdd-Type -AssemblyName PresentationCore\r\n\r\n$img = [System.Drawing.Image]::FromFile('${imagePath.replace(/\\\\/g, \"\\\\\\\\\")}')\r\n\r\n# Calculate label dimensions in microns (using ${PRINT_DPI} DPI source images)\r\n$labelLengthMicrons = [int]($img.Width / ${PRINT_DPI}.0 * 25400) + 3000\r\n$tapeWidthMicrons = ${media.width}\r\n\r\n# Image dimensions in WPF units (1/96 inch) - convert from ${PRINT_DPI} DPI source\r\n$imgWidthWpf = $img.Width / ${PRINT_DPI}.0 * 96\r\n$imgHeightWpf = $img.Height / ${PRINT_DPI}.0 * 96\r\n\r\nWrite-Host \"Using ${tapeMm}mm tape, label length: $([int]($labelLengthMicrons/1000))mm\"\r\n\r\n# Build PrintTicket XML\r\n$ticketXml = @\"\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<psf:PrintTicket xmlns:psf=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework\"\r\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"1\"\r\n xmlns:psk=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords\"\r\n xmlns:ns0001=\"http://schemas.brother.info/mfc/printing/2006/11/printschemakeywords\">\r\n <psf:Feature name=\"psk:PageMediaSize\">\r\n <psf:Option name=\"ns0001:${media.name}\">\r\n <psf:ScoredProperty name=\"psk:MediaSizeWidth\">\r\n <psf:Value xsi:type=\"xsd:integer\">${media.width}</psf:Value>\r\n </psf:ScoredProperty>\r\n <psf:ScoredProperty name=\"psk:MediaSizeHeight\">\r\n <psf:ParameterRef name=\"psk:PageMediaSizeMediaSizeHeight\" />\r\n </psf:ScoredProperty>\r\n </psf:Option>\r\n </psf:Feature>\r\n <psf:ParameterInit name=\"psk:PageMediaSizeMediaSizeHeight\">\r\n <psf:Value xsi:type=\"xsd:integer\">$labelLengthMicrons</psf:Value>\r\n </psf:ParameterInit>\r\n <psf:Feature name=\"psk:PageOrientation\">\r\n <psf:Option name=\"psk:Landscape\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"ns0001:PageRollFeedToEndOfSheet\">\r\n <psf:Option name=\"ns0001:FeedToImageEdge\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"psk:PageMediaType\">\r\n <psf:Option name=\"psk:Label\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"ns0001:JobRollCutSheet\">\r\n <psf:Option name=\"ns0001:CutSheet\" />\r\n </psf:Feature>\r\n</psf:PrintTicket>\r\n\"@\r\n\r\n$xmlBytes = [System.Text.Encoding]::UTF8.GetBytes($ticketXml)\r\n$memStream = New-Object System.IO.MemoryStream(,$xmlBytes)\r\n$ticket = New-Object System.Printing.PrintTicket($memStream)\r\n\r\n# Get print queue and create XPS document writer with our ticket\r\n$server = New-Object System.Printing.LocalPrintServer\r\n$queue = $server.GetPrintQueue('${printerName}')\r\n\r\n# Create temp XPS file\r\n$xpsPath = [System.IO.Path]::GetTempFileName() + \".xps\"\r\n\r\n# Page size in WPF units (96 dpi) - convert from microns\r\n$pageWidth = $labelLengthMicrons / 25400.0 * 96 # length is horizontal\r\n$pageHeight = $tapeWidthMicrons / 25400.0 * 96 # tape width is vertical\r\n\r\n# Create XPS document\r\n$package = [System.IO.Packaging.Package]::Open($xpsPath, [System.IO.FileMode]::Create)\r\n$xpsDoc = New-Object System.Windows.Xps.Packaging.XpsDocument($package)\r\n$writer = [System.Windows.Xps.Packaging.XpsDocument]::CreateXpsDocumentWriter($xpsDoc)\r\n\r\n# Create visual with image\r\n$visual = New-Object System.Windows.Media.DrawingVisual\r\n$dc = $visual.RenderOpen()\r\n\r\n# Load image as WPF bitmap\r\n$bitmapImg = New-Object System.Windows.Media.Imaging.BitmapImage\r\n$bitmapImg.BeginInit()\r\n$bitmapImg.UriSource = New-Object System.Uri('${imagePath.replace(/\\\\/g, \"\\\\\\\\\")}')\r\n$bitmapImg.EndInit()\r\n\r\n# Draw image centered vertically on page\r\n$yOffset = ($pageHeight - $imgHeightWpf) / 2\r\n$rect = New-Object System.Windows.Rect(0, $yOffset, $imgWidthWpf, $imgHeightWpf)\r\n$dc.DrawImage($bitmapImg, $rect)\r\n$dc.Close()\r\n\r\n# Write to XPS with page size\r\n$pageSize = New-Object System.Printing.PageMediaSize($pageWidth, $pageHeight)\r\n$writer.Write($visual, $ticket)\r\n\r\n$xpsDoc.Close()\r\n$package.Close()\r\n$img.Dispose()\r\n\r\n# Print the XPS file with our ticket\r\n$xpsDocForPrint = New-Object System.Windows.Xps.Packaging.XpsDocument($xpsPath, [System.IO.FileAccess]::Read)\r\n$seq = $xpsDocForPrint.GetFixedDocumentSequence()\r\n\r\n$xpsWriter = [System.Printing.PrintQueue]::CreateXpsDocumentWriter($queue)\r\n$xpsWriter.Write($seq, $ticket)\r\n\r\n$xpsDocForPrint.Close()\r\nRemove-Item $xpsPath -ErrorAction SilentlyContinue\r\n\r\nWrite-Host \"Print complete\"\r\n`;\r\n\r\n const ps = spawn(\"powershell\", [\"-Command\", psScript], { stdio: \"pipe\" });\r\n\r\n let stdout = \"\";\r\n let stderr = \"\";\r\n ps.stdout.on(\"data\", (data) => {\r\n stdout += data.toString();\r\n });\r\n ps.stderr.on(\"data\", (data) => {\r\n stderr += data.toString();\r\n });\r\n\r\n ps.on(\"close\", (code) => {\r\n if (stdout) console.log(stdout.trim());\r\n if (code === 0) {\r\n resolve();\r\n } else {\r\n reject(new Error(`Print failed: ${stderr}`));\r\n }\r\n });\r\n\r\n ps.on(\"error\", (err) => {\r\n reject(new Error(`Failed to print: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\nasync function printLabel(text: string, options: PrintOptions): Promise<void> {\r\n // Create temp file for the image\r\n const tempDir = os.tmpdir();\r\n const tempFile = path.join(tempDir, `label-${Date.now()}.png`);\r\n\r\n try {\r\n const imageBuffer = await createLabelImage(text, options);\r\n fs.writeFileSync(tempFile, imageBuffer);\r\n\r\n await printImage(tempFile, options.printer, options.tapeMm);\r\n } finally {\r\n // Clean up temp file\r\n if (fs.existsSync(tempFile)) {\r\n fs.unlinkSync(tempFile);\r\n }\r\n }\r\n}\r\n\r\nasync function printHtmlLabel(htmlPath: string, options: PrintOptions): Promise<void> {\r\n const tempDir = os.tmpdir();\r\n const tempFile = path.join(tempDir, `label-html-${Date.now()}.png`);\r\n\r\n try {\r\n // CSS mm units use 96 DPI. Convert tape mm to CSS pixels, then scale up.\r\n // For 12mm tape: 12mm * 3.78 px/mm = ~45px CSS height\r\n // deviceScaleFactor of 300/96 ≈ 3.125 gives us 300 DPI output\r\n const cssPixelsPerMm = 96 / 25.4; // ~3.78\r\n const viewportHeight = Math.round(options.tapeMm * cssPixelsPerMm);\r\n const viewportWidth = Math.round(viewportHeight * 5); // ~5:1 aspect for labels\r\n const scaleFactor = PRINT_DPI / 96; // Scale CSS pixels to print DPI\r\n\r\n const renderedBuffer = await renderHtmlFile(htmlPath, {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n deviceScaleFactor: scaleFactor,\r\n keepScale: true, // Keep full resolution for printing\r\n });\r\n\r\n // Add margins for printer feed (3mm left, 4mm right)\r\n const pxPerMm = PRINT_DPI / 25.4;\r\n const leftMargin = Math.round(3 * pxPerMm);\r\n const rightMargin = Math.round(4 * pxPerMm);\r\n\r\n const rendered = await Jimp.read(renderedBuffer);\r\n const paddedWidth = rendered.width + leftMargin + rightMargin;\r\n const padded = new Jimp({ width: paddedWidth, height: rendered.height, color: 0xffffffff });\r\n padded.composite(rendered, leftMargin, 0);\r\n\r\n const imageBuffer = await padded.getBuffer(\"image/png\");\r\n fs.writeFileSync(tempFile, imageBuffer);\r\n\r\n await printImage(tempFile, options.printer, options.tapeMm);\r\n } finally {\r\n if (fs.existsSync(tempFile)) {\r\n fs.unlinkSync(tempFile);\r\n }\r\n await closeBrowser();\r\n }\r\n}\r\n\r\nasync function listPrinters(): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n exec('powershell -Command \"Get-Printer | Where-Object { $_.Name -like \\'*Brother*\\' -or $_.Name -like \\'*PT*\\' } | Select-Object -ExpandProperty Name\"',\r\n (error, stdout, stderr) => {\r\n if (error) {\r\n reject(new Error(`Failed to list printers: ${stderr}`));\r\n return;\r\n }\r\n const printers = stdout.trim().split(\"\\n\").filter(p => p.trim());\r\n if (printers.length === 0) {\r\n console.log(\"No Brother printers found\");\r\n } else {\r\n console.log(\"Brother printers:\");\r\n printers.forEach(p => console.log(` ${p.trim()}`));\r\n }\r\n resolve();\r\n });\r\n });\r\n}\r\n\r\nasync function detectTapeSize(printerName: string): Promise<number | null> {\r\n // First check config file for user-specified tape size\r\n const config = loadConfig();\r\n if (config.defaultTape) {\r\n const mm = parseInt(config.defaultTape.replace(\"mm\", \"\"), 10);\r\n if (!isNaN(mm) && TAPE_SIZES[`${mm}mm`]) {\r\n return mm;\r\n }\r\n }\r\n\r\n // Fall back to WMI query (may be stale after tape change)\r\n return new Promise((resolve) => {\r\n exec(`powershell -Command \"(Get-WmiObject Win32_PrinterConfiguration -Filter \\\\\"Name='${printerName}'\\\\\").PaperWidth\"`,\r\n (error, stdout) => {\r\n if (error || !stdout.trim()) {\r\n resolve(null);\r\n return;\r\n }\r\n // PaperWidth is in tenths of mm\r\n const tenthsMm = parseInt(stdout.trim(), 10);\r\n if (isNaN(tenthsMm)) {\r\n resolve(null);\r\n return;\r\n }\r\n const mm = Math.round(tenthsMm / 10);\r\n resolve(mm);\r\n });\r\n });\r\n}\r\n\r\n// Default printer name\r\nconst DEFAULT_PRINTER = \"Brother PT-P710BT\";\r\n\r\n// Label sizes for P-touch tapes at 300 DPI (high quality)\r\n// PT-P710BT has 180 DPI print head; 300 DPI source ensures max quality\r\n// Printable area from printer: 0.71\" height for 24mm tape, proportional for others\r\nconst PRINT_DPI = 300;\r\nconst TAPE_SIZES: Record<string, { width: number; height: number; mm: number }> = {\r\n \"6mm\": { width: 1137, height: 56, mm: 6 }, // 3.79\" x 0.19\" @ 300 DPI\r\n \"9mm\": { width: 1137, height: 84, mm: 9 }, // 3.79\" x 0.28\" @ 300 DPI\r\n \"12mm\": { width: 1137, height: 113, mm: 12 }, // 3.79\" x 0.38\" @ 300 DPI\r\n \"18mm\": { width: 1137, height: 169, mm: 18 }, // 3.79\" x 0.56\" @ 300 DPI\r\n \"24mm\": { width: 1137, height: 213, mm: 24 }, // 3.79\" x 0.71\" @ 300 DPI\r\n};\r\n\r\nprogram\r\n .name(\"brother-print\")\r\n .description(\"Print labels to Brother P-touch and QL label printers\")\r\n .version(\"1.0.0\");\r\n\r\nprogram\r\n .command(\"print <text>\")\r\n .description(\"Print a text label (use \\\\\\\\n for newlines)\")\r\n .option(\"-p, --printer <name>\", \"Printer name\", DEFAULT_PRINTER)\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm, or 'auto'\", \"auto\")\r\n .option(\"-w, --width <px>\", \"Custom width in pixels\")\r\n .option(\"-H, --img-height <px>\", \"Custom height in pixels\")\r\n .action(async (text: string, opts) => {\r\n try {\r\n let tapeMm: number;\r\n let tapeSize;\r\n\r\n if (opts.tape === \"auto\") {\r\n const detected = await detectTapeSize(opts.printer);\r\n if (detected) {\r\n tapeMm = detected;\r\n tapeSize = TAPE_SIZES[`${detected}mm`] || TAPE_SIZES[\"24mm\"];\r\n console.log(`Detected ${detected}mm tape`);\r\n } else {\r\n console.log(\"Could not detect tape, using 24mm\");\r\n tapeMm = 24;\r\n tapeSize = TAPE_SIZES[\"24mm\"];\r\n }\r\n } else {\r\n tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"24mm\"];\r\n tapeMm = tapeSize.mm;\r\n }\r\n\r\n const options: PrintOptions = {\r\n printer: opts.printer,\r\n fontSize: 32,\r\n width: opts.width ? parseInt(opts.width, 10) : tapeSize.width, // label length\r\n height: opts.imgHeight ? parseInt(opts.imgHeight, 10) : tapeSize.height, // tape height (printable)\r\n tapeMm: tapeMm,\r\n };\r\n\r\n await printLabel(text, options);\r\n console.log(\"Label printed successfully\");\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"list\")\r\n .description(\"List connected Brother printers\")\r\n .action(async () => {\r\n try {\r\n await listPrinters();\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"image <file>\")\r\n .description(\"Print an image file (PNG, JPG, BMP)\")\r\n .option(\"-p, --printer <name>\", \"Printer name\", DEFAULT_PRINTER)\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm, or 'auto'\", \"auto\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n let tapeMm: number;\r\n let tapeSize;\r\n\r\n if (opts.tape === \"auto\") {\r\n const detected = await detectTapeSize(opts.printer);\r\n if (detected) {\r\n tapeMm = detected;\r\n tapeSize = TAPE_SIZES[`${detected}mm`] || TAPE_SIZES[\"24mm\"];\r\n console.log(`Detected ${detected}mm tape`);\r\n } else {\r\n console.log(\"Could not detect tape, using 24mm\");\r\n tapeMm = 24;\r\n tapeSize = TAPE_SIZES[\"24mm\"];\r\n }\r\n } else {\r\n tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"24mm\"];\r\n tapeMm = tapeSize.mm;\r\n }\r\n\r\n const absolutePath = path.resolve(file);\r\n await printImage(absolutePath, opts.printer, tapeMm);\r\n console.log(\"Image printed successfully\");\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"html <file>\")\r\n .description(\"Print an HTML file as a label\")\r\n .option(\"-p, --printer <name>\", \"Printer name\", DEFAULT_PRINTER)\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm, or 'auto'\", \"auto\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n let tapeMm: number;\r\n let tapeSize;\r\n\r\n if (opts.tape === \"auto\") {\r\n const detected = await detectTapeSize(opts.printer);\r\n if (detected) {\r\n tapeMm = detected;\r\n tapeSize = TAPE_SIZES[`${detected}mm`] || TAPE_SIZES[\"24mm\"];\r\n console.log(`Detected ${detected}mm tape`);\r\n } else {\r\n console.log(\"Could not detect tape, using 24mm\");\r\n tapeMm = 24;\r\n tapeSize = TAPE_SIZES[\"24mm\"];\r\n }\r\n } else {\r\n tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"24mm\"];\r\n tapeMm = tapeSize.mm;\r\n }\r\n\r\n const options: PrintOptions = {\r\n printer: opts.printer,\r\n fontSize: 32,\r\n width: tapeSize.width, // label length\r\n height: tapeSize.height, // tape height (printable)\r\n tapeMm: tapeMm,\r\n };\r\n\r\n await printHtmlLabel(file, options);\r\n console.log(\"HTML label printed successfully\");\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"preview <text>\")\r\n .description(\"Save label as PNG without printing\")\r\n .option(\"-f, --font-size <size>\", \"Font size (16 or 32)\", \"32\")\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm\", \"12mm\")\r\n .option(\"-w, --width <px>\", \"Custom width in pixels\")\r\n .option(\"-H, --img-height <px>\", \"Custom height in pixels\")\r\n .option(\"-o, --output <file>\", \"Output file path\", \"label-preview.png\")\r\n .action(async (text: string, opts) => {\r\n try {\r\n const tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"12mm\"];\r\n const options: PrintOptions = {\r\n printer: \"\",\r\n fontSize: parseInt(opts.fontSize, 10),\r\n width: opts.width ? parseInt(opts.width, 10) : tapeSize.width, // label length\r\n height: opts.imgHeight ? parseInt(opts.imgHeight, 10) : tapeSize.height, // tape height\r\n tapeMm: tapeSize.mm,\r\n };\r\n\r\n const imageBuffer = await createLabelImage(text, options);\r\n fs.writeFileSync(opts.output, imageBuffer);\r\n console.log(`Preview saved to ${opts.output}`);\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"qr <data>\")\r\n .description(\"Print a QR code label\")\r\n .option(\"-p, --printer <name>\", \"Printer name\", DEFAULT_PRINTER)\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm, or 'auto'\", \"auto\")\r\n .option(\"-l, --label <text>\", \"Optional text label beside QR code\")\r\n .option(\"-o, --output <file>\", \"Save to file instead of printing\")\r\n .action(async (data: string, opts) => {\r\n try {\r\n let tapeMm: number;\r\n let tapeSize;\r\n\r\n if (opts.tape === \"auto\") {\r\n const detected = await detectTapeSize(opts.printer);\r\n if (detected) {\r\n tapeMm = detected;\r\n tapeSize = TAPE_SIZES[`${detected}mm`] || TAPE_SIZES[\"24mm\"];\r\n console.log(`Detected ${detected}mm tape`);\r\n } else {\r\n console.log(\"Could not detect tape, using 24mm\");\r\n tapeMm = 24;\r\n tapeSize = TAPE_SIZES[\"24mm\"];\r\n }\r\n } else {\r\n tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"24mm\"];\r\n tapeMm = tapeSize.mm;\r\n }\r\n\r\n const options: PrintOptions = {\r\n printer: opts.printer,\r\n fontSize: 32,\r\n width: tapeSize.width,\r\n height: tapeSize.height,\r\n tapeMm: tapeMm,\r\n };\r\n\r\n const imageBuffer = await createQrLabelImage(data, options, opts.label);\r\n\r\n if (opts.output) {\r\n fs.writeFileSync(opts.output, imageBuffer);\r\n console.log(`QR label saved to ${opts.output}`);\r\n } else {\r\n const tempDir = os.tmpdir();\r\n const tempFile = path.join(tempDir, `qr-label-${Date.now()}.png`);\r\n try {\r\n fs.writeFileSync(tempFile, imageBuffer);\r\n await printImage(tempFile, options.printer, options.tapeMm);\r\n console.log(\"QR label printed successfully\");\r\n } finally {\r\n if (fs.existsSync(tempFile)) {\r\n fs.unlinkSync(tempFile);\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"config\")\r\n .description(\"Set default tape size and printer (stored in ~/.brother-label.json)\")\r\n .option(\"-t, --tape <size>\", \"Set default tape size: 6mm, 9mm, 12mm, 18mm, 24mm\")\r\n .option(\"-p, --printer <name>\", \"Set default printer name\")\r\n .option(\"-s, --show\", \"Show current configuration\")\r\n .action((opts) => {\r\n const config = loadConfig();\r\n\r\n if (opts.show || (!opts.tape && !opts.printer)) {\r\n console.log(\"Current configuration:\");\r\n console.log(` Config file: ${CONFIG_PATH}`);\r\n console.log(` Default tape: ${config.defaultTape || \"(not set - will use WMI detection)\"}`);\r\n console.log(` Default printer: ${config.defaultPrinter || DEFAULT_PRINTER}`);\r\n console.log(\"\\nAvailable tape sizes: 6mm, 9mm, 12mm, 18mm, 24mm\");\r\n return;\r\n }\r\n\r\n if (opts.tape) {\r\n const tape = opts.tape.endsWith(\"mm\") ? opts.tape : `${opts.tape}mm`;\r\n if (!TAPE_SIZES[tape]) {\r\n console.error(`Invalid tape size: ${opts.tape}`);\r\n console.error(\"Valid sizes: 6mm, 9mm, 12mm, 18mm, 24mm\");\r\n process.exit(1);\r\n }\r\n config.defaultTape = tape;\r\n console.log(`Default tape set to: ${tape}`);\r\n }\r\n\r\n if (opts.printer) {\r\n config.defaultPrinter = opts.printer;\r\n console.log(`Default printer set to: ${opts.printer}`);\r\n }\r\n\r\n saveConfig(config);\r\n console.log(`Configuration saved to ${CONFIG_PATH}`);\r\n });\r\n\r\nprogram.parse();\r\n"]}
1
+ {"version":3,"file":"brother-print.js","sourceRoot":"","sources":["brother-print.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\r\nimport { Jimp, loadFont, measureText, measureTextHeight, HorizontalAlign, VerticalAlign } from \"jimp\";\r\nimport { program } from \"commander\";\r\nimport { exec, spawn } from \"child_process\";\r\nimport * as fs from \"fs\";\r\nimport * as path from \"path\";\r\nimport { fileURLToPath } from \"url\";\r\nimport * as os from \"os\";\r\nimport { renderHtmlFile, closeBrowser } from \"./render.js\";\r\nimport QRCode from \"qrcode\";\r\n\r\n\r\ninterface PrintOptions {\r\n printer: string;\r\n fontSize: number;\r\n width: number;\r\n height: number;\r\n tapeMm: number;\r\n}\r\n\r\ninterface Config {\r\n defaultTape?: string;\r\n defaultPrinter?: string;\r\n}\r\n\r\nconst CONFIG_PATH = path.join(os.homedir(), \".brother-label.json\");\r\n\r\nfunction loadConfig(): Config {\r\n try {\r\n if (fs.existsSync(CONFIG_PATH)) {\r\n return JSON.parse(fs.readFileSync(CONFIG_PATH, \"utf-8\"));\r\n }\r\n } catch (err) {\r\n // Ignore config errors\r\n }\r\n return {};\r\n}\r\n\r\nfunction saveConfig(config: Config): void {\r\n fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));\r\n}\r\n\r\n// Available font sizes in jimp\r\nconst FONT_SIZES = [128, 64, 32, 16, 14, 12, 10, 8];\r\n\r\nasync function loadFontBySize(size: number): Promise<any> {\r\n const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), \"node_modules/@jimp/plugin-print/fonts/open-sans\");\r\n const fontFolder = `open-sans-${size}-black`;\r\n const fontPath = path.join(fontDir, fontFolder, `${fontFolder}.fnt`);\r\n return loadFont(fontPath);\r\n}\r\n\r\nasync function createLabelImage(text: string, options: PrintOptions): Promise<Buffer> {\r\n const lines = text.split(\"\\\\n\").join(\"\\n\");\r\n const targetHeight = options.height;\r\n\r\n // Use largest font for best quality, then scale down\r\n let font = await loadFontBySize(128);\r\n\r\n // Render text at large size first\r\n const textWidth = measureText(font, lines);\r\n const textHeight = measureTextHeight(font, lines, textWidth + 100);\r\n\r\n // Create image for text with small padding\r\n const padding = 10;\r\n const imgWidth = textWidth + padding * 2;\r\n const imgHeight = textHeight + padding * 2;\r\n\r\n const tempImage = new Jimp({ width: imgWidth, height: imgHeight, color: 0xffffffff });\r\n\r\n tempImage.print({\r\n font: font,\r\n x: padding,\r\n y: padding,\r\n text: lines,\r\n });\r\n\r\n // Scale to fit tape height (tape sizes already account for printable area)\r\n const scale = targetHeight / imgHeight;\r\n const finalWidth = Math.round(imgWidth * scale);\r\n const finalHeight = Math.round(imgHeight * scale);\r\n\r\n tempImage.resize({ w: finalWidth, h: finalHeight });\r\n\r\n // Create final image sized to content with small horizontal padding\r\n const hPadding = Math.round(targetHeight * 0.2); // ~20% of height as side margins\r\n const outputWidth = finalWidth + hPadding * 2;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n\r\n // Center both horizontally and vertically\r\n const xOffset = hPadding;\r\n const yOffset = Math.round((targetHeight - finalHeight) / 2);\r\n image.composite(tempImage, xOffset, yOffset);\r\n\r\n return image.getBuffer(\"image/png\");\r\n}\r\n\r\nasync function createQrLabelImage(data: string, options: PrintOptions, labelText?: string): Promise<Buffer> {\r\n const targetHeight = options.height;\r\n const qrSize = Math.floor(targetHeight * 0.95); // QR code is 95% of tape height\r\n\r\n // Margins in mm converted to pixels at PRINT_DPI\r\n // Left margin ~2mm, right margin ~4mm to account for printer feed\r\n const pxPerMm = PRINT_DPI / 25.4;\r\n const leftMargin = Math.round(2 * pxPerMm);\r\n const rightMargin = Math.round(4 * pxPerMm);\r\n\r\n // Generate QR code as PNG buffer at high resolution\r\n const qrBuffer = await QRCode.toBuffer(data, {\r\n type: \"png\",\r\n width: qrSize,\r\n margin: 0,\r\n errorCorrectionLevel: \"M\",\r\n color: { dark: \"#000000\", light: \"#ffffff\" },\r\n });\r\n\r\n const qrImage = await Jimp.read(qrBuffer);\r\n\r\n if (!labelText) {\r\n // QR only - create minimal label with margins\r\n const outputWidth = leftMargin + qrSize + rightMargin;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n const yOffset = Math.floor((targetHeight - qrSize) / 2);\r\n image.composite(qrImage, leftMargin, yOffset);\r\n return image.getBuffer(\"image/png\");\r\n }\r\n\r\n // QR + text label\r\n const font = await loadFontBySize(64);\r\n const textWidth = measureText(font, labelText);\r\n const textHeight = measureTextHeight(font, labelText, textWidth + 50);\r\n\r\n // Scale text to fit beside QR\r\n const maxTextHeight = targetHeight * 0.8;\r\n const textScale = Math.min(1, maxTextHeight / textHeight);\r\n const scaledTextWidth = Math.round(textWidth * textScale);\r\n const scaledTextHeight = Math.round(textHeight * textScale);\r\n\r\n // Create text image\r\n const textImg = new Jimp({ width: textWidth + 20, height: textHeight + 20, color: 0xffffffff });\r\n textImg.print({ font, x: 10, y: 10, text: labelText });\r\n if (textScale < 1) {\r\n textImg.resize({ w: scaledTextWidth, h: scaledTextHeight });\r\n }\r\n\r\n // Compose final image: QR on left, text on right\r\n const gap = Math.floor(targetHeight * 0.15);\r\n const outputWidth = leftMargin + qrSize + gap + scaledTextWidth + rightMargin;\r\n const image = new Jimp({ width: outputWidth, height: targetHeight, color: 0xffffffff });\r\n\r\n const qrY = Math.floor((targetHeight - qrSize) / 2);\r\n image.composite(qrImage, leftMargin, qrY);\r\n\r\n const textY = Math.floor((targetHeight - scaledTextHeight) / 2);\r\n image.composite(textImg, leftMargin + qrSize + gap, textY);\r\n\r\n return image.getBuffer(\"image/png\");\r\n}\r\n\r\nasync function printImage(imagePath: string, printerName: string, tapeMm: number): Promise<void> {\r\n // Map tape mm to Brother CustomMediaSize for PrintTicket\r\n const mediaOptions: Record<number, { name: string; width: number }> = {\r\n 6: { name: \"CustomMediaSize257\", width: 5900 },\r\n 9: { name: \"CustomMediaSize258\", width: 9000 },\r\n 12: { name: \"CustomMediaSize259\", width: 11900 },\r\n 18: { name: \"CustomMediaSize260\", width: 18100 },\r\n 24: { name: \"CustomMediaSize261\", width: 24000 },\r\n };\r\n const media = mediaOptions[tapeMm] || mediaOptions[12];\r\n\r\n return new Promise((resolve, reject) => {\r\n const psScript = `\r\nAdd-Type -AssemblyName System.Drawing\r\nAdd-Type -AssemblyName System.Printing\r\nAdd-Type -AssemblyName ReachFramework\r\nAdd-Type -AssemblyName PresentationCore\r\n\r\n$img = [System.Drawing.Image]::FromFile('${imagePath.replace(/\\\\/g, \"\\\\\\\\\")}')\r\n\r\n# Calculate label dimensions in microns (using ${PRINT_DPI} DPI source images)\r\n$labelLengthMicrons = [int]($img.Width / ${PRINT_DPI}.0 * 25400) + 3000\r\n$tapeWidthMicrons = ${media.width}\r\n\r\n# Image dimensions in WPF units (1/96 inch) - convert from ${PRINT_DPI} DPI source\r\n$imgWidthWpf = $img.Width / ${PRINT_DPI}.0 * 96\r\n$imgHeightWpf = $img.Height / ${PRINT_DPI}.0 * 96\r\n\r\nWrite-Host \"Using ${tapeMm}mm tape, label length: $([int]($labelLengthMicrons/1000))mm\"\r\n\r\n# Build PrintTicket XML\r\n$ticketXml = @\"\r\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<psf:PrintTicket xmlns:psf=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework\"\r\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" version=\"1\"\r\n xmlns:psk=\"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords\"\r\n xmlns:ns0001=\"http://schemas.brother.info/mfc/printing/2006/11/printschemakeywords\">\r\n <psf:Feature name=\"psk:PageMediaSize\">\r\n <psf:Option name=\"ns0001:${media.name}\">\r\n <psf:ScoredProperty name=\"psk:MediaSizeWidth\">\r\n <psf:Value xsi:type=\"xsd:integer\">${media.width}</psf:Value>\r\n </psf:ScoredProperty>\r\n <psf:ScoredProperty name=\"psk:MediaSizeHeight\">\r\n <psf:ParameterRef name=\"psk:PageMediaSizeMediaSizeHeight\" />\r\n </psf:ScoredProperty>\r\n </psf:Option>\r\n </psf:Feature>\r\n <psf:ParameterInit name=\"psk:PageMediaSizeMediaSizeHeight\">\r\n <psf:Value xsi:type=\"xsd:integer\">$labelLengthMicrons</psf:Value>\r\n </psf:ParameterInit>\r\n <psf:Feature name=\"psk:PageOrientation\">\r\n <psf:Option name=\"psk:Landscape\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"ns0001:PageRollFeedToEndOfSheet\">\r\n <psf:Option name=\"ns0001:FeedToImageEdge\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"psk:PageMediaType\">\r\n <psf:Option name=\"psk:Label\" />\r\n </psf:Feature>\r\n <psf:Feature name=\"ns0001:JobRollCutSheet\">\r\n <psf:Option name=\"ns0001:CutSheet\" />\r\n </psf:Feature>\r\n</psf:PrintTicket>\r\n\"@\r\n\r\n$xmlBytes = [System.Text.Encoding]::UTF8.GetBytes($ticketXml)\r\n$memStream = New-Object System.IO.MemoryStream(,$xmlBytes)\r\n$ticket = New-Object System.Printing.PrintTicket($memStream)\r\n\r\n# Get print queue and create XPS document writer with our ticket\r\n$server = New-Object System.Printing.LocalPrintServer\r\n$queue = $server.GetPrintQueue('${printerName}')\r\n\r\n# Create temp XPS file\r\n$xpsPath = [System.IO.Path]::GetTempFileName() + \".xps\"\r\n\r\n# Page size in WPF units (96 dpi) - convert from microns\r\n$pageWidth = $labelLengthMicrons / 25400.0 * 96 # length is horizontal\r\n$pageHeight = $tapeWidthMicrons / 25400.0 * 96 # tape width is vertical\r\n\r\n# Create XPS document\r\n$package = [System.IO.Packaging.Package]::Open($xpsPath, [System.IO.FileMode]::Create)\r\n$xpsDoc = New-Object System.Windows.Xps.Packaging.XpsDocument($package)\r\n$writer = [System.Windows.Xps.Packaging.XpsDocument]::CreateXpsDocumentWriter($xpsDoc)\r\n\r\n# Create visual with image\r\n$visual = New-Object System.Windows.Media.DrawingVisual\r\n$dc = $visual.RenderOpen()\r\n\r\n# Load image as WPF bitmap\r\n$bitmapImg = New-Object System.Windows.Media.Imaging.BitmapImage\r\n$bitmapImg.BeginInit()\r\n$bitmapImg.UriSource = New-Object System.Uri('${imagePath.replace(/\\\\/g, \"\\\\\\\\\")}')\r\n$bitmapImg.EndInit()\r\n\r\n# Draw image centered vertically on page\r\n$yOffset = ($pageHeight - $imgHeightWpf) / 2\r\n$rect = New-Object System.Windows.Rect(0, $yOffset, $imgWidthWpf, $imgHeightWpf)\r\n$dc.DrawImage($bitmapImg, $rect)\r\n$dc.Close()\r\n\r\n# Write to XPS with page size\r\n$pageSize = New-Object System.Printing.PageMediaSize($pageWidth, $pageHeight)\r\n$writer.Write($visual, $ticket)\r\n\r\n$xpsDoc.Close()\r\n$package.Close()\r\n$img.Dispose()\r\n\r\n# Print the XPS file with our ticket\r\n$xpsDocForPrint = New-Object System.Windows.Xps.Packaging.XpsDocument($xpsPath, [System.IO.FileAccess]::Read)\r\n$seq = $xpsDocForPrint.GetFixedDocumentSequence()\r\n\r\n$xpsWriter = [System.Printing.PrintQueue]::CreateXpsDocumentWriter($queue)\r\n$xpsWriter.Write($seq, $ticket)\r\n\r\n$xpsDocForPrint.Close()\r\nRemove-Item $xpsPath -ErrorAction SilentlyContinue\r\n\r\nWrite-Host \"Print complete\"\r\n`;\r\n\r\n const ps = spawn(\"powershell\", [\"-Command\", psScript], { stdio: \"pipe\" });\r\n\r\n let stdout = \"\";\r\n let stderr = \"\";\r\n ps.stdout.on(\"data\", (data) => {\r\n stdout += data.toString();\r\n });\r\n ps.stderr.on(\"data\", (data) => {\r\n stderr += data.toString();\r\n });\r\n\r\n ps.on(\"close\", (code) => {\r\n if (stdout) console.log(stdout.trim());\r\n if (code === 0) {\r\n resolve();\r\n } else {\r\n reject(new Error(`Print failed: ${stderr}`));\r\n }\r\n });\r\n\r\n ps.on(\"error\", (err) => {\r\n reject(new Error(`Failed to print: ${err.message}`));\r\n });\r\n });\r\n}\r\n\r\nasync function printLabel(text: string, options: PrintOptions): Promise<void> {\r\n // Create temp file for the image\r\n const tempDir = os.tmpdir();\r\n const tempFile = path.join(tempDir, `label-${Date.now()}.png`);\r\n\r\n try {\r\n const imageBuffer = await createLabelImage(text, options);\r\n fs.writeFileSync(tempFile, imageBuffer);\r\n\r\n await printImage(tempFile, options.printer, options.tapeMm);\r\n } finally {\r\n // Clean up temp file\r\n if (fs.existsSync(tempFile)) {\r\n fs.unlinkSync(tempFile);\r\n }\r\n }\r\n}\r\n\r\nasync function printHtmlLabel(htmlPath: string, options: PrintOptions): Promise<void> {\r\n const tempDir = os.tmpdir();\r\n const tempFile = path.join(tempDir, `label-html-${Date.now()}.png`);\r\n\r\n try {\r\n // CSS mm units use 96 DPI. Convert tape mm to CSS pixels, then scale up.\r\n // For 12mm tape: 12mm * 3.78 px/mm = ~45px CSS height\r\n // deviceScaleFactor of 300/96 ≈ 3.125 gives us 300 DPI output\r\n const cssPixelsPerMm = 96 / 25.4; // ~3.78\r\n const viewportHeight = Math.round(options.tapeMm * cssPixelsPerMm);\r\n const viewportWidth = Math.round(viewportHeight * 5); // ~5:1 aspect for labels\r\n const scaleFactor = PRINT_DPI / 96; // Scale CSS pixels to print DPI\r\n\r\n const renderedBuffer = await renderHtmlFile(htmlPath, {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n deviceScaleFactor: scaleFactor,\r\n keepScale: true, // Keep full resolution for printing\r\n });\r\n\r\n // Add margins for printer feed (3mm left, 4mm right)\r\n const pxPerMm = PRINT_DPI / 25.4;\r\n const leftMargin = Math.round(3 * pxPerMm);\r\n const rightMargin = Math.round(4 * pxPerMm);\r\n\r\n const rendered = await Jimp.read(renderedBuffer);\r\n const paddedWidth = rendered.width + leftMargin + rightMargin;\r\n const padded = new Jimp({ width: paddedWidth, height: rendered.height, color: 0xffffffff });\r\n padded.composite(rendered, leftMargin, 0);\r\n\r\n const imageBuffer = await padded.getBuffer(\"image/png\");\r\n fs.writeFileSync(tempFile, imageBuffer);\r\n\r\n await printImage(tempFile, options.printer, options.tapeMm);\r\n } finally {\r\n if (fs.existsSync(tempFile)) {\r\n fs.unlinkSync(tempFile);\r\n }\r\n await closeBrowser();\r\n }\r\n}\r\n\r\nasync function listPrinters(): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n exec('powershell -Command \"Get-Printer | Where-Object { $_.Name -like \\'*Brother*\\' -or $_.Name -like \\'*PT*\\' } | Select-Object -ExpandProperty Name\"',\r\n (error, stdout, stderr) => {\r\n if (error) {\r\n reject(new Error(`Failed to list printers: ${stderr}`));\r\n return;\r\n }\r\n const printers = stdout.trim().split(\"\\n\").filter(p => p.trim());\r\n if (printers.length === 0) {\r\n console.log(\"No Brother printers found\");\r\n } else {\r\n console.log(\"Brother printers:\");\r\n printers.forEach(p => console.log(` ${p.trim()}`));\r\n }\r\n resolve();\r\n });\r\n });\r\n}\r\n\r\nasync function detectTapeSize(printerName: string): Promise<number | null> {\r\n // First check config file for user-specified tape size\r\n const config = loadConfig();\r\n if (config.defaultTape) {\r\n const mm = parseInt(config.defaultTape.replace(\"mm\", \"\"), 10);\r\n if (!isNaN(mm) && TAPE_SIZES[`${mm}mm`]) {\r\n return mm;\r\n }\r\n }\r\n\r\n // Fall back to WMI query (may be stale after tape change)\r\n return new Promise((resolve) => {\r\n exec(`powershell -Command \"(Get-WmiObject Win32_PrinterConfiguration -Filter \\\\\"Name='${printerName}'\\\\\").PaperWidth\"`,\r\n (error, stdout) => {\r\n if (error || !stdout.trim()) {\r\n resolve(null);\r\n return;\r\n }\r\n // PaperWidth is in tenths of mm\r\n const tenthsMm = parseInt(stdout.trim(), 10);\r\n if (isNaN(tenthsMm)) {\r\n resolve(null);\r\n return;\r\n }\r\n const mm = Math.round(tenthsMm / 10);\r\n resolve(mm);\r\n });\r\n });\r\n}\r\n\r\n// Default printer name\r\nconst DEFAULT_PRINTER = \"Brother PT-P710BT\";\r\n\r\n// Label sizes for P-touch tapes at 300 DPI (high quality)\r\n// PT-P710BT has 180 DPI print head; 300 DPI source ensures max quality\r\n// Printable area from printer: 0.71\" height for 24mm tape, proportional for others\r\nconst PRINT_DPI = 300;\r\nconst TAPE_SIZES: Record<string, { width: number; height: number; mm: number }> = {\r\n \"6mm\": { width: 1137, height: 56, mm: 6 }, // 3.79\" x 0.19\" @ 300 DPI\r\n \"9mm\": { width: 1137, height: 84, mm: 9 }, // 3.79\" x 0.28\" @ 300 DPI\r\n \"12mm\": { width: 1137, height: 113, mm: 12 }, // 3.79\" x 0.38\" @ 300 DPI\r\n \"18mm\": { width: 1137, height: 169, mm: 18 }, // 3.79\" x 0.56\" @ 300 DPI\r\n \"24mm\": { width: 1137, height: 213, mm: 24 }, // 3.79\" x 0.71\" @ 300 DPI\r\n};\r\n\r\nprogram\r\n .name(\"brother-print\")\r\n .description(\"Print labels to Brother P-touch and QL label printers\")\r\n .version(\"1.0.0\");\r\n\r\nprogram\r\n .command(\"print <text>\")\r\n .description(\"Print a text label (use \\\\\\\\n for newlines)\")\r\n .option(\"-p, --printer <name>\", \"Printer name\", DEFAULT_PRINTER)\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm, or 'auto'\", \"auto\")\r\n .option(\"-w, --width <px>\", \"Custom width in pixels\")\r\n .option(\"-H, --img-height <px>\", \"Custom height in pixels\")\r\n .action(async (text: string, opts) => {\r\n try {\r\n let tapeMm: number;\r\n let tapeSize;\r\n\r\n if (opts.tape === \"auto\") {\r\n const detected = await detectTapeSize(opts.printer);\r\n if (detected) {\r\n tapeMm = detected;\r\n tapeSize = TAPE_SIZES[`${detected}mm`] || TAPE_SIZES[\"24mm\"];\r\n console.log(`Detected ${detected}mm tape`);\r\n } else {\r\n console.log(\"Could not detect tape, using 24mm\");\r\n tapeMm = 24;\r\n tapeSize = TAPE_SIZES[\"24mm\"];\r\n }\r\n } else {\r\n tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"24mm\"];\r\n tapeMm = tapeSize.mm;\r\n }\r\n\r\n const options: PrintOptions = {\r\n printer: opts.printer,\r\n fontSize: 32,\r\n width: opts.width ? parseInt(opts.width, 10) : tapeSize.width, // label length\r\n height: opts.imgHeight ? parseInt(opts.imgHeight, 10) : tapeSize.height, // tape height (printable)\r\n tapeMm: tapeMm,\r\n };\r\n\r\n await printLabel(text, options);\r\n console.log(\"Label printed successfully\");\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"list\")\r\n .description(\"List connected Brother printers\")\r\n .action(async () => {\r\n try {\r\n await listPrinters();\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"image <file>\")\r\n .description(\"Print an image file (PNG, JPG, BMP)\")\r\n .option(\"-p, --printer <name>\", \"Printer name\", DEFAULT_PRINTER)\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm, or 'auto'\", \"auto\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n let tapeMm: number;\r\n let tapeSize;\r\n\r\n if (opts.tape === \"auto\") {\r\n const detected = await detectTapeSize(opts.printer);\r\n if (detected) {\r\n tapeMm = detected;\r\n tapeSize = TAPE_SIZES[`${detected}mm`] || TAPE_SIZES[\"24mm\"];\r\n console.log(`Detected ${detected}mm tape`);\r\n } else {\r\n console.log(\"Could not detect tape, using 24mm\");\r\n tapeMm = 24;\r\n tapeSize = TAPE_SIZES[\"24mm\"];\r\n }\r\n } else {\r\n tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"24mm\"];\r\n tapeMm = tapeSize.mm;\r\n }\r\n\r\n const absolutePath = path.resolve(file);\r\n await printImage(absolutePath, opts.printer, tapeMm);\r\n console.log(\"Image printed successfully\");\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"html <file>\")\r\n .description(\"Print an HTML file as a label\")\r\n .option(\"-p, --printer <name>\", \"Printer name\", DEFAULT_PRINTER)\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm, or 'auto'\", \"auto\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n let tapeMm: number;\r\n let tapeSize;\r\n\r\n if (opts.tape === \"auto\") {\r\n const detected = await detectTapeSize(opts.printer);\r\n if (detected) {\r\n tapeMm = detected;\r\n tapeSize = TAPE_SIZES[`${detected}mm`] || TAPE_SIZES[\"24mm\"];\r\n console.log(`Detected ${detected}mm tape`);\r\n } else {\r\n console.log(\"Could not detect tape, using 24mm\");\r\n tapeMm = 24;\r\n tapeSize = TAPE_SIZES[\"24mm\"];\r\n }\r\n } else {\r\n tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"24mm\"];\r\n tapeMm = tapeSize.mm;\r\n }\r\n\r\n const options: PrintOptions = {\r\n printer: opts.printer,\r\n fontSize: 32,\r\n width: tapeSize.width, // label length\r\n height: tapeSize.height, // tape height (printable)\r\n tapeMm: tapeMm,\r\n };\r\n\r\n await printHtmlLabel(file, options);\r\n console.log(\"HTML label printed successfully\");\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"preview <text>\")\r\n .description(\"Save label as PNG without printing\")\r\n .option(\"-f, --font-size <size>\", \"Font size (16 or 32)\", \"32\")\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm\", \"12mm\")\r\n .option(\"-w, --width <px>\", \"Custom width in pixels\")\r\n .option(\"-H, --img-height <px>\", \"Custom height in pixels\")\r\n .option(\"-o, --output <file>\", \"Output file path\", \"label-preview.png\")\r\n .action(async (text: string, opts) => {\r\n try {\r\n const tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"12mm\"];\r\n const options: PrintOptions = {\r\n printer: \"\",\r\n fontSize: parseInt(opts.fontSize, 10),\r\n width: opts.width ? parseInt(opts.width, 10) : tapeSize.width, // label length\r\n height: opts.imgHeight ? parseInt(opts.imgHeight, 10) : tapeSize.height, // tape height\r\n tapeMm: tapeSize.mm,\r\n };\r\n\r\n const imageBuffer = await createLabelImage(text, options);\r\n fs.writeFileSync(opts.output, imageBuffer);\r\n console.log(`Preview saved to ${opts.output}`);\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"qr <data>\")\r\n .description(\"Print a QR code label\")\r\n .option(\"-p, --printer <name>\", \"Printer name\", DEFAULT_PRINTER)\r\n .option(\"-t, --tape <size>\", \"Tape size: 6mm, 9mm, 12mm, 18mm, 24mm, or 'auto'\", \"auto\")\r\n .option(\"-l, --label <text>\", \"Optional text label beside QR code\")\r\n .option(\"-o, --output <file>\", \"Save to file instead of printing\")\r\n .action(async (data: string, opts) => {\r\n try {\r\n let tapeMm: number;\r\n let tapeSize;\r\n\r\n if (opts.tape === \"auto\") {\r\n const detected = await detectTapeSize(opts.printer);\r\n if (detected) {\r\n tapeMm = detected;\r\n tapeSize = TAPE_SIZES[`${detected}mm`] || TAPE_SIZES[\"24mm\"];\r\n console.log(`Detected ${detected}mm tape`);\r\n } else {\r\n console.log(\"Could not detect tape, using 24mm\");\r\n tapeMm = 24;\r\n tapeSize = TAPE_SIZES[\"24mm\"];\r\n }\r\n } else {\r\n tapeSize = TAPE_SIZES[opts.tape] || TAPE_SIZES[\"24mm\"];\r\n tapeMm = tapeSize.mm;\r\n }\r\n\r\n const options: PrintOptions = {\r\n printer: opts.printer,\r\n fontSize: 32,\r\n width: tapeSize.width,\r\n height: tapeSize.height,\r\n tapeMm: tapeMm,\r\n };\r\n\r\n const imageBuffer = await createQrLabelImage(data, options, opts.label);\r\n\r\n if (opts.output) {\r\n fs.writeFileSync(opts.output, imageBuffer);\r\n console.log(`QR label saved to ${opts.output}`);\r\n } else {\r\n const tempDir = os.tmpdir();\r\n const tempFile = path.join(tempDir, `qr-label-${Date.now()}.png`);\r\n try {\r\n fs.writeFileSync(tempFile, imageBuffer);\r\n await printImage(tempFile, options.printer, options.tapeMm);\r\n console.log(\"QR label printed successfully\");\r\n } finally {\r\n if (fs.existsSync(tempFile)) {\r\n fs.unlinkSync(tempFile);\r\n }\r\n }\r\n }\r\n } catch (err) {\r\n console.error(`Error: ${(err as Error).message}`);\r\n process.exit(1);\r\n }\r\n });\r\n\r\nprogram\r\n .command(\"config\")\r\n .description(\"Set default tape size and printer (stored in ~/.brother-label.json)\")\r\n .option(\"-t, --tape <size>\", \"Set default tape size: 6mm, 9mm, 12mm, 18mm, 24mm\")\r\n .option(\"-p, --printer <name>\", \"Set default printer name\")\r\n .option(\"-s, --show\", \"Show current configuration\")\r\n .action((opts) => {\r\n const config = loadConfig();\r\n\r\n if (opts.show || (!opts.tape && !opts.printer)) {\r\n console.log(\"Current configuration:\");\r\n console.log(` Config file: ${CONFIG_PATH}`);\r\n console.log(` Default tape: ${config.defaultTape || \"(not set - will use WMI detection)\"}`);\r\n console.log(` Default printer: ${config.defaultPrinter || DEFAULT_PRINTER}`);\r\n console.log(\"\\nAvailable tape sizes: 6mm, 9mm, 12mm, 18mm, 24mm\");\r\n return;\r\n }\r\n\r\n if (opts.tape) {\r\n const tape = opts.tape.endsWith(\"mm\") ? opts.tape : `${opts.tape}mm`;\r\n if (!TAPE_SIZES[tape]) {\r\n console.error(`Invalid tape size: ${opts.tape}`);\r\n console.error(\"Valid sizes: 6mm, 9mm, 12mm, 18mm, 24mm\");\r\n process.exit(1);\r\n }\r\n config.defaultTape = tape;\r\n console.log(`Default tape set to: ${tape}`);\r\n }\r\n\r\n if (opts.printer) {\r\n config.defaultPrinter = opts.printer;\r\n console.log(`Default printer set to: ${opts.printer}`);\r\n }\r\n\r\n saveConfig(config);\r\n console.log(`Configuration saved to ${CONFIG_PATH}`);\r\n });\r\n\r\nprogram.parse();\r\n"]}
package/brother-print.ts CHANGED
@@ -4,11 +4,11 @@ import { program } from "commander";
4
4
  import { exec, spawn } from "child_process";
5
5
  import * as fs from "fs";
6
6
  import * as path from "path";
7
+ import { fileURLToPath } from "url";
7
8
  import * as os from "os";
8
9
  import { renderHtmlFile, closeBrowser } from "./render.js";
9
10
  import QRCode from "qrcode";
10
11
 
11
- const __dirname = import.meta.dirname;
12
12
 
13
13
  interface PrintOptions {
14
14
  printer: string;
@@ -44,7 +44,7 @@ function saveConfig(config: Config): void {
44
44
  const FONT_SIZES = [128, 64, 32, 16, 14, 12, 10, 8];
45
45
 
46
46
  async function loadFontBySize(size: number): Promise<any> {
47
- const fontDir = path.join(__dirname, "node_modules/@jimp/plugin-print/fonts/open-sans");
47
+ const fontDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "node_modules/@jimp/plugin-print/fonts/open-sans");
48
48
  const fontFolder = `open-sans-${size}-black`;
49
49
  const fontPath = path.join(fontDir, fontFolder, `${fontFolder}.fnt`);
50
50
  return loadFont(fontPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/brother-label",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "description": "API and CLI for printing labels on Brother P-touch printers",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -50,7 +50,7 @@
50
50
  "qrcode": "^1.5.4"
51
51
  },
52
52
  "devDependencies": {
53
- "@types/node": "^20.0.0",
53
+ "@types/node": "^25.2.1",
54
54
  "@types/qrcode": "^1.5.6",
55
55
  "typescript": "^5.0.0"
56
56
  },