diff --git a/src/components/FontCreator/useFontCreator.js b/src/components/FontCreator/useFontCreator.js index 98a712f..588d565 100644 --- a/src/components/FontCreator/useFontCreator.js +++ b/src/components/FontCreator/useFontCreator.js @@ -1,11 +1,12 @@ import { ref } from "vue"; import { createGlobalState } from "@vueuse/core"; import useSettingStore from "@/stores/useSettingStore"; +import { flipGlyphData } from "../../utils/flip"; import { getFontGlyph } from "../../apis/font"; import { watchDebounced } from "@vueuse/core"; export default createGlobalState(() => { const needText = ref("波特律动"); - const { mode, color, fontSize } = useSettingStore(); + const { mode, hFlip, vFlip, color, fontSize } = useSettingStore(); const fontTemplates = ref([ { name: "波特律动OLED驱动", @@ -33,7 +34,7 @@ export default createGlobalState(() => { const fontFace = ref(fontFaces.value[0]); watchDebounced( - [needText, fontSize, mode, color, fontFace], + [needText, fontSize, mode, hFlip, vFlip, color, fontFace], async () => { const needList = [...new Set(needText.value.split(""))]; const res = await getFontGlyph( @@ -45,6 +46,10 @@ export default createGlobalState(() => { color.value ); console.log(res.data); + if (!res.data || !res.data.data) { + console.error('API返回数据异常', res) + return + } const a = {}; needList.forEach((item) => { a[item] = { @@ -53,6 +58,19 @@ export default createGlobalState(() => { data: res.data.data[item], }; }); + // 应用水平/垂直翻转 + if (hFlip.value || vFlip.value) { + Object.keys(a).forEach((key) => { + a[key].data = flipGlyphData( + a[key].data, + a[key].width, + a[key].height, + mode.value, + hFlip.value, + vFlip.value + ) + }) + } fonts.value = a; }, { immediate: true, deep: true, debounce: 100, maxWait: 300 } diff --git a/src/components/ImageCreator/ImageCreator.vue b/src/components/ImageCreator/ImageCreator.vue index c9d0a21..730eea7 100644 --- a/src/components/ImageCreator/ImageCreator.vue +++ b/src/components/ImageCreator/ImageCreator.vue @@ -5,7 +5,7 @@ import useImageCreator from "./useImageCreator"; import { watchDebounced } from "@vueuse/core"; const canvasRef = ref(null); const imgRef = ref(null); -const { mode, color, imageSize } = useSettingStore(); +const { mode, hFlip, vFlip, color, imageSize } = useSettingStore(); const { sourceImg, imgGlyph, imgThreshold, mask } = useImageCreator(); @@ -50,6 +50,26 @@ async function getGlyph() { const res = []; + // 像素级翻转(在取模转换之前) + if (hFlip.value) { + for (let y = 0; y < height; y++) { + for (let x = 0; x < width / 2; x++) { + const a = (y * width + x) * 4 + const b = (y * width + (width - 1 - x)) * 4 + ;[canvasImg.data[a], canvasImg.data[b]] = [canvasImg.data[b], canvasImg.data[a]] + } + } + } + if (vFlip.value) { + for (let y = 0; y < height / 2; y++) { + for (let x = 0; x < width; x++) { + const a = (y * width + x) * 4 + const b = ((height - 1 - y) * width + x) * 4 + ;[canvasImg.data[a], canvasImg.data[b]] = [canvasImg.data[b], canvasImg.data[a]] + } + } + } + if (mode.value == '列行式') { const page = ~~((imageSize.value.height + 7) / 8); for (let i = 0; i < page; i++) { @@ -134,7 +154,7 @@ onMounted(async () => { getGlyph() mask.value = {} }, { immediate: true, deep: true, debounce: 100, maxWait: 300 }); - watchDebounced([mode, color, mask], async () => { + watchDebounced([mode, hFlip, vFlip, color, mask], async () => { getGlyph() }, { immediate: true, deep: true, debounce: 100, maxWait: 300 }); }); diff --git a/src/components/SettingPanel/panels/FontSettingPanel.vue b/src/components/SettingPanel/panels/FontSettingPanel.vue index 7b38a33..d8953c1 100644 --- a/src/components/SettingPanel/panels/FontSettingPanel.vue +++ b/src/components/SettingPanel/panels/FontSettingPanel.vue @@ -6,7 +6,7 @@ import { Codemirror } from 'vue-codemirror' import { oneDark } from '@codemirror/theme-one-dark' import { cpp } from '@codemirror/lang-cpp' import { computed } from 'vue'; -const { fontSize, modeList, mode, color, } = useSettingStore(); +const { fontSize, modeList, mode, hFlip, vFlip, color } = useSettingStore(); const { needText, fontTemplates, fontTemplate, fontFaces, fontFace } = useFontCreator(); const currentFontface = computed({ @@ -61,6 +61,19 @@ const currentFontface = computed({
+
反转方式:
+
+
+ + +
+
阴阳码:
diff --git a/src/components/SettingPanel/panels/ImageSettingPanel.vue b/src/components/SettingPanel/panels/ImageSettingPanel.vue index d7ec390..45ae238 100644 --- a/src/components/SettingPanel/panels/ImageSettingPanel.vue +++ b/src/components/SettingPanel/panels/ImageSettingPanel.vue @@ -8,7 +8,7 @@ import { oneDark } from '@codemirror/theme-one-dark' import { cpp } from '@codemirror/lang-cpp' import { watchDebounced } from '@vueuse/core' import usePreviewScreen from '@/components/PreviewScreen/usePreviewScreen'; -const { imageSize, modeList, mode, color } = useSettingStore(); +const { imageSize, modeList, mode, hFlip, vFlip, color } = useSettingStore(); const { sourceImg, imgThreshold, imgTemplates, imgTemplate, imgName } = useImageCreator(); const { screenSize } = usePreviewScreen(); const threshold = ref(imgThreshold.value) @@ -125,6 +125,19 @@ watchDebounced(threshold, async () => {
+
反转方式:
+
+ + + + +
阴阳码:
diff --git a/src/stores/useSettingStore.js b/src/stores/useSettingStore.js index 8f93e38..04f0bc5 100644 --- a/src/stores/useSettingStore.js +++ b/src/stores/useSettingStore.js @@ -24,6 +24,10 @@ export default createGlobalState(() => { // 取模助手 | 驱动库 const software = ref("取模助手"); + //镜像反转 + const hFlip = ref(false); + const vFlip = ref(false); + return { sourceList, source, @@ -31,6 +35,8 @@ export default createGlobalState(() => { imageSize, modeList, mode, + hFlip, + vFlip, color, endian, software, diff --git a/src/utils/flip.js b/src/utils/flip.js new file mode 100644 index 0000000..9d6b35d --- /dev/null +++ b/src/utils/flip.js @@ -0,0 +1,141 @@ + +/** + * 对字模字节数据进行水平/垂直对称反转 + * @param {number[]} data - 字节数据 + * @param {number} w - 宽度(像素) + * @param {number} h - 高度(像素) + * @param {string} mode - 取模方式 (列行式/行列式/逐列式/逐行式) + * @param {boolean} hFlip - 水平反转 (左右镜像) + * @param {boolean} vFlip - 垂直反转 (上下镜像) + * @returns {number[]} 反转后的数据副本 + */ +export function flipGlyphData(data, w, h, mode, hFlip, vFlip) { + if (!hFlip && !vFlip) return [...data] + + let result = [...data] + + if (mode === '列行式') { + const page = Math.ceil(h / 8) + const ps = w // 每页字节数 + + if (hFlip) { + // 水平:每页内反转列顺序 + for (let p = 0; p < page; p++) { + const base = p * ps + for (let c = 0; c < w / 2; c++) { + const a = base + c + const b = base + (w - 1 - c) + ;[result[a], result[b]] = [result[b], result[a]] + } + } + } + + if (vFlip) { + // 垂直:反转页顺序 + 每字节内位反转 + const temp = [...result] + for (let p = 0; p < page; p++) { + const srcP = page - 1 - p + for (let c = 0; c < w; c++) { + let byte = temp[srcP * ps + c] + byte = reverseBits(byte) + result[p * ps + c] = byte + } + } + } + + } else if (mode === '逐列式') { + const page = Math.ceil(h / 8) + + if (hFlip) { + // 水平:反转列顺序 + for (let c = 0; c < w / 2; c++) { + const a = c * page + const b = (w - 1 - c) * page + for (let i = 0; i < page; i++) { + ;[result[a + i], result[b + i]] = [result[b + i], result[a + i]] + } + } + } + + if (vFlip) { + // 垂直:每列内反转页顺序 + 位反转 + const temp = [...result] + for (let c = 0; c < w; c++) { + const base = c * page + for (let p = 0; p < page; p++) { + const srcP = page - 1 - p + let byte = temp[base + srcP] + byte = reverseBits(byte) + result[base + p] = byte + } + } + } + + } else if (mode === '行列式') { + const page = Math.ceil(w / 8) + const ps = h // 每水平页字节数 + + if (hFlip) { + // 水平:反转水平页顺序 + 位反转 + const temp = [...result] + for (let p = 0; p < page; p++) { + const srcP = page - 1 - p + for (let r = 0; r < h; r++) { + let byte = temp[srcP * ps + r] + byte = reverseBits(byte) + result[p * ps + r] = byte + } + } + } + + if (vFlip) { + // 垂直:每水平页内反转行顺序 + for (let p = 0; p < page; p++) { + const base = p * ps + for (let r = 0; r < h / 2; r++) { + const a = base + r + const b = base + (h - 1 - r) + ;[result[a], result[b]] = [result[b], result[a]] + } + } + } + + } else if (mode === '逐行式') { + const page = Math.ceil(w / 8) + + if (hFlip) { + // 水平:每行内反转水平页顺序 + 位反转 + const temp = [...result] + for (let r = 0; r < h; r++) { + const base = r * page + for (let p = 0; p < page; p++) { + const srcP = page - 1 - p + let byte = temp[base + srcP] + byte = reverseBits(byte) + result[base + p] = byte + } + } + } + + if (vFlip) { + // 垂直:反转行顺序 + for (let r = 0; r < h / 2; r++) { + const a = r * page + const b = (h - 1 - r) * page + for (let i = 0; i < page; i++) { + ;[result[a + i], result[b + i]] = [result[b + i], result[a + i]] + } + } + } + } + + return result +} + +//页内字节反转 +function reverseBits(b) { + b = ((b & 0xF0) >> 4) | ((b & 0x0F) << 4) + b = ((b & 0xCC) >> 2) | ((b & 0x33) << 2) + b = ((b & 0xAA) >> 1) | ((b & 0x55) << 1) + return b +}