Demo:
components/imgDecode.vue
:
<script setup>
import { nextTick, ref } from "vue";
import markdownIt from "markdown-it";
import { invoke, convertFileSrc } from '@tauri-apps/api/tauri';
import { resolve, resourceDir } from '@tauri-apps/api/path';
import { readBinaryFile } from "@tauri-apps/api/fs";
const md = markdownIt();
md.set({ html: true });
const md_context = ref();
// an arbitrary image in the /img dir in my project
let img_path = "E:/myProjects2/tauri_vue/mdren/img/a-1-01.png";
// convert the image file from Uint8Array to string, then solve it with window.btoa
const contents = await readBinaryFile(img_path);
const str_contents = () => {
let binary = "";
let len = contents.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return binary;
}
let src = window.btoa(str_contents);
// an async logics
currentLogics();
async function currentLogics() {
try {
// process the markdown file first
await solveMd();
// re-render the images after the DOM has changed
nextTick(() => {
reloadImg();
})
} catch (e) {
console.log(e);
}
}
async function solveMd() {
md_context.value = await md.render("$\xRightarrow{aaaaaaaaaaaaaaaaaaa}$nn<img id='img-to-remove' src='../img/a-1-01.png'>");
// ignore the xRightarrow line, the markdown-it-katex cannot stretch it properly, and it's temporarily fixed with other methods
}
async function reloadImg() {
console.log("function called");
let img_element = document.querySelectorAll("#img-to-remove");
console.log(img_element);
img_element.forEach(async (element) => {
element.src = "data:image/png;base64," + src;
});
}
</script>
<template>
<div v-html="md_context"></div>
</template>
<style scoped>
</style>
App.vue
:
<script setup>
import imgDecode from "./components/imgDecode.vue";
</script>
<template>
<Suspense>
<resolveData />
</Suspense>
</template>
<style scoped>
</style>
I wrote a markdown rendering tool using tauri + Vue3 + markdown-it, but there are images in the markdown files, the contents are binded to the pages with v-html
, so all the assets resolved using relative routes.
The images are rendered properly with npm run tauri dev
, with a localhost built in the main directory of the project. However with npm run tauri build
, this won’t work, the images cannot render mainly due to the security policy.
Then I revised the tauri.conf.json
as the ConvertFileSrc shows, setting the tauri.security.csp
as "csp": "default-src 'self'; img-src '*' asset: https://asset.localhost"
, where the '*'
is set as other blogs suggests (actually it does not work with 'self'
either), and the images still won’t show.
Then I tried to use the Rust backend to read the file and send it to the frontend, using the blob
to create a url, however the image seems broken, but the img src in dev tools seemed proper.
Afterwards I tried the tauri/api/fs
. First, setting the tauri.allowlist.fs
in the tauri.conf.json
to:
"fs": {
"all": true,
"scope": ["D:/**", "E:/**"]
}
which allows it to read all the files in the disks, then set the csp
to: "csp": "asset:"
. The main logics to prosess the image is:
let img_path = "E:/myProjects2/tauri_vue/mdren/img/a-1-01.png";
const contents = await readBinaryFile(img_path);
const str_contents = () => {
let binary = "";
let len = contents.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return binary;
} // contents: Uint8Array -> string
let src = window.btoa(str_contents); // window.btoa: string -> url
// ...
// call reloadImg after the DOM has changed, re-render the <img id="img-to-remove" ...>
async function reloadImg() {
console.log("function called");
let img_element = document.querySelectorAll("#img-to-remove");
console.log(img_element);
img_element.forEach(async (element) => {
element.src = "data:image/png;base64," + src;
});
}
which is shown at the beginning of the question. These attempts all worked well except the last step, the img src all seemed correct, but the images are all broken. I guess this problem might be caused with the readBinaryFile
and the attempts using the Rust backend to read the file. The csp and rendering all passed my tests.