@qrdx/cli 0.0.7 → 0.0.9

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.
Files changed (2) hide show
  1. package/dist/index.js +21 -40
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import { readFileSync, mkdirSync, writeFileSync, createReadStream } from 'fs';
3
3
  import { join, resolve, extname } from 'path';
4
4
  import { readFile } from 'fs/promises';
5
- import { BODY_PATTERN, CORNER_EYE_PATTERNS, CORNER_EYE_DOT_PATTERNS, getTemplateIds, FRAME_STYLES, DEFAULT_FRAME_TEXT, FRAME_TEXT_MAX_LENGTH, DEFAULT_MARGIN, getFrameDimensions, colorConfigSchema, errorLevelSchema, QRCodeSVG, svgToEPS } from 'qrdx';
5
+ import { BODY_PATTERN, CORNER_EYE_PATTERNS, CORNER_EYE_DOT_PATTERNS, getTemplateIds, BUILT_IN_FRAMES, DEFAULT_FRAME_TEXT, FRAME_TEXT_MAX_LENGTH, DEFAULT_MARGIN, getFrameDimensions, colorConfigSchema, errorLevelSchema, QRCodeSVG, svgToEPS, FRAME_STYLES } from 'qrdx';
6
+ import { getQRAsPNG } from 'qrdx/node';
6
7
  import { createElement } from 'react';
7
8
  import { renderToStaticMarkup } from 'react-dom/server';
8
9
  import * as readline from 'readline';
@@ -138,7 +139,6 @@ var OUTPUT_FORMATS = [
138
139
  "webp",
139
140
  "eps"
140
141
  ];
141
- var encodeRaster = (image, format) => format === "webp" ? image.webp({ lossless: true }) : image.png();
142
142
  function buildSVGString(props) {
143
143
  const element = createElement(QRCodeSVG, {
144
144
  size: props.size ?? 512,
@@ -198,24 +198,6 @@ async function buildEPSString(props) {
198
198
  }
199
199
  return await svgToEPS(buildSVGString(epsProps));
200
200
  }
201
- async function findLogoBox(sharp, svgString) {
202
- const imageTag = svgString.match(/<image\b[^>]*?(?:\/>|><\/image>)/)?.[0];
203
- if (!imageTag) {
204
- return null;
205
- }
206
- const markerTag = imageTag.replace(/^<image\b/, '<rect class="qrdx-logo-box"').replace(/\shref="[^"]*"/, "").replace(/(?:\/>|><\/image>)$/, ' fill="#000"/>');
207
- const markerSvg = svgString.replace(imageTag, markerTag).replace(
208
- /<svg\b[^>]*>/,
209
- (open) => `${open}<style>*{visibility:hidden}.qrdx-logo-box{visibility:visible}</style>`
210
- );
211
- const { info } = await sharp(Buffer.from(markerSvg, "utf-8")).png().trim().toBuffer({ resolveWithObject: true });
212
- return {
213
- left: -(info.trimOffsetLeft ?? 0),
214
- top: -(info.trimOffsetTop ?? 0),
215
- width: info.width,
216
- height: info.height
217
- };
218
- }
219
201
  async function saveOutput(options) {
220
202
  const { outputPath, format, ...qrProps } = options;
221
203
  const svgString = buildSVGString(qrProps);
@@ -229,33 +211,24 @@ ${svgString}`;
229
211
  writeFileSync(outputPath, await buildEPSString(qrProps), "utf-8");
230
212
  return;
231
213
  }
214
+ const pngBytes = await getQRAsPNG(qrProps, {
215
+ size: qrProps.size ?? 512,
216
+ loadExternalLogos: true
217
+ });
218
+ if (format === "png") {
219
+ writeFileSync(outputPath, pngBytes);
220
+ return;
221
+ }
232
222
  let sharp;
233
223
  try {
234
224
  const mod = await import('sharp');
235
225
  sharp = mod.default;
236
226
  } catch {
237
227
  throw new Error(
238
- `${format === "webp" ? "WebP" : "PNG"} output needs the sharp package (native binaries). It is optional and may not have installed; use SVG or reinstall: https://sharp.pixelplumbing.com/install`
228
+ "WebP output needs the sharp package (native binaries). It is optional and may not have installed; use SVG or reinstall: https://sharp.pixelplumbing.com/install"
239
229
  );
240
230
  }
241
- const svgBuffer = Buffer.from(svgString, "utf-8");
242
- const size = qrProps.size ?? 512;
243
- const { width, height } = getFrameDimensions(size, qrProps.frame);
244
- const qrImage = sharp(svgBuffer).resize(
245
- Math.round(width),
246
- Math.round(height)
247
- );
248
- const logoSrc = qrProps.imageSettings?.src;
249
- const box = logoSrc ? await findLogoBox(sharp, svgString) : null;
250
- if (!(logoSrc && box)) {
251
- await encodeRaster(qrImage, format).toFile(outputPath);
252
- return;
253
- }
254
- const logo = await sharp(await loadLogo(logoSrc)).resize(box.width, box.height, { fit: "fill" }).png().toBuffer();
255
- const composited = sharp(await qrImage.png().toBuffer()).composite([
256
- { input: logo, left: box.left, top: box.top }
257
- ]);
258
- await encodeRaster(composited, format).toFile(outputPath);
231
+ await sharp(Buffer.from(pngBytes)).webp({ lossless: true }).toFile(outputPath);
259
232
  }
260
233
  var RESET = "\x1B[0m";
261
234
  var TEXT = "\x1B[38;5;145m";
@@ -869,7 +842,15 @@ async function runGenerate(args, meta) {
869
842
  if (flags.frame === void 0 && !frame) {
870
843
  const res = await p.select({
871
844
  message: `Frame ${DIM}(call-to-action label around the code)${RESET}`,
872
- options: FRAME_STYLES.map((style) => ({ value: style, label: style })),
845
+ // Every built-in frame, by its style name and its name
846
+ options: [
847
+ { value: "none", label: "none" },
848
+ ...BUILT_IN_FRAMES.map((item) => ({
849
+ value: item.style,
850
+ label: item.style,
851
+ hint: item.name
852
+ }))
853
+ ],
873
854
  initialValue: "none"
874
855
  });
875
856
  if (isCancel2(res)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qrdx/cli",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "QR code generator CLI for developers: styled SVG, PNG, WebP and vector EPS QR codes from the command line",
5
5
  "keywords": [
6
6
  "qr-code",
@@ -45,7 +45,7 @@
45
45
  "dependencies": {
46
46
  "@clack/prompts": "^1.8.1",
47
47
  "picocolors": "^1.1.1",
48
- "qrdx": "0.0.49",
48
+ "qrdx": "0.0.52",
49
49
  "react": "19.3.1",
50
50
  "react-dom": "19.3.1"
51
51
  },