Working tree changes 2024-07-28 00:00
All checks were successful
Test project build / Build (push) Successful in 1m6s
All checks were successful
Test project build / Build (push) Successful in 1m6s
This commit is contained in:
parent
16324d5f5f
commit
266a392401
28
niimblue/src/lib/GenericObjectParamsControls.svelte
Normal file
28
niimblue/src/lib/GenericObjectParamsControls.svelte
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { fabric } from "fabric";
|
||||||
|
import FaIcon from "./FaIcon.svelte";
|
||||||
|
|
||||||
|
export let selectedObject: fabric.Object;
|
||||||
|
export let valueUpdated: () => void;
|
||||||
|
|
||||||
|
const putToCenterV = () => {
|
||||||
|
selectedObject.canvas?.centerObjectH(selectedObject);
|
||||||
|
selectedObject.centerV();
|
||||||
|
valueUpdated();
|
||||||
|
};
|
||||||
|
|
||||||
|
const putToCenterH = () => {
|
||||||
|
selectedObject.centerH();
|
||||||
|
valueUpdated();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<button class="btn btn-sm btn-secondary" on:click={putToCenterV} title="Center vertically">
|
||||||
|
<FaIcon icon="up-down" />
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-secondary" on:click={putToCenterH} title="Center horizontally">
|
||||||
|
<FaIcon icon="left-right" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
@ -9,6 +9,7 @@
|
|||||||
import FaIcon from "./FaIcon.svelte";
|
import FaIcon from "./FaIcon.svelte";
|
||||||
import PrintPreview from "./PrintPreview.svelte";
|
import PrintPreview from "./PrintPreview.svelte";
|
||||||
import TextParamsPanel from "./TextParamsControls.svelte";
|
import TextParamsPanel from "./TextParamsControls.svelte";
|
||||||
|
import GenericObjectParamsControls from "./GenericObjectParamsControls.svelte";
|
||||||
|
|
||||||
let htmlCanvas: HTMLCanvasElement;
|
let htmlCanvas: HTMLCanvasElement;
|
||||||
let fabricCanvas: fabric.Canvas;
|
let fabricCanvas: fabric.Canvas;
|
||||||
@ -94,9 +95,10 @@
|
|||||||
if (name === "text") {
|
if (name === "text") {
|
||||||
const obj = new fabric.IText("Text", {
|
const obj = new fabric.IText("Text", {
|
||||||
...fabricObjectDefaults,
|
...fabricObjectDefaults,
|
||||||
fontFamily: "Arial",
|
fontFamily: "Arial"
|
||||||
});
|
});
|
||||||
fabricCanvas.add(obj);
|
fabricCanvas.add(obj);
|
||||||
|
obj.center();
|
||||||
} else if (name === "line") {
|
} else if (name === "line") {
|
||||||
const obj = new fabric.Line([10, 10, 10 + defaultSize, 10], {
|
const obj = new fabric.Line([10, 10, 10 + defaultSize, 10], {
|
||||||
...fabricObjectDefaults,
|
...fabricObjectDefaults,
|
||||||
@ -111,8 +113,8 @@
|
|||||||
mt: false,
|
mt: false,
|
||||||
mb: false,
|
mb: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
fabricCanvas.add(obj);
|
fabricCanvas.add(obj);
|
||||||
|
obj.centerV();
|
||||||
} else if (name === "circle") {
|
} else if (name === "circle") {
|
||||||
const obj = new fabric.Circle({
|
const obj = new fabric.Circle({
|
||||||
...fabricObjectDefaults,
|
...fabricObjectDefaults,
|
||||||
@ -122,6 +124,7 @@
|
|||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
});
|
});
|
||||||
fabricCanvas.add(obj);
|
fabricCanvas.add(obj);
|
||||||
|
obj.centerV();
|
||||||
} else if (name === "rectangle") {
|
} else if (name === "rectangle") {
|
||||||
const obj = new fabric.Rect({
|
const obj = new fabric.Rect({
|
||||||
...fabricObjectDefaults,
|
...fabricObjectDefaults,
|
||||||
@ -132,6 +135,7 @@
|
|||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
});
|
});
|
||||||
fabricCanvas.add(obj);
|
fabricCanvas.add(obj);
|
||||||
|
obj.centerV();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -288,8 +292,9 @@
|
|||||||
<button class="btn btn-sm btn-danger me-1" on:click={deleteSelected}><FaIcon icon="trash" /></button>
|
<button class="btn btn-sm btn-danger me-1" on:click={deleteSelected}><FaIcon icon="trash" /></button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if selectedCount === 1}
|
{#if selectedObject && selectedCount === 1}
|
||||||
<button class="btn btn-sm btn-secondary me-1" on:click={cloneSelected}><FaIcon icon="clone" /></button>
|
<button class="btn btn-sm btn-secondary me-1" on:click={cloneSelected}><FaIcon icon="clone" /></button>
|
||||||
|
<GenericObjectParamsControls {selectedObject} valueUpdated={() => fabricCanvas.requestRenderAll()} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if selectedObject instanceof fabric.IText}
|
{#if selectedObject instanceof fabric.IText}
|
||||||
|
@ -7,19 +7,14 @@
|
|||||||
import {
|
import {
|
||||||
type EncodedImage,
|
type EncodedImage,
|
||||||
ImageEncoder,
|
ImageEncoder,
|
||||||
Utils,
|
|
||||||
LabelType,
|
|
||||||
PacketGenerator,
|
PacketGenerator,
|
||||||
ProtocolVariant,
|
ProtocolVersion,
|
||||||
ResponseCommandId,
|
|
||||||
PrintError,
|
|
||||||
} from "@mmote/niimbluelib";
|
} from "@mmote/niimbluelib";
|
||||||
import type { LabelProps } from "../types";
|
import type { LabelProps } from "../types";
|
||||||
import FaIcon from "./FaIcon.svelte";
|
import FaIcon from "./FaIcon.svelte";
|
||||||
|
|
||||||
export let onClosed: () => void;
|
export let onClosed: () => void;
|
||||||
export let labelProps: LabelProps;
|
export let labelProps: LabelProps;
|
||||||
|
|
||||||
export let imageCallback: () => string;
|
export let imageCallback: () => string;
|
||||||
|
|
||||||
let modalElement: HTMLElement;
|
let modalElement: HTMLElement;
|
||||||
@ -34,7 +29,7 @@
|
|||||||
let thresholdValue: number = 140;
|
let thresholdValue: number = 140;
|
||||||
let imgData: ImageData;
|
let imgData: ImageData;
|
||||||
let imgContext: CanvasRenderingContext2D;
|
let imgContext: CanvasRenderingContext2D;
|
||||||
let protoVariant: ProtocolVariant = ProtocolVariant.V3;
|
let printTaskVersion: ProtocolVersion = ProtocolVersion.V3;
|
||||||
let statusTimer: NodeJS.Timeout | undefined = undefined;
|
let statusTimer: NodeJS.Timeout | undefined = undefined;
|
||||||
let printError: boolean = false;
|
let printError: boolean = false;
|
||||||
|
|
||||||
@ -54,7 +49,7 @@
|
|||||||
const onPrint = async () => {
|
const onPrint = async () => {
|
||||||
printError = false;
|
printError = false;
|
||||||
const encoded: EncodedImage = ImageEncoder.encodeCanvas(previewCanvas, labelProps.startPos);
|
const encoded: EncodedImage = ImageEncoder.encodeCanvas(previewCanvas, labelProps.startPos);
|
||||||
const packets = PacketGenerator.generatePrintSequence(protoVariant, encoded, { quantity, density });
|
const packets = PacketGenerator.generatePrintSequence(printTaskVersion, encoded, { quantity, density });
|
||||||
|
|
||||||
for (let i = 0; i < packets.length; i++) {
|
for (let i = 0; i < packets.length; i++) {
|
||||||
sendProgress = Math.round(((i + 1) / packets.length) * 100);
|
sendProgress = Math.round(((i + 1) / packets.length) * 100);
|
||||||
@ -92,15 +87,14 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
// create image from fabric canvas to work with
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
previewCanvas.width = img.width;
|
previewCanvas.width = img.width;
|
||||||
previewCanvas.height = img.height;
|
previewCanvas.height = img.height;
|
||||||
|
|
||||||
imgContext = previewCanvas.getContext("2d")!;
|
imgContext = previewCanvas.getContext("2d")!;
|
||||||
imgContext.drawImage(img, 0, 0, img.width, img.height);
|
imgContext.drawImage(img, 0, 0, img.width, img.height);
|
||||||
imgData = imgContext.getImageData(0, 0, img.width, img.height);
|
imgData = imgContext.getImageData(0, 0, img.width, img.height);
|
||||||
|
|
||||||
updatePreview();
|
updatePreview();
|
||||||
};
|
};
|
||||||
img.src = imageCallback();
|
img.src = imageCallback();
|
||||||
@ -111,6 +105,12 @@
|
|||||||
cancelPrint();
|
cancelPrint();
|
||||||
onClosed();
|
onClosed();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const taskVer = $printerClient?.getCapabilities().printTaskVersion;
|
||||||
|
if (taskVer !== undefined && taskVer !== ProtocolVersion.UNKNOWN) {
|
||||||
|
console.log(`Detected print task version: ${ProtocolVersion[taskVer]}`)
|
||||||
|
printTaskVersion = taskVer;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
@ -192,10 +192,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
<span class="input-group-text">Protocol variant</span>
|
<span class="input-group-text">Print task version</span>
|
||||||
<select class="form-select" bind:value={protoVariant}>
|
<select class="form-select" bind:value={printTaskVersion}>
|
||||||
<option value={ProtocolVariant.V3}>V3 - D110</option>
|
<option value={ProtocolVersion.V1} disabled>V1 - NOT IMPLEMENTED</option>
|
||||||
<option value={ProtocolVariant.V4}>V4 - B1</option>
|
<option value={ProtocolVersion.V2} disabled>V2 - NOT IMPLEMENTED</option>
|
||||||
|
<option value={ProtocolVersion.V3}>V3 - D110</option>
|
||||||
|
<option value={ProtocolVersion.V4}>V4 - B1</option>
|
||||||
|
<option value={ProtocolVersion.V5} disabled>V5 - NOT IMPLEMENTED</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { PrinterModelId, type RfidInfo } from "@mmote/niimbluelib";
|
import { PrinterModel, type RfidInfo } from "@mmote/niimbluelib";
|
||||||
import { printerClient, connectedPrinterName, connectionState, initClient, heartbeatData, printerConfig } from "../stores";
|
import { printerClient, connectedPrinterName, connectionState, initClient, heartbeatData, printerConfig } from "../stores";
|
||||||
import type { ConnectionType } from "../types";
|
import type { ConnectionType } from "../types";
|
||||||
import FaIcon from "./FaIcon.svelte";
|
import FaIcon from "./FaIcon.svelte";
|
||||||
@ -36,11 +36,6 @@
|
|||||||
// clearInterval(timer);
|
// clearInterval(timer);
|
||||||
$printerClient.stopHeartbeat();
|
$printerClient.stopHeartbeat();
|
||||||
};
|
};
|
||||||
|
|
||||||
const test3 = async () => {
|
|
||||||
const id = await $printerClient.abstraction.getPrinterModel();
|
|
||||||
alert(`Printer model: ${PrinterModelId[id]}`);
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="input-group flex-nowrap justify-content-end">
|
<div class="input-group flex-nowrap justify-content-end">
|
||||||
@ -49,24 +44,33 @@
|
|||||||
><FaIcon icon="gear" />
|
><FaIcon icon="gear" />
|
||||||
</button>
|
</button>
|
||||||
<div class="dropdown-menu p-1">
|
<div class="dropdown-menu p-1">
|
||||||
|
<div>
|
||||||
|
Model: {$printerConfig.model === undefined ? "?" : (PrinterModel[$printerConfig.model] ?? "Unknown")}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
Printer info:
|
Printer info:
|
||||||
<pre>{JSON.stringify($printerConfig, null, 1)}</pre>
|
<pre>{JSON.stringify($printerConfig, null, 1)}</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Rfid info:
|
||||||
|
<pre>{JSON.stringify(rfidInfo || {}, null, 1)}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
Heartbeat data:
|
Heartbeat data:
|
||||||
<pre>{JSON.stringify($heartbeatData, null, 1)}</pre>
|
<pre>{JSON.stringify($heartbeatData, null, 1)}</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
Rfid info:
|
Tests
|
||||||
<pre>{JSON.stringify(rfidInfo || {}, null, 1)}</pre>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm btn-primary" on:click={getRfidInfo}>RfidInfo</button>
|
|
||||||
<button class="btn btn-sm btn-primary" on:click={startHeartbeat}>start heartbeat (test)</button>
|
<button class="btn btn-sm btn-primary" on:click={getRfidInfo}>Rfid</button>
|
||||||
<button class="btn btn-sm btn-primary" on:click={stopHeartbeat}>stop heartbeat (test)</button>
|
<button class="btn btn-sm btn-primary" on:click={startHeartbeat}>Heartbeat on</button>
|
||||||
<button class="btn btn-sm btn-primary" on:click={test3}>Guess printer model</button>
|
<button class="btn btn-sm btn-primary" on:click={stopHeartbeat}>Heartbeat off</button>
|
||||||
</div>
|
</div>
|
||||||
<span class="input-group-text">{$connectedPrinterName}</span>
|
<span class="input-group-text">{$connectedPrinterName}</span>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -54,14 +54,17 @@
|
|||||||
{#if selectedText}
|
{#if selectedText}
|
||||||
<!-- <div class="d-flex flex-wrap gap-1"> -->
|
<!-- <div class="d-flex flex-wrap gap-1"> -->
|
||||||
<button
|
<button
|
||||||
|
title="Align text: Left"
|
||||||
class="btn btn-sm {selectedText.textAlign === 'left' ? 'btn-secondary' : ''}"
|
class="btn btn-sm {selectedText.textAlign === 'left' ? 'btn-secondary' : ''}"
|
||||||
on:click={() => setAlign("left")}><FaIcon icon="align-left" /></button
|
on:click={() => setAlign("left")}><FaIcon icon="align-left" /></button
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
|
title="Align text: Center"
|
||||||
class="btn btn-sm {selectedText.textAlign === 'center' ? 'btn-secondary' : ''}"
|
class="btn btn-sm {selectedText.textAlign === 'center' ? 'btn-secondary' : ''}"
|
||||||
on:click={() => setAlign("center")}><FaIcon icon="align-center" /></button
|
on:click={() => setAlign("center")}><FaIcon icon="align-center" /></button
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
|
title="Align text: Right"
|
||||||
class="btn btn-sm {selectedText.textAlign === 'right' ? 'btn-secondary' : ''}"
|
class="btn btn-sm {selectedText.textAlign === 'right' ? 'btn-secondary' : ''}"
|
||||||
on:click={() => setAlign("right")}><FaIcon icon="align-right" /></button
|
on:click={() => setAlign("right")}><FaIcon icon="align-right" /></button
|
||||||
>
|
>
|
||||||
|
@ -2,25 +2,12 @@ export const copyImageData = (iData: ImageData): ImageData => {
|
|||||||
return new ImageData(new Uint8ClampedArray(iData.data), iData.width, iData.height);
|
return new ImageData(new Uint8ClampedArray(iData.data), iData.width, iData.height);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const convertImgDataToBlackAndWhite = (iData: ImageData, threshold = 0xff): ImageData => {
|
// Original code is taken from https://github.com/NielsLeenheer/CanvasDither
|
||||||
for (let x = 0; x < iData.width; x++) {
|
|
||||||
for (let i = 0; i < iData.data.byteLength / 4; i++) {
|
|
||||||
const pos = i * 4;
|
|
||||||
const b =
|
|
||||||
iData.data[pos] >= threshold || iData.data[pos + 1] >= threshold || iData.data[pos + 2] >= threshold ? 0xff : 0;
|
|
||||||
iData.data[pos] = b;
|
|
||||||
iData.data[pos + 1] = b;
|
|
||||||
iData.data[pos + 2] = b;
|
|
||||||
iData.data[pos + 3] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return iData;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the image to blank and white using a simple threshold
|
* Change the image to blank and white using a simple threshold
|
||||||
*
|
*
|
||||||
|
*
|
||||||
* @param {object} image The imageData of a Canvas 2d context
|
* @param {object} image The imageData of a Canvas 2d context
|
||||||
* @param {number} threshold Threshold value (0-255)
|
* @param {number} threshold Threshold value (0-255)
|
||||||
* @return {object} The resulting imageData
|
* @return {object} The resulting imageData
|
||||||
@ -29,7 +16,6 @@ export const convertImgDataToBlackAndWhite = (iData: ImageData, threshold = 0xff
|
|||||||
export const threshold = (image: ImageData, threshold: number): ImageData => {
|
export const threshold = (image: ImageData, threshold: number): ImageData => {
|
||||||
for (let i = 0; i < image.data.length; i += 4) {
|
for (let i = 0; i < image.data.length; i += 4) {
|
||||||
const luminance = image.data[i] * 0.299 + image.data[i + 1] * 0.587 + image.data[i + 2] * 0.114;
|
const luminance = image.data[i] * 0.299 + image.data[i + 1] * 0.587 + image.data[i + 2] * 0.114;
|
||||||
|
|
||||||
const value = luminance < threshold ? 0 : 255;
|
const value = luminance < threshold ? 0 : 255;
|
||||||
image.data.fill(value, i, i + 3);
|
image.data.fill(value, i, i + 3);
|
||||||
}
|
}
|
||||||
@ -37,68 +23,11 @@ export const threshold = (image: ImageData, threshold: number): ImageData => {
|
|||||||
return image;
|
return image;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the image to blank and white using the Bayer algorithm
|
|
||||||
*
|
|
||||||
* @param {object} image The imageData of a Canvas 2d context
|
|
||||||
* @param {number} threshold Threshold value (0-255)
|
|
||||||
* @return {object} The resulting imageData
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const bayer = (image: ImageData, threshold: number): ImageData => {
|
|
||||||
const thresholdMap = [
|
|
||||||
[15, 135, 45, 165],
|
|
||||||
[195, 75, 225, 105],
|
|
||||||
[60, 180, 30, 150],
|
|
||||||
[240, 120, 210, 90],
|
|
||||||
];
|
|
||||||
|
|
||||||
for (let i = 0; i < image.data.length; i += 4) {
|
|
||||||
const luminance = image.data[i] * 0.299 + image.data[i + 1] * 0.587 + image.data[i + 2] * 0.114;
|
|
||||||
|
|
||||||
const x = (i / 4) % image.width;
|
|
||||||
const y = Math.floor(i / 4 / image.width);
|
|
||||||
const map = Math.floor((luminance + thresholdMap[x % 4][y % 4]) / 2);
|
|
||||||
const value = map < threshold ? 0 : 255;
|
|
||||||
image.data.fill(value, i, i + 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Change the image to blank and white using the Floyd-Steinberg algorithm
|
|
||||||
*
|
|
||||||
* @param {object} image The imageData of a Canvas 2d context
|
|
||||||
* @return {object} The resulting imageData
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const floydsteinberg = (image: ImageData, threshold: number): ImageData => {
|
|
||||||
const width = image.width;
|
|
||||||
const luminance = new Uint8ClampedArray(image.width * image.height);
|
|
||||||
|
|
||||||
for (let l = 0, i = 0; i < image.data.length; l++, i += 4) {
|
|
||||||
luminance[l] = image.data[i] * 0.299 + image.data[i + 1] * 0.587 + image.data[i + 2] * 0.114;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let l = 0, i = 0; i < image.data.length; l++, i += 4) {
|
|
||||||
const value = luminance[l] < threshold ? 0 : 255;
|
|
||||||
const error = Math.floor((luminance[l] - value) / 16);
|
|
||||||
image.data.fill(value, i, i + 3);
|
|
||||||
|
|
||||||
luminance[l + 1] += error * 7;
|
|
||||||
luminance[l + width - 1] += error * 3;
|
|
||||||
luminance[l + width] += error * 5;
|
|
||||||
luminance[l + width + 1] += error * 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return image;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the image to blank and white using the Atkinson algorithm
|
* Change the image to blank and white using the Atkinson algorithm
|
||||||
*
|
*
|
||||||
* @param {object} image The imageData of a Canvas 2d context
|
* @param {object} image The imageData of a Canvas 2d context
|
||||||
|
* @param {number} threshold Threshold value (0-255)
|
||||||
* @return {object} The resulting imageData
|
* @return {object} The resulting imageData
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -125,35 +54,3 @@ export const atkinson = (image: ImageData, threshold: number): ImageData => {
|
|||||||
|
|
||||||
return image;
|
return image;
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://observablehq.com/@tmcw/dithering
|
|
||||||
export const atkinson2 = (image: ImageData, threshold: number):ImageData => {
|
|
||||||
let GRAYS = 256;
|
|
||||||
let THRESHOLD = [];
|
|
||||||
for (let i = 0; i < GRAYS; i++) {
|
|
||||||
THRESHOLD.push(i < (GRAYS >> 1) ? 0 : GRAYS - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let clone = new ImageData(new Uint8ClampedArray(image.data), image.width, image.height);
|
|
||||||
|
|
||||||
function px(x:number, y:number) {
|
|
||||||
return (x * 4) + (y * image.width * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let y = 0; y < image.height; y++) {
|
|
||||||
for (let x = 0; x < image.width; x++) {
|
|
||||||
let oldPixel = clone.data[px(x, y)];
|
|
||||||
let grayNew = THRESHOLD[oldPixel];
|
|
||||||
let grayErr = (oldPixel - grayNew) >> 3;
|
|
||||||
let newPixel = oldPixel > 125 ? 255 : 0;
|
|
||||||
clone.data[px(x, y)] = clone.data[px(x, y) + 1] = clone.data[px(x, y) + 2] = newPixel;
|
|
||||||
clone.data[px(x, y)] =
|
|
||||||
clone.data[px(x, y) + 1] =
|
|
||||||
clone.data[px(x, y) + 2] = grayNew;
|
|
||||||
[[1, 0], [2, 0], [-1, 1], [0, 1], [1, 1], [0, 2]].forEach(([dx, dy]) => {
|
|
||||||
clone.data[px(x + dx, y + dy)] += grayErr;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clone;
|
|
||||||
}
|
|
@ -52,7 +52,7 @@ export const initClient = (connectionType: ConnectionType) => {
|
|||||||
console.log("onConnect");
|
console.log("onConnect");
|
||||||
connectionState.set("connected");
|
connectionState.set("connected");
|
||||||
connectedPrinterName.set(e.info.deviceName ?? "unknown");
|
connectedPrinterName.set(e.info.deviceName ?? "unknown");
|
||||||
printerConfig.set(newClient.getPrinterConfig());
|
printerConfig.set(newClient.getPrinterInfo());
|
||||||
});
|
});
|
||||||
|
|
||||||
newClient.addEventListener("disconnect", () => {
|
newClient.addEventListener("disconnect", () => {
|
||||||
|
@ -40,7 +40,7 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
|||||||
const disconnectListener = async () => {
|
const disconnectListener = async () => {
|
||||||
this.gattServer = undefined;
|
this.gattServer = undefined;
|
||||||
this.channel = undefined;
|
this.channel = undefined;
|
||||||
this.printerConfig = {};
|
this.info = {};
|
||||||
this.stopHeartbeat();
|
this.stopHeartbeat();
|
||||||
this.dispatchTypedEvent("disconnect", new DisconnectEvent());
|
this.dispatchTypedEvent("disconnect", new DisconnectEvent());
|
||||||
device.removeEventListener("gattserverdisconnected", disconnectListener);
|
device.removeEventListener("gattserverdisconnected", disconnectListener);
|
||||||
@ -73,14 +73,14 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this.initialNegotiate();
|
await this.initialNegotiate();
|
||||||
await this.fetchPrinterConfig();
|
await this.fetchPrinterInfo();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: ConnectionInfo = {
|
const result: ConnectionInfo = {
|
||||||
deviceName: device.name,
|
deviceName: device.name,
|
||||||
result: this.printerConfig.connectResult ?? ConnectResult.FirmwareErrors
|
result: this.info.connectResult ?? ConnectResult.FirmwareErrors
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dispatchTypedEvent("connect", new ConnectEvent(result));
|
this.dispatchTypedEvent("connect", new ConnectEvent(result));
|
||||||
@ -97,7 +97,7 @@ export class NiimbotBluetoothClient extends NiimbotAbstractClient {
|
|||||||
this.gattServer?.disconnect();
|
this.gattServer?.disconnect();
|
||||||
this.gattServer = undefined;
|
this.gattServer = undefined;
|
||||||
this.channel = undefined;
|
this.channel = undefined;
|
||||||
this.printerConfig = {};
|
this.info = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { AutoShutdownTime, BatteryChargeLevel, ConnectResult, NiimbotPacket, PrinterModelId } from "../packets";
|
import { AutoShutdownTime, BatteryChargeLevel, ConnectResult, NiimbotPacket } from "../packets";
|
||||||
import { TypedEventTarget } from "typescript-event-target";
|
import { TypedEventTarget } from "typescript-event-target";
|
||||||
import { ClientEventMap, HeartbeatEvent } from "./events";
|
import { ClientEventMap, HeartbeatEvent } from "./events";
|
||||||
import { Abstraction } from "../packets/abstraction";
|
import { Abstraction } from "../packets/abstraction";
|
||||||
|
import { getPrinterCapabilities, PrinterCapabilities, PrinterModel } from "../printers";
|
||||||
|
|
||||||
export type ConnectionInfo = {
|
export type ConnectionInfo = {
|
||||||
deviceName?: string;
|
deviceName?: string;
|
||||||
@ -11,7 +12,7 @@ export type ConnectionInfo = {
|
|||||||
export interface PrinterConfig {
|
export interface PrinterConfig {
|
||||||
connectResult?: ConnectResult;
|
connectResult?: ConnectResult;
|
||||||
protocolVersion?: number;
|
protocolVersion?: number;
|
||||||
model?: PrinterModelId;
|
model?: PrinterModel;
|
||||||
serial?: string;
|
serial?: string;
|
||||||
mac?: string;
|
mac?: string;
|
||||||
charge?: BatteryChargeLevel;
|
charge?: BatteryChargeLevel;
|
||||||
@ -20,7 +21,7 @@ export interface PrinterConfig {
|
|||||||
|
|
||||||
export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEventMap> {
|
export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEventMap> {
|
||||||
public readonly abstraction: Abstraction;
|
public readonly abstraction: Abstraction;
|
||||||
protected printerConfig: PrinterConfig = {};
|
protected info: PrinterConfig = {};
|
||||||
private heartbeatTimer?: NodeJS.Timeout;
|
private heartbeatTimer?: NodeJS.Timeout;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -56,7 +57,7 @@ export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEvent
|
|||||||
|
|
||||||
/** Send "connect" packet and fetch the protocol version */
|
/** Send "connect" packet and fetch the protocol version */
|
||||||
protected async initialNegotiate(): Promise<void> {
|
protected async initialNegotiate(): Promise<void> {
|
||||||
const cfg = this.printerConfig;
|
const cfg = this.info;
|
||||||
cfg.connectResult = await this.abstraction.connectResult();
|
cfg.connectResult = await this.abstraction.connectResult();
|
||||||
cfg.protocolVersion = 0;
|
cfg.protocolVersion = 0;
|
||||||
|
|
||||||
@ -68,18 +69,18 @@ export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEvent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fetchPrinterConfig(): Promise<PrinterConfig> {
|
public async fetchPrinterInfo(): Promise<PrinterConfig> {
|
||||||
// console.log(await this.abstraction.getPrinterStatusData());
|
// console.log(await this.abstraction.getPrinterStatusData());
|
||||||
this.printerConfig.model = await this.abstraction.getPrinterModel();
|
this.info.model = await this.abstraction.getPrinterModel();
|
||||||
this.printerConfig.serial = await this.abstraction.getPrinterSerialNumber();
|
this.info.serial = await this.abstraction.getPrinterSerialNumber();
|
||||||
this.printerConfig.mac = await this.abstraction.getPrinterBluetoothMacAddress();
|
this.info.mac = await this.abstraction.getPrinterBluetoothMacAddress();
|
||||||
this.printerConfig.charge = await this.abstraction.getBatteryChargeLevel();
|
this.info.charge = await this.abstraction.getBatteryChargeLevel();
|
||||||
this.printerConfig.autoShutdownTime = await this.abstraction.getAutoShutDownTime();
|
this.info.autoShutdownTime = await this.abstraction.getAutoShutDownTime();
|
||||||
return this.printerConfig;
|
return this.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPrinterConfig(): PrinterConfig {
|
public getPrinterInfo(): PrinterConfig {
|
||||||
return this.printerConfig;
|
return this.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,6 +103,11 @@ export abstract class NiimbotAbstractClient extends TypedEventTarget<ClientEvent
|
|||||||
public isHeartbeatStarted(): boolean {
|
public isHeartbeatStarted(): boolean {
|
||||||
return this.heartbeatTimer === undefined;
|
return this.heartbeatTimer === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get printer capabilities based on the printer model */
|
||||||
|
public getCapabilities(): PrinterCapabilities {
|
||||||
|
return getPrinterCapabilities(this.info.model ?? PrinterModel.UNKNOWN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export * from "./events";
|
export * from "./events";
|
||||||
|
@ -30,14 +30,14 @@ export class NiimbotSerialClient extends NiimbotAbstractClient {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this.initialNegotiate();
|
await this.initialNegotiate();
|
||||||
await this.fetchPrinterConfig();
|
await this.fetchPrinterInfo();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result: ConnectionInfo = {
|
const result: ConnectionInfo = {
|
||||||
deviceName: `Serial (VID:${info.usbVendorId?.toString(16)} PID:${info.usbProductId?.toString(16)})`,
|
deviceName: `Serial (VID:${info.usbVendorId?.toString(16)} PID:${info.usbProductId?.toString(16)})`,
|
||||||
result: this.printerConfig.connectResult ?? ConnectResult.FirmwareErrors
|
result: this.info.connectResult ?? ConnectResult.FirmwareErrors
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dispatchTypedEvent("connect", new ConnectEvent(result));
|
this.dispatchTypedEvent("connect", new ConnectEvent(result));
|
||||||
|
@ -95,7 +95,7 @@ export class ImageEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param data Encoded pixels (every byte is 8 pixels)
|
* @param data Pixels encoded by {@link encodeCanvas} (byte is 8 pixels)
|
||||||
* @returns Array of indexes where every index stored in two bytes (big endian)
|
* @returns Array of indexes where every index stored in two bytes (big endian)
|
||||||
*/
|
*/
|
||||||
public static indexPixels(data: Uint8Array): Uint8Array {
|
public static indexPixels(data: Uint8Array): Uint8Array {
|
||||||
|
@ -2,3 +2,4 @@ export * from "./client";
|
|||||||
export * from "./packets";
|
export * from "./packets";
|
||||||
export * from "./image_encoder";
|
export * from "./image_encoder";
|
||||||
export * from "./utils";
|
export * from "./utils";
|
||||||
|
export * from "./printers";
|
||||||
|
@ -7,12 +7,12 @@ import {
|
|||||||
NiimbotPacket,
|
NiimbotPacket,
|
||||||
PacketGenerator,
|
PacketGenerator,
|
||||||
PrinterInfoType,
|
PrinterInfoType,
|
||||||
PrinterModelId,
|
|
||||||
ResponseCommandId,
|
ResponseCommandId,
|
||||||
SoundSettingsItemType,
|
SoundSettingsItemType,
|
||||||
SoundSettingsType,
|
SoundSettingsType,
|
||||||
} from ".";
|
} from ".";
|
||||||
import { NiimbotAbstractClient, Utils, Validators } from "..";
|
import { NiimbotAbstractClient, Utils, Validators } from "..";
|
||||||
|
import { PrinterModel } from "../printers";
|
||||||
import { SequentialDataReader } from "./data_reader";
|
import { SequentialDataReader } from "./data_reader";
|
||||||
|
|
||||||
export class PrintError extends Error {
|
export class PrintError extends Error {
|
||||||
@ -89,10 +89,7 @@ export class Abstraction {
|
|||||||
|
|
||||||
if (packet.command === ResponseCommandId.In_PrintError) {
|
if (packet.command === ResponseCommandId.In_PrintError) {
|
||||||
Validators.u8ArrayLengthEquals(packet.data, 1);
|
Validators.u8ArrayLengthEquals(packet.data, 1);
|
||||||
throw new PrintError(
|
throw new PrintError(`Print error (${ResponseCommandId[packet.command]} packet received)`, packet.data[0]);
|
||||||
`Print error (${ResponseCommandId[packet.command]} packet received)`,
|
|
||||||
packet.data[0]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Validators.u8ArrayLengthAtLeast(packet.data, 4); // can be 8, 10, but ignore it for now
|
Validators.u8ArrayLengthAtLeast(packet.data, 4); // can be 8, 10, but ignore it for now
|
||||||
@ -105,7 +102,10 @@ export class Abstraction {
|
|||||||
if (packet.dataLength === 10) {
|
if (packet.dataLength === 10) {
|
||||||
r.skip(2);
|
r.skip(2);
|
||||||
const error = r.readI8();
|
const error = r.readI8();
|
||||||
throw new PrintError(`Print error (${ResponseCommandId[packet.command]} packet flag)`, error);
|
|
||||||
|
if (error !== 0) {
|
||||||
|
throw new PrintError(`Print error (${ResponseCommandId[packet.command]} packet flag)`, error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { page, pagePrintProgress, pageFeedProgress };
|
return { page, pagePrintProgress, pageFeedProgress };
|
||||||
@ -122,34 +122,34 @@ export class Abstraction {
|
|||||||
const packet = await this.send(PacketGenerator.getPrinterStatusData());
|
const packet = await this.send(PacketGenerator.getPrinterStatusData());
|
||||||
let supportColor = 0;
|
let supportColor = 0;
|
||||||
|
|
||||||
if (packet.dataLength > 12) {
|
if (packet.dataLength > 12) {
|
||||||
supportColor = packet.data[10];
|
supportColor = packet.data[10];
|
||||||
|
|
||||||
let n = packet.data[11] * 100 + packet.data[12];
|
let n = packet.data[11] * 100 + packet.data[12];
|
||||||
if (n >= 204 && n < 300) {
|
if (n >= 204 && n < 300) {
|
||||||
protocolVersion = 3;
|
protocolVersion = 3;
|
||||||
}
|
|
||||||
if (n >= 301) {
|
|
||||||
protocolVersion = 4;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (n >= 301) {
|
||||||
|
protocolVersion = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
supportColor,
|
supportColor,
|
||||||
protocolVersion
|
protocolVersion,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getPrinterModel(): Promise<PrinterModelId> {
|
public async getPrinterModel(): Promise<PrinterModel> {
|
||||||
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.PrinterModelId));
|
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.PrinterModelId));
|
||||||
Validators.u8ArrayLengthEquals(packet.data, 2);
|
Validators.u8ArrayLengthEquals(packet.data, 2);
|
||||||
|
|
||||||
const id = Utils.bytesToI16(packet.data);
|
const id = Utils.bytesToI16(packet.data);
|
||||||
|
|
||||||
if (id in PrinterModelId) {
|
if (id in PrinterModel) {
|
||||||
return id as PrinterModelId;
|
return id as PrinterModel;
|
||||||
}
|
}
|
||||||
return PrinterModelId.UNKNOWN;
|
return PrinterModel.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Read paper nfc tag info */
|
/** Read paper nfc tag info */
|
||||||
@ -224,7 +224,7 @@ export class Abstraction {
|
|||||||
}
|
}
|
||||||
r.end();
|
r.end();
|
||||||
|
|
||||||
const model = this.client.getPrinterConfig().model ?? PrinterModelId.UNKNOWN;
|
const model = this.client.getPrinterInfo().model ?? PrinterModel.UNKNOWN;
|
||||||
|
|
||||||
if (![512, 514, 513, 2304, 1792, 3584, 5120, 2560, 3840, 4352, 272].includes(model)) {
|
if (![512, 514, 513, 2304, 1792, 3584, 5120, 2560, 3840, 4352, 272].includes(model)) {
|
||||||
info.lidClosed = !info.lidClosed;
|
info.lidClosed = !info.lidClosed;
|
||||||
@ -245,6 +245,10 @@ export class Abstraction {
|
|||||||
return packet.data[0] as AutoShutdownTime;
|
return packet.data[0] as AutoShutdownTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async setAutoShutDownTime(time: AutoShutdownTime): Promise<void> {
|
||||||
|
await this.send(PacketGenerator.setAutoShutDownTime(time));
|
||||||
|
}
|
||||||
|
|
||||||
public async getLabelType(): Promise<LabelType> {
|
public async getLabelType(): Promise<LabelType> {
|
||||||
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.LabelType));
|
const packet = await this.send(PacketGenerator.getPrinterInfo(PrinterInfoType.LabelType));
|
||||||
Validators.u8ArrayLengthEquals(packet.data, 1);
|
Validators.u8ArrayLengthEquals(packet.data, 1);
|
||||||
|
@ -27,7 +27,7 @@ export enum RequestCommandId {
|
|||||||
SetLabelType = 0x23 /* D11 - 1,5, for D110 able to set 1,2,3,5; see LabelType */,
|
SetLabelType = 0x23 /* D11 - 1,5, for D110 able to set 1,2,3,5; see LabelType */,
|
||||||
SetPageSize = 0x13, // 2, 4 or 6 bytes
|
SetPageSize = 0x13, // 2, 4 or 6 bytes
|
||||||
SoundSettings = 0x58,
|
SoundSettings = 0x58,
|
||||||
Unknown1 = 0x0b, // some info request (niimbot app), 01 long 02 short
|
AntiFake = 0x0b, // some info request (niimbot app), 01 long 02 short
|
||||||
WriteRFID = 0x70, // same as GetVolumeLevel???
|
WriteRFID = 0x70, // same as GetVolumeLevel???
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ export enum ResponseCommandId {
|
|||||||
In_PrinterInfoPrinterCode = 0x48,
|
In_PrinterInfoPrinterCode = 0x48,
|
||||||
In_PrinterInfoSerialNumber = 0x4b,
|
In_PrinterInfoSerialNumber = 0x4b,
|
||||||
In_PrinterInfoSoftWareVersion = 0x49,
|
In_PrinterInfoSoftWareVersion = 0x49,
|
||||||
In_PrinterInfoUnknown1 = 0x4f,
|
In_PrinterInfoArea = 0x4f,
|
||||||
IN_PrinterStatusData = 0xb5,
|
IN_PrinterStatusData = 0xb5,
|
||||||
In_PrintStatus = 0xb3,
|
In_PrintStatus = 0xb3,
|
||||||
In_PrintError = 0xdb, // For example, sent on SetPageSize when page print is not started
|
In_PrintError = 0xdb, // For example, sent on SetPageSize when page print is not started
|
||||||
@ -66,7 +66,7 @@ export enum ResponseCommandId {
|
|||||||
In_SetLabelType = 0x33,
|
In_SetLabelType = 0x33,
|
||||||
In_SetPageSize = 0x14,
|
In_SetPageSize = 0x14,
|
||||||
In_SoundSettings = 0x68,
|
In_SoundSettings = 0x68,
|
||||||
In_Unknown1 = 0xe4,
|
In_OageEnd = 0xe4,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum PrinterInfoType {
|
export enum PrinterInfoType {
|
||||||
@ -83,7 +83,7 @@ export enum PrinterInfoType {
|
|||||||
HardWareVersion = 12,
|
HardWareVersion = 12,
|
||||||
BluetoothAddress = 13,
|
BluetoothAddress = 13,
|
||||||
PrintMode = 14,
|
PrintMode = 14,
|
||||||
Unknown1 = 15,
|
Area = 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum SoundSettingsType {
|
export enum SoundSettingsType {
|
||||||
@ -138,67 +138,6 @@ export enum ConnectResult {
|
|||||||
FirmwareErrors = 90,
|
FirmwareErrors = 90,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Generated from android app (assets/flutter_assets/assets/config/printerList.json) */
|
|
||||||
export enum PrinterModelId {
|
|
||||||
UNKNOWN = 0,
|
|
||||||
T6 = 51715,
|
|
||||||
TP2M_H = 4609,
|
|
||||||
B31 = 5632,
|
|
||||||
B1 = 4096,
|
|
||||||
M2_H = 4608,
|
|
||||||
B21_PRO = 785,
|
|
||||||
P1 = 1024,
|
|
||||||
T2S = 53250,
|
|
||||||
B50W = 51714,
|
|
||||||
T7 = 51717,
|
|
||||||
B50 = 51713,
|
|
||||||
Z401 = 2051,
|
|
||||||
B32R = 2050,
|
|
||||||
A63 = 2054,
|
|
||||||
T8S = 2053,
|
|
||||||
B32 = 2049,
|
|
||||||
B18S = 3585,
|
|
||||||
B18 = 3584,
|
|
||||||
MP3K_W = 4867,
|
|
||||||
MP3K = 4866,
|
|
||||||
K3_W = 4865,
|
|
||||||
K3 = 4864,
|
|
||||||
B3S_P = 272,
|
|
||||||
S6 = 261,
|
|
||||||
B3S = 256,
|
|
||||||
B3S_V2 = 260,
|
|
||||||
B3S_V3 = 262,
|
|
||||||
B3 = 52993,
|
|
||||||
A203 = 2818,
|
|
||||||
A20 = 2817,
|
|
||||||
B203 = 2816,
|
|
||||||
S1 = 51458,
|
|
||||||
JC_M90 = 51461,
|
|
||||||
S3 = 51460,
|
|
||||||
B11 = 51457,
|
|
||||||
B21_H = 784,
|
|
||||||
B21S_C2B = 776,
|
|
||||||
B21S = 777,
|
|
||||||
B21_L2B = 769,
|
|
||||||
B21_C2B = 771,
|
|
||||||
B21_C2B_V2 = 775,
|
|
||||||
B21 = 768,
|
|
||||||
B16 = 1792,
|
|
||||||
BETTY = 2561,
|
|
||||||
D101 = 2560,
|
|
||||||
D110_M = 2320,
|
|
||||||
HI_D110 = 2305,
|
|
||||||
D110 = 2304,
|
|
||||||
D11_H = 528,
|
|
||||||
D11S = 514,
|
|
||||||
FUST = 513,
|
|
||||||
D11 = 512,
|
|
||||||
ET10 = 5376,
|
|
||||||
P18 = 1026,
|
|
||||||
P1S = 1025,
|
|
||||||
T8 = 51718,
|
|
||||||
}
|
|
||||||
|
|
||||||
export * from "./packet";
|
export * from "./packet";
|
||||||
export * from "./packet_generator";
|
export * from "./packet_generator";
|
||||||
export * from "./abstraction";
|
export * from "./abstraction";
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
SoundSettingsType,
|
SoundSettingsType,
|
||||||
} from ".";
|
} from ".";
|
||||||
import { EncodedImage, ImageEncoder, ImageRow as ImagePart } from "../image_encoder";
|
import { EncodedImage, ImageEncoder, ImageRow as ImagePart } from "../image_encoder";
|
||||||
|
import { ProtocolVersion } from "../printers";
|
||||||
import { Utils } from "../utils";
|
import { Utils } from "../utils";
|
||||||
|
|
||||||
export type PrintOptions = {
|
export type PrintOptions = {
|
||||||
@ -18,19 +19,6 @@ export type PrintOptions = {
|
|||||||
quantity?: number;
|
quantity?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum ProtocolVariant {
|
|
||||||
/** Used in D11 */
|
|
||||||
V1 = 1,
|
|
||||||
/** Used in B21, D110new */
|
|
||||||
V2,
|
|
||||||
/** Used in B16 */
|
|
||||||
V3,
|
|
||||||
/** Used in B1 */
|
|
||||||
V4,
|
|
||||||
/** Not used */
|
|
||||||
V5,
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PacketGenerator {
|
export class PacketGenerator {
|
||||||
public static generic(
|
public static generic(
|
||||||
requestId: RequestCommandId,
|
requestId: RequestCommandId,
|
||||||
@ -73,7 +61,7 @@ export class PacketGenerator {
|
|||||||
ResponseCommandId.In_PrinterInfoHardWareVersion,
|
ResponseCommandId.In_PrinterInfoHardWareVersion,
|
||||||
ResponseCommandId.In_PrinterInfoBluetoothAddress,
|
ResponseCommandId.In_PrinterInfoBluetoothAddress,
|
||||||
// ResponseCommandId.In_PrinterInfoPrintMode,
|
// ResponseCommandId.In_PrinterInfoPrintMode,
|
||||||
ResponseCommandId.In_PrinterInfoUnknown1,
|
ResponseCommandId.In_PrinterInfoArea,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -334,12 +322,12 @@ export class PacketGenerator {
|
|||||||
/*
|
/*
|
||||||
B1 print process example (square in square, 160x240)
|
B1 print process example (square in square, 160x240)
|
||||||
|
|
||||||
SetDensity 5555 21 0102 22aaaa
|
SetDensity 5555 21 01 02 22aaaa
|
||||||
SetLabelType 5555 23 0101 23aaaa
|
SetLabelType 5555 23 01 01 23aaaa
|
||||||
PrintStart 5555 01 0700010000000000 07aaaa
|
PrintStart 5555 01 07 00010000000000 07aaaa
|
||||||
PageStart 5555 03 0101 03aaaa
|
PageStart 5555 03 01 01 03aaaa
|
||||||
SetPageSize 5555 13 0600a000f00001 44aaaa
|
SetPageSize 5555 13 06 00a000f00001 44aaaa
|
||||||
PrintEmptyRows 5555 84 0300001d 9aaaaa
|
PrintEmptyRows 5555 84 03 00001d 9aaaaa
|
||||||
PrintBitmapRows 5555 85 24 001d 3e3000 04 000000000000003ffffffffffffffffffffffffffffffff0000000000000 86aaaa
|
PrintBitmapRows 5555 85 24 001d 3e3000 04 000000000000003ffffffffffffffffffffffffffffffff0000000000000 86aaaa
|
||||||
PrintBitmapRows 5555 85 24 0021 b83000 21 000000000000003c000000000000000000000000000000f0000000000000 e5aaaa
|
PrintBitmapRows 5555 85 24 0021 b83000 21 000000000000003c000000000000000000000000000000f0000000000000 e5aaaa
|
||||||
PrintBitmapRows 5555 85 24 0042 9e3000 04 000000000000003c000000000007fffffe000000000000f0000000000000 7caaaa
|
PrintBitmapRows 5555 85 24 0042 9e3000 04 000000000000003c000000000007fffffe000000000000f0000000000000 7caaaa
|
||||||
@ -347,10 +335,10 @@ export class PacketGenerator {
|
|||||||
PrintBitmapRows 5555 85 24 005a 9e3000 04 000000000000003c000000000007fffffe000000000000f0000000000000 64aaaa
|
PrintBitmapRows 5555 85 24 005a 9e3000 04 000000000000003c000000000007fffffe000000000000f0000000000000 64aaaa
|
||||||
PrintBitmapRows 5555 85 24 005e b83000 23 000000000000003c000000000000000000000000000000f0000000000000 98aaaa
|
PrintBitmapRows 5555 85 24 005e b83000 23 000000000000003c000000000000000000000000000000f0000000000000 98aaaa
|
||||||
PrintBitmapRows 5555 85 24 0081 3e3000 04 000000000000003ffffffffffffffffffffffffffffffff0000000000000 1aaaaa
|
PrintBitmapRows 5555 85 24 0081 3e3000 04 000000000000003ffffffffffffffffffffffffffffffff0000000000000 1aaaaa
|
||||||
PrintEmptyRows 5555 84 0300851b19aaaa
|
PrintEmptyRows 5555 84 03 00851b19aaaa
|
||||||
PageEnd 5555 e3 0101 e3aaaa
|
PageEnd 5555 e3 01 01 e3aaaa
|
||||||
PrintStatus 5555 a3 0101 a3aaaa (alot)
|
PrintStatus 5555 a3 01 01 a3aaaa (alot)
|
||||||
PrintEnd 5555 f3 0101 f3aaaa
|
PrintEnd 5555 f3 01 01 f3aaaa
|
||||||
|
|
||||||
|
|
||||||
You should send PrintEnd manually after this sequence (after print finished)
|
You should send PrintEnd manually after this sequence (after print finished)
|
||||||
@ -368,17 +356,17 @@ export class PacketGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static generatePrintSequence(
|
public static generatePrintSequence(
|
||||||
variant: ProtocolVariant,
|
protoVersion: ProtocolVersion,
|
||||||
image: EncodedImage,
|
image: EncodedImage,
|
||||||
options?: PrintOptions
|
options?: PrintOptions
|
||||||
): NiimbotPacket[] {
|
): NiimbotPacket[] {
|
||||||
switch (variant) {
|
switch (protoVersion) {
|
||||||
case ProtocolVariant.V3:
|
case ProtocolVersion.V3:
|
||||||
return PacketGenerator.generatePrintSequenceV3(image, options);
|
return PacketGenerator.generatePrintSequenceV3(image, options);
|
||||||
case ProtocolVariant.V4:
|
case ProtocolVersion.V4:
|
||||||
return PacketGenerator.generatePrintSequenceV4(image, options);
|
return PacketGenerator.generatePrintSequenceV4(image, options);
|
||||||
default:
|
default:
|
||||||
throw new Error("Not implemented");
|
throw new Error(`PrintTaskVersion ${protoVersion} Not implemented`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
184
niimbluelib/src/printers.ts
Normal file
184
niimbluelib/src/printers.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
export enum PrinterModel {
|
||||||
|
UNKNOWN = 0,
|
||||||
|
A20 = 2817,
|
||||||
|
A203 = 2818,
|
||||||
|
A63 = 2054,
|
||||||
|
A8 = 1280,
|
||||||
|
B11 = 51457,
|
||||||
|
B16 = 1792,
|
||||||
|
B18 = 3584,
|
||||||
|
B18S = 3585,
|
||||||
|
B20 = 4608,
|
||||||
|
B201__B1 = 4096,
|
||||||
|
B203 = 2816,
|
||||||
|
B21__B21_OLD = 768,
|
||||||
|
B21_C2B = 771,
|
||||||
|
B21_C2B_ZX__B21_C2B_V2 = 775,
|
||||||
|
B21_C2W = 772,
|
||||||
|
B21_C3W = 774,
|
||||||
|
B21_H = 784,
|
||||||
|
B21_L2B = 769,
|
||||||
|
B21_L2W = 770,
|
||||||
|
B21_PRO = 785,
|
||||||
|
B21S = 777,
|
||||||
|
B21S_C2B = 776,
|
||||||
|
B3 = 52993,
|
||||||
|
B31 = 5632,
|
||||||
|
B32 = 2049,
|
||||||
|
B32_R = 2050,
|
||||||
|
B3S = 256,
|
||||||
|
B3S_GD__B3S_V3 = 262,
|
||||||
|
B3S_P = 272,
|
||||||
|
B3S_ZX__B3S_V2 = 260,
|
||||||
|
B50 = 51713,
|
||||||
|
B50W = 51714,
|
||||||
|
BETTY = 2561,
|
||||||
|
C1 = 5120,
|
||||||
|
D101 = 2560,
|
||||||
|
D11 = 512,
|
||||||
|
D11_H = 528,
|
||||||
|
D110 = 2304,
|
||||||
|
D110_M = 2320,
|
||||||
|
D11S = 514,
|
||||||
|
D61 = 1536,
|
||||||
|
ET10 = 5376,
|
||||||
|
FUST = 513,
|
||||||
|
H1 = 4352,
|
||||||
|
H10 = 3840,
|
||||||
|
HI_D110 = 2305,
|
||||||
|
JC_M90 = 51461,
|
||||||
|
K1__K3 = 4864,
|
||||||
|
K1S__K3_W = 4865,
|
||||||
|
MP3K = 4866,
|
||||||
|
MP3K_W = 4867,
|
||||||
|
P1 = 1024,
|
||||||
|
P18 = 1026,
|
||||||
|
P1S = 1025,
|
||||||
|
S1 = 51458,
|
||||||
|
S3 = 51460,
|
||||||
|
S6 = 257,
|
||||||
|
S6_1 = 258,
|
||||||
|
S6_2 = 261,
|
||||||
|
T2S = 53250,
|
||||||
|
T6 = 51715,
|
||||||
|
T7 = 51717,
|
||||||
|
T8 = 51718,
|
||||||
|
T8S = 2053,
|
||||||
|
TP2M_H = 4609,
|
||||||
|
TSC = 255,
|
||||||
|
Z401 = 2051,
|
||||||
|
Z401_R = 2052,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ProtocolVersion {
|
||||||
|
UNKNOWN = 0,
|
||||||
|
/** Used in D11 */
|
||||||
|
V1,
|
||||||
|
/** Used in B21, D110new */
|
||||||
|
V2,
|
||||||
|
/** Used in B16 */
|
||||||
|
V3,
|
||||||
|
/** Used in B1 */
|
||||||
|
V4,
|
||||||
|
/** Not used */
|
||||||
|
V5,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PrinterCapabilities {
|
||||||
|
printTaskVersion: ProtocolVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
import M = PrinterModel;
|
||||||
|
export const getPrinterCapabilities = (id: PrinterModel): PrinterCapabilities => {
|
||||||
|
let printTaskVersion = ProtocolVersion.UNKNOWN;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case M.D11:
|
||||||
|
case M.D11_H:
|
||||||
|
case M.D11S:
|
||||||
|
printTaskVersion = ProtocolVersion.V1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M.D110:
|
||||||
|
case M.D110_M:
|
||||||
|
printTaskVersion = ProtocolVersion.V3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case M.B201__B1:
|
||||||
|
printTaskVersion = ProtocolVersion.V4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// todo: find other models info
|
||||||
|
case M.UNKNOWN:
|
||||||
|
case M.A20:
|
||||||
|
case M.A203:
|
||||||
|
case M.A63:
|
||||||
|
case M.A8:
|
||||||
|
case M.B11:
|
||||||
|
case M.B16:
|
||||||
|
case M.B18:
|
||||||
|
case M.B18S:
|
||||||
|
case M.B20:
|
||||||
|
case M.B203:
|
||||||
|
case M.B21__B21_OLD:
|
||||||
|
case M.B21_C2B:
|
||||||
|
case M.B21_C2B_ZX__B21_C2B_V2:
|
||||||
|
case M.B21_C2W:
|
||||||
|
case M.B21_C3W:
|
||||||
|
case M.B21_H:
|
||||||
|
case M.B21_L2B:
|
||||||
|
case M.B21_L2W:
|
||||||
|
case M.B21_PRO:
|
||||||
|
case M.B21S:
|
||||||
|
case M.B21S_C2B:
|
||||||
|
case M.B3:
|
||||||
|
case M.B31:
|
||||||
|
case M.B32:
|
||||||
|
case M.B32_R:
|
||||||
|
case M.B3S:
|
||||||
|
case M.B3S_GD__B3S_V3:
|
||||||
|
case M.B3S_P:
|
||||||
|
case M.B3S_ZX__B3S_V2:
|
||||||
|
case M.B50:
|
||||||
|
case M.B50W:
|
||||||
|
case M.BETTY:
|
||||||
|
case M.C1:
|
||||||
|
case M.D101:
|
||||||
|
case M.D61:
|
||||||
|
case M.ET10:
|
||||||
|
case M.FUST:
|
||||||
|
case M.H1:
|
||||||
|
case M.H10:
|
||||||
|
case M.HI_D110:
|
||||||
|
case M.JC_M90:
|
||||||
|
case M.K1__K3:
|
||||||
|
case M.K1S__K3_W:
|
||||||
|
case M.MP3K:
|
||||||
|
case M.MP3K_W:
|
||||||
|
case M.P1:
|
||||||
|
case M.P18:
|
||||||
|
case M.P1S:
|
||||||
|
case M.S1:
|
||||||
|
case M.S3:
|
||||||
|
case M.S6:
|
||||||
|
case M.S6_1:
|
||||||
|
case M.S6_2:
|
||||||
|
case M.T2S:
|
||||||
|
case M.T6:
|
||||||
|
case M.T7:
|
||||||
|
case M.T8:
|
||||||
|
case M.T8S:
|
||||||
|
case M.TP2M_H:
|
||||||
|
case M.TSC:
|
||||||
|
case M.Z401:
|
||||||
|
case M.Z401_R:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
((_id: never) => {
|
||||||
|
throw new Error(`Printer model ${_id} was unhandled!`);
|
||||||
|
})(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { printTaskVersion };
|
||||||
|
};
|
Reference in New Issue
Block a user