qrlayout-core 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -1,108 +1,140 @@
1
1
  # qrlayout-core
2
2
 
3
- Print-ready QR label layout engine. Build a label template with text/QR/image blocks, then export as PNG, PDF, or ZPL.
3
+ A powerful, framework-agnostic engine for designing and printing QR code sticker layouts. Create pixel-perfect labels with text and QR codes, and export them to **PNG**, **PDF**, or **ZPL** (Zebra Programming Language).
4
4
 
5
5
  > [!NOTE]
6
- > This package was previously published as `@shashi089/qrlayout-core`. Please update your dependencies to `qrlayout-core`.
6
+ > This package is the core rendering engine. For a visual drag-and-drop designer and a live React example, visit our **[Live Demo](https://qr-layout-design-react-demo.netlify.app/)**.
7
7
 
8
- ## Install
8
+ ## Features
9
+
10
+ - **Precise Layouts**: Define stickers in `mm`, `cm`, `in`, or `px`.
11
+ - **Multiple Formats**: Export to Canvas (preview), PNG/JPEG (image), PDF (print), or ZPL (industrial thermal printers).
12
+ - **Dynamic Content**: Use variable placeholders (e.g., `{{name}}`, `{{sku}}`) to batch generate unique stickers.
13
+ - **Lightweight**: Minimal dependencies. PDF export is optional to keep bundle size small.
14
+
15
+ ## Live Demo & Examples
16
+
17
+ - **[Interactive React Demo](https://qr-layout-design-react-demo.netlify.app/)**: A full-featured designer built with this package.
18
+ - **[React Demo Source Code](https://github.com/shashi089/qr-code-layout-generate-tool/tree/example/demo-react)**: Reference implementation for monorepo usage.
19
+
20
+ ## Installation
9
21
 
10
22
  ```bash
11
23
  npm install qrlayout-core
12
24
  ```
13
25
 
14
- ## Quick start
26
+ ## Quick Start
27
+
28
+ ### 1. Define a Layout
29
+
30
+ A layout is a JSON object describing the sticker dimensions and elements.
15
31
 
16
32
  ```ts
17
- import { StickerPrinter, type StickerLayout } from "qrlayout-core";
33
+ import { type StickerLayout } from "qrlayout-core";
18
34
 
19
- const layout: StickerLayout = {
20
- id: "layout-1",
21
- name: "Badge",
22
- width: 100,
23
- height: 60,
35
+ const myLayout: StickerLayout = {
36
+ id: "badge-layout",
37
+ name: "Conference Badge",
38
+ width: 100, // 100mm width
39
+ height: 60, // 60mm height
24
40
  unit: "mm",
25
41
  elements: [
26
- { id: "title", type: "text", x: 0, y: 5, w: 100, h: 10, content: "CONFERENCE PASS" },
27
- { id: "name", type: "text", x: 5, y: 25, w: 60, h: 10, content: "{{name}}" },
28
- { id: "qr", type: "qr", x: 70, y: 20, w: 25, h: 25, content: "{{uuid}}" }
42
+ {
43
+ id: "title",
44
+ type: "text",
45
+ x: 0, y: 5, w: 100, h: 10,
46
+ content: "VISITOR PASS",
47
+ style: { fontSize: 14, fontWeight: "bold", textAlign: "center" }
48
+ },
49
+ {
50
+ id: "name",
51
+ type: "text",
52
+ x: 5, y: 25, w: 60, h: 10,
53
+ content: "{{name}}", // Placeholder
54
+ style: { fontSize: 12 }
55
+ },
56
+ {
57
+ id: "qr-code",
58
+ type: "qr",
59
+ x: 70, y: 20, w: 25, h: 25,
60
+ content: "{{visitorId}}" // Placeholder
61
+ }
29
62
  ]
30
63
  };
64
+ ```
31
65
 
32
- const data = { name: "John Doe", uuid: "https://example.com" };
33
- const printer = new StickerPrinter();
66
+ ### 2. Render or Export
34
67
 
35
- // Browser canvas preview
36
- const canvas = document.getElementById("preview-canvas") as HTMLCanvasElement;
37
- await printer.renderToCanvas(layout, data, canvas);
68
+ Pass data to the `StickerPrinter` to generate outputs.
38
69
 
39
- // PNG
40
- const png = await printer.renderToDataURL(layout, data, { format: "png" });
70
+ ```ts
71
+ import { StickerPrinter } from "qrlayout-core";
41
72
 
42
- // PDF
43
- const pdf = await printer.exportToPDF(layout, [data]);
44
- pdf.save("stickers.pdf");
73
+ // Data to fill placeholders
74
+ const data = {
75
+ name: "Priyanka Verma",
76
+ visitorId: "https://example.com/visitors/priyanka"
77
+ };
45
78
 
46
- // ZPL
47
- const zpl = printer.exportToZPL(layout, [data]);
48
- console.log(zpl[0]);
49
- ```
79
+ const printer = new StickerPrinter();
50
80
 
51
- ## Layout schema
81
+ // --- Option A: Render to HTML Canvas (Browser) ---
82
+ const canvas = document.querySelector("#preview") as HTMLCanvasElement;
83
+ await printer.renderToCanvas(myLayout, data, canvas);
84
+
85
+ // --- Option B: Get an Image URL (PNG) ---
86
+ const imageUrl = await printer.renderToDataURL(myLayout, data, { format: "png", dpi: 300 });
87
+ console.log(imageUrl); // "data:image/png;base64,..."
88
+
89
+ // --- Option C: Generate ZPL for Thermal Printers ---
90
+ const zplCommands = printer.exportToZPL(myLayout, [data]);
91
+ console.log(zplCommands[0]); // "^XA^FO..."
52
92
 
53
- ```ts
54
- type Unit = "mm" | "px" | "cm" | "in";
55
- type ElementType = "text" | "qr" | "image";
56
-
57
- interface StickerElement {
58
- id: string;
59
- type: ElementType;
60
- x: number;
61
- y: number;
62
- w: number;
63
- h: number;
64
- content: string; // supports {{placeholders}}
65
- style?: {
66
- fontFamily?: string;
67
- fontSize?: number;
68
- fontWeight?: string | number;
69
- textAlign?: "left" | "center" | "right";
70
- color?: string;
71
- backgroundColor?: string;
72
- };
73
- }
74
-
75
- interface StickerLayout {
76
- id: string;
77
- name: string;
78
- width: number;
79
- height: number;
80
- unit: Unit;
81
- elements: StickerElement[];
82
- backgroundColor?: string;
83
- backgroundImage?: string;
84
- }
85
93
  ```
86
94
 
87
- ## Outputs
95
+ ## PDF Export (Optional)
88
96
 
89
- - `renderToCanvas` for live preview in the browser
90
- - `renderToDataURL` for PNG/JPEG/WebP export
91
- - `exportToPDF` for print-ready PDF (optional)
92
- - `exportToZPL` for Zebra printers
97
+ To enable PDF export, you must install `jspdf`. This is an optional peer dependency to prevent bloating the core library for users who don't need PDF support.
93
98
 
94
- ## Optional PDF export
99
+ ### 1. Install jspdf
100
+
101
+ ```bash
102
+ npm install jspdf
103
+ ```
95
104
 
96
- PDF export is isolated in a separate entry so users can avoid the `jspdf` dependency unless needed.
105
+ ### 2. Use the PDF Module
97
106
 
98
107
  ```ts
99
108
  import { exportToPDF } from "qrlayout-core/pdf";
109
+
110
+ // Generate a PDF with multiple stickers (e.g., standard A4 sheet logic can be handled by caller,
111
+ // this function currently outputs one page per sticker or as configured).
112
+ const pdfDoc = await exportToPDF(myLayout, [data, data2, data3]);
113
+
114
+ // Save the PDF
115
+ pdfDoc.save("badges.pdf");
100
116
  ```
101
117
 
102
- If `jspdf` is not installed, `StickerPrinter.exportToPDF()` will throw a clear error.
118
+ ## API Reference
119
+
120
+ ### `StickerLayout` Interface
121
+
122
+ | Property | Type | Description |
123
+ |----------|------|-------------|
124
+ | `width` | `number` | Width of the sticker. |
125
+ | `height` | `number` | Height of the sticker. |
126
+ | `unit` | `"mm" \| "cm" \| "in" \| "px"` | Unit of measurement. |
127
+ | `elements` | `StickerElement[]` | List of items on the sticker. |
128
+
129
+ ### `StickerElement` Interface
130
+
131
+ | Property | Type | Description |
132
+ |----------|------|-------------|
133
+ | `type` | `"text" \| "qr"` | Type of element. |
134
+ | `x`, `y` | `number` | Position from top-left. |
135
+ | `w`, `h` | `number` | Width and height. |
136
+ | `content` | `string` | Text, URL, or image source. Supports `{{key}}` syntax. |
103
137
 
104
- ## Notes
138
+ ## License
105
139
 
106
- - Text alignment is horizontal only (left/center/right).
107
- - For ZPL, images are not embedded (text and QR only).
108
- - When using external images in the browser, CORS headers are required or the canvas export will fail.
140
+ MIT
@@ -1,10 +1,11 @@
1
1
  export type Unit = "mm" | "px" | "cm" | "in";
2
- export type ElementType = "text" | "qr" | "image";
2
+ export type ElementType = "text" | "qr";
3
3
  export interface ElementStyle {
4
4
  fontFamily?: string;
5
5
  fontSize?: number;
6
6
  fontWeight?: string | number;
7
7
  textAlign?: "left" | "center" | "right";
8
+ verticalAlign?: "top" | "middle" | "bottom";
8
9
  color?: string;
9
10
  backgroundColor?: string;
10
11
  }
package/dist/pdf.js CHANGED
@@ -59,16 +59,6 @@ export async function exportToPDF(layout, dataList) {
59
59
  doc.addImage(qrUrl, "PNG", x, y, w, h);
60
60
  }
61
61
  }
62
- else if (element.type === "image") {
63
- if (filledContent) {
64
- try {
65
- doc.addImage(filledContent, "PNG", x, y, w, h);
66
- }
67
- catch (e) {
68
- console.warn("Could not add image to PDF", e);
69
- }
70
- }
71
- }
72
62
  else if (element.type === "text") {
73
63
  const style = element.style || {};
74
64
  const fontSize = style.fontSize || 12;
@@ -81,8 +71,14 @@ export async function exportToPDF(layout, dataList) {
81
71
  drawX = x + w / 2;
82
72
  if (align === "right")
83
73
  drawX = x + w;
84
- doc.text(filledContent, drawX, y, {
85
- baseline: "top",
74
+ let drawY = y;
75
+ const vAlign = style.verticalAlign || "top";
76
+ if (vAlign === "middle")
77
+ drawY = y + h / 2;
78
+ if (vAlign === "bottom")
79
+ drawY = y + h;
80
+ doc.text(filledContent, drawX, drawY, {
81
+ baseline: vAlign === "middle" ? "middle" : (vAlign === "bottom" ? "bottom" : "top"),
86
82
  align: align
87
83
  });
88
84
  }
@@ -51,11 +51,6 @@ export class StickerPrinter {
51
51
  else if (element.type === "text") {
52
52
  this.drawText(ctx, element, filledContent, x, y, w, h);
53
53
  }
54
- else if (element.type === "image") {
55
- if (filledContent) { // Assume content is URL
56
- await this.drawImage(ctx, filledContent, x, y, w, h);
57
- }
58
- }
59
54
  }
60
55
  }
61
56
  async renderToDataURL(layout, data, options) {
@@ -79,15 +74,22 @@ export class StickerPrinter {
79
74
  const fontWeight = style.fontWeight || "normal";
80
75
  ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
81
76
  ctx.fillStyle = style.color || "#000";
82
- ctx.textBaseline = "top";
77
+ // Handle Vertical Alignment (textBaseline)
78
+ ctx.textBaseline = style.verticalAlign === "middle" ? "middle" : (style.verticalAlign === "bottom" ? "bottom" : "top");
83
79
  ctx.textAlign = style.textAlign || "left";
84
- // Handle Alignment X adjusment
80
+ // Handle Horizontal Alignment X adjustment
85
81
  let drawX = x;
86
82
  if (style.textAlign === "center")
87
83
  drawX = x + w / 2;
88
84
  if (style.textAlign === "right")
89
85
  drawX = x + w;
90
- ctx.fillText(text, drawX, y);
86
+ // Handle Vertical Alignment Y adjustment
87
+ let drawY = y;
88
+ if (style.verticalAlign === "middle")
89
+ drawY = y + h / 2;
90
+ if (style.verticalAlign === "bottom")
91
+ drawY = y + h;
92
+ ctx.fillText(text, drawX, drawY);
91
93
  }
92
94
  drawImage(ctx, url, x, y, w, h) {
93
95
  return new Promise((resolve) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qrlayout-core",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "QR sticker layout builder/renderer/exporter core",
5
5
  "author": "Shashidhar Naik <shashidharnaik8@gmail.com>",
6
6
  "license": "MIT",