msclient/src/lib/ImageShow.svelte

308 lines
7.1 KiB
Svelte

<script>
import { onMount, onDestroy } from "svelte";
import Navbar from "./Navbar.svelte";
import Mask from "./Mask.svelte";
import { ImageProcess } from "./utils";
const cv = window.cv;
let image_process = new ImageProcess();
export let url = "test.jpg";
let canvas_dom;
let resize_tag;
let image;
let image_for_show;
let window_width;
let window_height;
let canvas_width = 0;
let canvas_height = 0;
let mask_tag = false;
let crop_rect = {};
function LabelItem(label, items) {
this.label = label;
this.items = items.map((e) => {
return new OperationItem(e[0], e[1], e[2]);
});
}
function OperationItem(name, icon, handler = null) {
this.name = name;
this.icon = icon;
this.handler = handler;
}
const Menu = [
new LabelItem("采集操作", [
["确认并返回", "mdi mdi-checkbox-marked-circle-outline"],
["重新采集", "mdi mdi-reply-outline"],
]),
new LabelItem("图像操作", [
[
"向左旋转",
"mdi mdi-file-rotate-left-outline",
() => {
image_process.turn_left();
cv.rotate(image_for_show, image_for_show, 0);
show_image();
},
],
[
"向右旋转",
"mdi mdi-file-rotate-right-outline",
() => {
image_process.turn_right();
cv.rotate(image_for_show, image_for_show, 2);
show_image();
},
],
["文本加强", "mdi mdi-image-filter-center-focus-strong"],
[
"裁剪",
"mdi mdi-crop",
() => {
image_process.roi_init();
show_image();
mask_tag = mask_tag ? false : true;
},
],
[
"还原",
"mdi mdi-alpha-x-circle-outline",
() => {
image_process.recover();
init_canvas();
},
],
]),
new LabelItem("文件操作", [
["保存到本地", "mdi mdi-content-save-outline"],
["打印图片", "mdi mdi-printer-outline"],
]),
];
$: {
canvas_height = window_height - 64;
canvas_width = window_width * 0.8125;
}
function on_window_resize() {
if (resize_tag) {
clearTimeout(resize_tag);
}
resize_tag = setTimeout(function () {
image_process.roi_init();
if (image) {
let pre_scale = Math.min(
canvas_height / image.rows,
canvas_width / image.cols
);
let pre_dsize = new cv.Size(
pre_scale * image.cols,
pre_scale * image.rows
);
cv.resize(
image_for_show,
image_for_show,
pre_dsize,
0,
0,
cv.INTER_AREA
);
show_image();
}
}, 40);
}
function show_image() {
mask_tag = false;
let dst = new cv.Mat();
console.time("image show");
if (image_process.roi_tag) {
dst = image_for_show.roi(image_process.ROI_rect);
} else {
dst = image_for_show.clone();
}
let scale = Math.min(canvas_height / dst.rows, canvas_width / dst.cols);
let dsize = new cv.Size(scale * dst.cols, scale * dst.rows);
cv.resize(dst, dst, dsize, 0, 0, cv.INTER_AREA);
cv.imshow("canvas", dst);
console.timeEnd("image show");
dst.delete();
}
async function init_canvas() {
let img = new Image();
image_for_show = new cv.Mat();
img.src = url;
img.onload = function () {
setTimeout(() => {
image = cv.imread(img);
let pre_scale = Math.min(
canvas_height / image.rows,
canvas_width / image.cols
);
let pre_dsize = new cv.Size(
pre_scale * image.cols,
pre_scale * image.rows
);
cv.resize(image, image_for_show, pre_dsize, 0, 0, cv.INTER_AREA);
show_image();
}, 50);
};
}
function wheel_event_handler(e) {
e.preventDefault();
let mouse_point = new cv.Point(
e.clientX - canvas_dom.offsetLeft,
e.clientY - canvas_dom.offsetTop
);
image_process.roi(
image_for_show.rows,
image_for_show.cols,
mouse_point,
e.deltaY
);
show_image();
}
function keyboard_move_roi(event) {
if (event.shiftKey && event.altKey && event.ctrlKey) {
return;
}
if (event.keyCode > 40 || event.keyCode < 37) {
return;
}
event.preventDefault();
switch (event.key) {
case "ArrowUp":
image_process.roi_up();
break;
case "ArrowDown":
image_process.roi_down(image_for_show.rows);
break;
case "ArrowLeft":
image_process.roi_left();
break;
case "ArrowRight":
image_process.roi_right(image_for_show.cols);
break;
}
show_image();
}
/*function mouse_move_roi(event) {
if (event.type == "mousedown") {
roi_move_tag = true;
} else if (event.type == "mouseup") {
roi_move_tag = false;
}
}
function drag_roi(event) {
if (roi_move_tag) {
console.log(event);
let delta = {
x: event.clientX - mouse_move.x,
y: event.clientY - mouse_move.y,
};
image_process.roi_move(delta);
mouse_move = {
x: event.clientX,
y: event.clientY,
};
show_image();
}
}*/
onMount(async () => {
canvas_height = window_height - 64;
canvas_width = (window_width * 13) / 16;
init_canvas();
});
onDestroy(async () => {
if (image.delete) {
image.delete();
}
if (image_for_show.delete) {
image_for_show.delete();
}
});
</script>
<svelte:window
bind:innerHeight={window_height}
bind:innerWidth={window_width}
on:resize={on_window_resize}
on:keydown={keyboard_move_roi}
/>
<div class="disable-selection">
<Navbar />
<div class="columns is-gapless">
<div class="column is-2" style="margin: 10px">
<aside class="menu">
{#each Menu as m}
<p class="menu-label" style="font-size: 0.9em">{m.label}</p>
<ul class="menu-list">
{#each m.items as item}
<!-- svelte-ignore a11y-missing-attribute -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<li>
<a
on:click={() => {
if (item.handler) {
item.handler();
}
}}
><span class="icon-text">
<span class="icon">
<i class={item.icon} />
</span><span> {item.name}</span></span
>
</a>
</li>
{/each}
</ul>
{/each}
</aside>
</div>
<div class="column" style="text-align:center">
<div>
{#if mask_tag}
<Mask
{canvas_dom}
on:maskclose={(e) => {
mask_tag = false;
console.log(e);
}}
/>
{/if}
<canvas
bind:this={canvas_dom}
id="canvas"
on:wheel={wheel_event_handler}
/>
</div>
</div>
</div>
</div>
<style>
canvas {
border: 1px solid black;
}
</style>