1
0
Fork 0
mirror of https://github.com/silenty4ng/k5web synced 2025-04-07 17:14:52 +00:00
k5web/src/views/list/image/index.vue
2025-01-25 22:28:54 +08:00

297 lines
8.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="container">
<Breadcrumb :items="[$t('menu.list'), $t('menu.image')]" />
<a-row :gutter="20" align="stretch">
<a-col :span="24">
<a-spin :loading="state.loading" tip="写入中..." style="width: 100%;">
<a-card class="general-card" :title="$t('menu.image') + $t('global.onStart')">
<div id="canvasDiv" style="zoom: 250%; display: none"></div>
<div>
<table style="padding: 0; margin: 0; border-spacing: 0">
<tr v-for="col, y in state.matrix">
<td @mousedown="state.mousedown = true; changePixel(x, y)" @mouseup="state.mousedown = false;" @mouseover="changePixel(x, y)" v-for="row, x in col" :style="'background-color: ' + row + '; height: 5px; width: 3.5px;'"></td>
</tr>
</table>
</div>
<br>
色彩阈值<t-slider v-model="state.threshold" :max="256" style="width: 200px;" @change-end="changeThreshold" />
<br>
<a-space>
<a-button @click="selectFile">{{ $t('tool.selectImage') }}</a-button>
<a-button :disabled="state.matrix.length < 64" @click="negativeIt">{{ $t('image.negative') }}</a-button>
<a-button :disabled="state.matrix.length < 64" @click="saveIt">{{ $t('cps.save') }}</a-button>
<a-button type="primary" :disabled="state.matrix.length < 64" @click="flashIt">{{ $t('tool.write') }}</a-button>
</a-space>
</a-card>
</a-spin>
</a-col>
</a-row>
</div>
</template>
<script lang="ts" setup>
import { reactive, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { useAppStore } from '@/store';
import { eeprom_write, eeprom_reboot, eeprom_init } from '@/utils/serial.js';
const appStore = useAppStore();
const state : {
binaryFile: any,
loading: boolean,
matrix: any,
mousedown: boolean,
threshold: number,
cache: any
} = reactive({
binaryFile: undefined,
loading: false,
matrix: [],
mousedown: false,
threshold: 128,
cache: undefined
})
const route = useRoute();
onMounted(async ()=>{
if(route.query.url){
const img = await fetch(route.query.url, {
responseType: 'blob'
});
useImg(window.URL.createObjectURL(await img.blob()))
}
})
const negativeIt = () => {
const matrix = state.matrix
matrix.map((y: any, yi: any)=>{
y.map((x: any, xi: any)=>{
matrix[yi][xi] = x == '#fff' ? '#000' : '#fff'
})
})
state.matrix = matrix
}
const changePixel = (x: int, y: int) => {
if(state.mousedown){
const matrix = state.matrix
matrix[y][x] = state.matrix[y][x] == '#fff' ? '#000' : '#fff'
state.matrix = matrix
}
}
const useImg = (url: string) => {
const canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 64;
const canvas2 = canvas.cloneNode();
const canvasDiv = document.getElementById('canvasDiv');
canvasDiv.innerHTML = "";
canvasDiv?.append(canvas, canvas2);
const img = new Image()
img.src = url;
img.onload = () => {
const ctx = canvas.getContext('2d');
ctx?.drawImage(img, 0, 0, 128, 64);
const imageData = ctx?.getImageData(0, 0, canvas.width, canvas.height).data;
state.cache = imageData;
function getPixel(x: any, y: any) {
const index = y * 128 + x;
const i = index * 4;
return imageData[i] + imageData[i + 1] + imageData[i + 2] > state.threshold * 3 ? 0 : 1;
}
const matrix = [];
for (let y = 0; y < 64; y++) {
matrix.push([])
matrix[y] = []
for (let x = 0; x < 128; x++) {
const pixel = !getPixel(x, y);
matrix[y][x] = pixel ? '#fff' : '#000';
}
}
state.matrix = matrix
}
}
const selectFile = () => {
const input = document.createElement('input');
input.type = 'file';
input.onchange = async () => {
const blob = new Blob([input.files[0]], { type: 'application/octet-stream' });
const file = URL.createObjectURL(blob);
const canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 64;
const img = new Image()
img.src = file;
img.onload = () => {
const ctx = canvas.getContext('2d');
ctx?.drawImage(img, 0, 0, 128, 64);
const imageData = ctx?.getImageData(0, 0, canvas.width, canvas.height).data;
state.cache = imageData;
function getPixel(x: any, y: any) {
const index = y * 128 + x;
const i = index * 4;
return imageData[i] + imageData[i + 1] + imageData[i + 2] > state.threshold * 3 ? 0 : 1;
}
const matrix = [];
for (let y = 0; y < 64; y++) {
matrix.push([])
matrix[y] = []
for (let x = 0; x < 128; x++) {
const pixel = !getPixel(x, y);
matrix[y][x] = pixel ? '#fff' : '#000';
}
}
state.matrix = matrix
}
};
input.click();
}
const saveIt = async () => {
const matrix = state.matrix
const canvas = document.createElement("canvas");
canvas.width = 128;
canvas.height = 64;
const ctx = canvas.getContext('2d');
if(ctx){
ctx.fillStyle = "#fff";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#000";
}
for (let y = 0; y < 64; y++) {
for (let x = 0; x < 128; x++) {
if(matrix[y][x] == '#000'){
ctx?.beginPath();
ctx?.rect(x, y, 1, 1);
ctx?.fill();
}
}
}
const el = document.createElement('a');
el.href = canvas.toDataURL("image/jpeg", 1.0);
el.download = 'image.jpg';
el.click()
}
const flashIt = async () => {
const outputArray = new Uint8Array(1024);
// getPixel(i) outputs the pixel value for any x y coordinate. 0 = black, 1 = white.
// the outputArray is 1024 bytes, where each byte is 8 pixels IN VERTICAL ORDER.
let i = 0;
for (let y = 0; y < 64; y += 8) {
for (let x = 0; x < 128; x++) {
let byte = 0;
for (let i = 0; i < 8; i++) {
byte |= (state.matrix[y + i][x] == '#000' ? 1 : 0 ) << i;
}
outputArray[i++] = byte;
}
}
state.binaryFile = outputArray;
if(appStore.connectState != true){alert(sessionStorage.getItem('noticeConnectK5')); return;};
if(appStore.configuration?.uart == "official"){
alert(sessionStorage.getItem('noticeVersionNoSupport'));
return;
}
if(appStore.configuration?.charset != "losehu" && appStore.configuration?.charset != "gb2312"){
alert(sessionStorage.getItem('noticeVersionNoSupport'));
return;
}
state.loading = true
let position = 0x1E350;
if(appStore.configuration?.charset == "gb2312")position = 0x2080;
await eeprom_init(appStore.connectPort);
const rawEEPROM = state.binaryFile;
for (let i = position; i < rawEEPROM.length + position; i += 0x80) {
await eeprom_write(appStore.connectPort, i, rawEEPROM.slice(i - position, i - position + 0x80), rawEEPROM.slice(i - position, i - position + 0x80).length, appStore.configuration?.uart);
}
await eeprom_reboot(appStore.connectPort);
state.loading = false
}
const changeThreshold = () => {
const imageData = state.cache;
function getPixel(x: any, y: any) {
const index = y * 128 + x;
const i = index * 4;
return imageData[i] + imageData[i + 1] + imageData[i + 2] > state.threshold * 3 ? 0 : 1;
}
const matrix = [];
for (let y = 0; y < 64; y++) {
matrix.push([])
matrix[y] = []
for (let x = 0; x < 128; x++) {
const pixel = !getPixel(x, y);
matrix[y][x] = pixel ? '#fff' : '#000';
}
}
state.matrix = matrix
}
</script>
<script lang="ts">
export default {
name: 'Image',
};
</script>
<style scoped lang="less">
.container {
padding: 0 20px 20px 20px;
:deep(.arco-list-content) {
overflow-x: hidden;
}
:deep(.arco-card-meta-title) {
font-size: 14px;
}
}
:deep(.arco-list-col) {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
}
:deep(.arco-list-item) {
width: 33%;
}
:deep(.block-title) {
margin: 0 0 12px 0;
font-size: 14px;
}
:deep(.list-wrap) {
// min-height: 140px;
.list-row {
align-items: stretch;
.list-col {
margin-bottom: 16px;
}
}
:deep(.arco-space) {
width: 100%;
.arco-space-item {
&:last-child {
flex: 1;
}
}
}
}
</style>