Working tree changes 2024-07-31 01:00
All checks were successful
Test project build / Build (push) Successful in 1m17s

This commit is contained in:
Bot 2024-07-31 01:00:02 +03:00 committed by multimote
parent 319a33084e
commit 2e7cfe46b0
6 changed files with 103 additions and 47 deletions

View File

@ -54,6 +54,22 @@ export class ImageEditorUtils {
}
}
static addImageWithFilePicker(fabricCanvas: fabric.Canvas) {
const input: HTMLInputElement = document.createElement("input");
input.type = "file";
input.onchange = (e: Event) => {
let target = e.target as HTMLInputElement;
if (target.files !== null) {
let file: File = target.files[0];
this.addImageFile(fabricCanvas, file);
}
};
input.click();
}
public static addText(canvas: fabric.Canvas, text?: string): void {
const obj = new fabric.IText(text ?? "Text", {
...this.OBJECT_DEFAULTS,

View File

@ -51,23 +51,24 @@
const onUpdateLabelProps = () => {
labelProps = labelProps; // trigger update
fabricCanvas.setDimensions(labelProps.size);
localStorage.setItem("last_label_props", JSON.stringify(labelProps));
};
const onSaveClicked = () => {
const data = fabricCanvas.toJSON();
localStorage.setItem("canvas_data", JSON.stringify(data));
localStorage.setItem("canvas_props", JSON.stringify(labelProps));
localStorage.setItem("saved_canvas_data", JSON.stringify(data));
localStorage.setItem("saved_canvas_props", JSON.stringify(labelProps));
};
const onLoadClicked = () => {
const props = localStorage.getItem("canvas_props");
const props = localStorage.getItem("saved_canvas_props");
if (props) {
const parsedProps = JSON.parse(props);
labelProps = parsedProps;
onUpdateLabelProps();
}
const data = localStorage.getItem("canvas_data");
const data = localStorage.getItem("saved_canvas_data");
fabricCanvas.loadFromJSON(
data,
() => {
@ -89,6 +90,8 @@
ImageEditorUtils.addCircle(fabricCanvas);
} else if (name === "rectangle") {
ImageEditorUtils.addRect(fabricCanvas);
} else if (name === "image") {
ImageEditorUtils.addImageWithFilePicker(fabricCanvas);
}
};
@ -116,6 +119,19 @@
};
onMount(() => {
const savedLabelPropsStr: string | null = localStorage.getItem("last_label_props");
if (savedLabelPropsStr != null) {
try {
const obj = JSON.parse(savedLabelPropsStr);
if ("size" in obj && "width" in obj.size && "height" in obj.size && ["top", "left"].includes(obj.startPos)) {
labelProps = obj as LabelProps;
}
} catch (e) {
console.error(e);
}
}
fabricCanvas = new fabric.Canvas(htmlCanvas, {
width: labelProps.size.width,
height: labelProps.size.height,
@ -124,7 +140,6 @@
ImageEditorUtils.addText(fabricCanvas);
fabricCanvas.on("object:moving", (e: fabric.IEvent<MouseEvent>) => {
const grid = 5;
if (e.target && e.target.left !== undefined && e.target.top !== undefined) {
@ -198,7 +213,7 @@
<div class="col d-flex justify-content-center">
<div class="toolbar d-flex flex-wrap gap-1 justify-content-center align-items-center">
{#if selectedCount > 0}
<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 selectedObject && selectedCount === 1}

View File

@ -26,6 +26,10 @@
<button class="btn me-1" on:click={() => onSubmit("circle")}>
<FaIcon icon="circle-dot" /> Circle
</button>
<button class="btn me-1" on:click={() => onSubmit("image")}>
<FaIcon icon="image" /> Image
</button>
</div>
</div>
</div>

View File

@ -4,12 +4,7 @@
import Modal from "bootstrap/js/dist/modal";
import { connectionState, printerClient } from "../stores";
import { copyImageData, threshold, atkinson } from "../post_process";
import {
type EncodedImage,
ImageEncoder,
PacketGenerator,
ProtocolVersion,
} from "@mmote/niimbluelib";
import { type EncodedImage, ImageEncoder, PacketGenerator, ProtocolVersion } from "@mmote/niimbluelib";
import type { LabelProps } from "../types";
import FaIcon from "./FaIcon.svelte";
@ -19,59 +14,64 @@
let modalElement: HTMLElement;
let previewCanvas: HTMLCanvasElement;
let printState: "idle" | "sending" | "printing" = "idle";
let modal: Modal;
let sendProgress: number = 0;
let printProgress: number = 0; // todo: more progress data
let density: number = 3;
let quantity: number = 1;
let printed: boolean = false;
let postProcessType: "threshold" | "dither";
let thresholdValue: number = 140;
let imgData: ImageData;
let imgContext: CanvasRenderingContext2D;
let printTaskVersion: ProtocolVersion = ProtocolVersion.V3;
let statusTimer: NodeJS.Timeout | undefined = undefined;
let printError: boolean = false;
let error: string = "";
const disconnected = derived(connectionState, ($connectionState) => $connectionState !== "connected");
const cancelPrint = async () => {
const endPrint = async () => {
clearInterval(statusTimer);
if (!$disconnected && printed) {
await $printerClient.sendPacket(PacketGenerator.printEnd());
if (!$disconnected && printState !== "idle") {
await $printerClient.abstraction.printEnd();
}
printed = false;
printState = "idle";
printProgress = 0;
};
const onPrint = async () => {
printError = false;
const encoded: EncodedImage = ImageEncoder.encodeCanvas(previewCanvas, labelProps.startPos);
const packets = PacketGenerator.generatePrintSequence(printTaskVersion, encoded, { quantity, density });
for (let i = 0; i < packets.length; i++) {
sendProgress = Math.round(((i + 1) / packets.length) * 100);
await $printerClient.sendPacketWaitResponse(packets[i], 10_000);
printState = "sending";
error = "";
try {
await $printerClient.abstraction.print(printTaskVersion, encoded, { quantity, density });
} catch (e) {
error = `${e}`;
console.error(e);
return;
}
printState = "printing";
statusTimer = setInterval(async () => {
try {
const status = await $printerClient.abstraction.getPrintStatus();
printProgress = status.pagePrintProgress;
if (status.page === quantity && status.pagePrintProgress === 100 && status.pageFeedProgress === 100) {
await cancelPrint();
await endPrint();
}
} catch (e) {
error = `${e}`;
console.error(e);
await cancelPrint();
printError = true;
await endPrint();
}
}, 100);
printed = true;
printState = "idle";
};
const updatePreview = () => {
@ -102,13 +102,13 @@
modal = new Modal(modalElement);
modal.show();
modalElement.addEventListener("hidden.bs.modal", async () => {
cancelPrint();
endPrint();
onClosed();
});
const taskVer = $printerClient?.getCapabilities().printTaskVersion;
if (taskVer !== undefined && taskVer !== ProtocolVersion.UNKNOWN) {
console.log(`Detected print task version: ${ProtocolVersion[taskVer]}`)
console.log(`Detected print task version: ${ProtocolVersion[taskVer]}`);
printTaskVersion = taskVer;
}
});
@ -139,13 +139,8 @@
<div class="modal-body text-center">
<canvas class="print-start-{labelProps.startPos}" bind:this={previewCanvas}></canvas>
{#if sendProgress != 0 && sendProgress != 100}
<div>
Sending...
<div class="progress" role="progressbar">
<div class="progress-bar" style="width: {sendProgress}%">{sendProgress}%</div>
</div>
</div>
{#if printState === "sending"}
<div>Sending...</div>
{/if}
{#if printProgress != 0 && printProgress != 100}
<div>
@ -157,8 +152,8 @@
{/if}
</div>
{#if printError}
<div class="alert alert-danger" role="alert">Print error</div>
{#if error}
<div class="alert alert-danger" role="alert">{error}</div>
{/if}
<div class="modal-footer">
@ -204,13 +199,13 @@
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
{#if printed}
<button type="button" class="btn btn-primary" disabled={$disconnected} on:click={cancelPrint}>
{#if printState !== "idle"}
<button type="button" class="btn btn-primary" disabled={$disconnected} on:click={endPrint}>
Cancel print
</button>
{/if}
<button type="button" class="btn btn-primary" disabled={$disconnected || printed} on:click={onPrint}>
<button type="button" class="btn btn-primary" disabled={$disconnected || printState !== "idle"} on:click={onPrint}>
{#if $disconnected}
Printer is not connected
{:else}

View File

@ -15,4 +15,4 @@ export type LabelPreset = {
startPosition: HeadPosition;
};
export type OjectType = "text" | "rectangle" | "line" | "circle"
export type OjectType = "text" | "rectangle" | "line" | "circle" | "image"

View File

@ -7,12 +7,17 @@ import {
NiimbotPacket,
PacketGenerator,
PrinterInfoType,
PrintOptions,
ResponseCommandId,
SoundSettingsItemType,
SoundSettingsType,
} from ".";
import { NiimbotAbstractClient, Utils, Validators } from "..";
import { PrinterModel } from "../printers";
EncodedImage,
NiimbotAbstractClient,
Utils,
Validators,
PrinterModel,
ProtocolVersion,
} from "..";
import { SequentialDataReader } from "./data_reader";
export class PrintError extends Error {
@ -64,8 +69,9 @@ export interface PrinterStatusData {
/** Not sure for name. */
export class Abstraction {
private readonly DEFAULT_TIMEOUT: number = 1_000;
private client: NiimbotAbstractClient;
private timeout: number = 1000;
private timeout: number = this.DEFAULT_TIMEOUT;
constructor(client: NiimbotAbstractClient) {
this.client = client;
@ -79,6 +85,10 @@ export class Abstraction {
this.timeout = value;
}
public setDefaultTimeout() {
this.timeout = this.DEFAULT_TIMEOUT;
}
/** Send packet and wait for response */
private async send(packet: NiimbotPacket): Promise<NiimbotPacket> {
return this.client.sendPacketWaitResponse(packet, this.timeout);
@ -277,4 +287,20 @@ export class Abstraction {
public async setSoundEnabled(soundType: SoundSettingsItemType, value: boolean): Promise<void> {
await this.send(PacketGenerator.setSoundSettings(soundType, value));
}
public async print(protoVersion: ProtocolVersion, image: EncodedImage, options?: PrintOptions, timeout?:number): Promise<void> {
this.setTimeout(timeout ?? 10_000);
const packets: NiimbotPacket[] = PacketGenerator.generatePrintSequence(protoVersion, image, options);
try {
for (const element of packets) {
await this.send(element);
}
} finally {
this.setDefaultTimeout();
}
}
public async printEnd(): Promise<void> {
await this.send(PacketGenerator.printEnd());
}
}