diff --git a/.env.production b/.env.production index 7451af0f9f..9c39bf5c52 100644 --- a/.env.production +++ b/.env.production @@ -2,7 +2,6 @@ DEFAULT_ENGINE_INFOS=`[ { "uuid": "074fc39e-678b-4c13-8916-ffca8d505d1d", "name": "VOICEVOX Engine", - "iconPath": "manifest_assets/icon.png", "executionEnabled": true, "executionFilePath": "run.exe", "host": "http://127.0.0.1:50021", diff --git a/src/background.ts b/src/background.ts index 5c14bf266c..e98d362c8e 100644 --- a/src/background.ts +++ b/src/background.ts @@ -99,39 +99,6 @@ protocol.registerSchemesAsPrivileged([ const isMac = process.platform === "darwin"; -function detectImageTypeFromBase64(data: string): string { - switch (data[0]) { - case "/": - return "image/svg+xml"; - case "R": - return "image/gif"; - case "i": - return "image/png"; - case "D": - return "image/jpeg"; - default: - return ""; - } -} - -// EngineInfoからアイコンを読み込む -function replaceEngineInfoIconData(engineInfo: EngineInfo): EngineInfo { - if (!engineInfo.iconPath) return engineInfo; - let b64icon; - try { - b64icon = fs.readFileSync(path.resolve(appDirPath, engineInfo.iconPath), { - encoding: "base64", - }); - } catch (e) { - log.error("Failed to read icon file: " + engineInfo.iconPath); - return engineInfo; - } - return { - ...engineInfo, - iconData: `data:${detectImageTypeFromBase64(b64icon)};base64,${b64icon}`, - }; -} - const defaultEngineInfos: EngineInfo[] = (() => { // TODO: envから直接ではなく、envに書いたengine_manifest.jsonから情報を得るようにする const defaultEngineInfosEnv = process.env.DEFAULT_ENGINE_INFOS; @@ -141,7 +108,7 @@ const defaultEngineInfos: EngineInfo[] = (() => { engines = JSON.parse(defaultEngineInfosEnv) as EngineInfo[]; } - return engines.map(replaceEngineInfoIconData).map((engineInfo) => { + return engines.map((engineInfo) => { return { ...engineInfo, path: @@ -181,13 +148,12 @@ function fetchEngineInfosFromUserDirectory(): EngineInfo[] { uuid: manifest.uuid, host: `http://127.0.0.1:${manifest.port}`, name: manifest.name, - iconPath: path.join(engineDir, manifest.icon), path: engineDir, executionEnabled: true, executionFilePath: path.join(engineDir, manifest.command), }); } - return engines.map(replaceEngineInfoIconData); + return engines; } function fetchEngineInfos(): EngineInfo[] { diff --git a/src/components/AudioCell.vue b/src/components/AudioCell.vue index 07de862396..ca01c27049 100644 --- a/src/components/AudioCell.vue +++ b/src/components/AudioCell.vue @@ -204,6 +204,7 @@ import { computed, watch, defineComponent, ref } from "vue"; import { useStore } from "@/store"; import { AudioItem } from "@/store/type"; import { QInput, debounce } from "quasar"; +import { base64ImageToUri } from "@/helpers/imageHelper"; export default defineComponent({ name: "AudioCell", @@ -470,7 +471,7 @@ export default defineComponent({ Object.fromEntries( store.state.engineIds.map((engineId) => [ engineId, - store.state.engineInfos[engineId].iconData, + base64ImageToUri(store.state.engineManifests[engineId].icon), ]) ) ); diff --git a/src/components/MenuBar.vue b/src/components/MenuBar.vue index 0b169a1988..3ee666c1e8 100644 --- a/src/components/MenuBar.vue +++ b/src/components/MenuBar.vue @@ -45,6 +45,7 @@ import { generateAndSaveOneAudioWithDialog, connectAndExportTextWithDialog, } from "@/components/Dialog"; +import { base64ImageToUri } from "@/helpers/imageHelper"; type MenuItemBase = { type: T; @@ -99,6 +100,7 @@ export default defineComponent({ const isEdited = computed(() => store.getters.IS_EDITED); const isFullscreen = computed(() => store.getters.IS_FULLSCREEN); const engineInfos = computed(() => store.state.engineInfos); + const engineManifests = computed(() => store.state.engineManifests); const createNewProject = async () => { if (!uiLocked.value) { @@ -437,7 +439,11 @@ export default defineComponent({ ({ type: "root", label: engineInfo.name, - icon: engineInfo.iconData, + icon: + store.state.engineManifests[engineInfo.uuid] && + base64ImageToUri( + store.state.engineManifests[engineInfo.uuid].icon + ), subMenu: [ engineInfo.path && { type: "button", @@ -473,7 +479,7 @@ export default defineComponent({ ]; } } - watch(engineInfos, updateEngines, { immediate: true }); // engineInfosを見て動的に更新できるようにする + watch([engineInfos, engineManifests], updateEngines, { immediate: true }); // engineInfos、engineManifestsを見て動的に更新できるようにする watch(uiLocked, () => { // UIのロックが解除された時に再びメニューが開かれてしまうのを防ぐ diff --git a/src/helpers/imageHelper.ts b/src/helpers/imageHelper.ts new file mode 100644 index 0000000000..80b7cbf91d --- /dev/null +++ b/src/helpers/imageHelper.ts @@ -0,0 +1,24 @@ +function detectImageTypeFromBase64(data: string): string { + switch (data[0]) { + case "/": + return "image/svg+xml"; + case "R": + return "image/gif"; + case "i": + return "image/png"; + case "D": + return "image/jpeg"; + default: + return ""; + } +} + +export function base64ImageToUri(image: string): string { + const mimeType = detectImageTypeFromBase64(image); + const buffer = Buffer.from(image, "base64"); + return URL.createObjectURL( + new Blob([buffer.buffer], { + type: mimeType, + }) + ); +} diff --git a/src/store/audio.ts b/src/store/audio.ts index 58ccc59117..8052d720cd 100644 --- a/src/store/audio.ts +++ b/src/store/audio.ts @@ -31,6 +31,7 @@ import { currentDateString, } from "./utility"; import { createPartialStore } from "./vuex"; +import { base64ImageToUri } from "@/helpers/imageHelper"; async function generateUniqueIdAndQuery( state: State, @@ -414,7 +415,7 @@ export const audioStore = createPartialStore({ styleName: style.name, styleId: style.id, engineId, - iconPath: base64ToUrl(styleInfo.icon, "image/png"), + iconPath: base64ImageToUri(styleInfo.icon), voiceSamplePaths: voiceSamples, }; }); @@ -435,7 +436,7 @@ export const audioStore = createPartialStore({ }); const styles = getStyles(speaker, speakerInfo); const characterInfo: CharacterInfo = { - portraitPath: base64ToUrl(speakerInfo.portrait, "image/png"), + portraitPath: base64ImageToUri(speakerInfo.portrait), metas: { speakerUuid: speaker.speakerUuid, speakerName: speaker.name, diff --git a/src/type/preload.ts b/src/type/preload.ts index 38b98b234e..29d33c2a52 100644 --- a/src/type/preload.ts +++ b/src/type/preload.ts @@ -173,8 +173,6 @@ export type EngineInfo = { uuid: string; host: string; name: string; - iconPath?: string; - iconData?: string; path?: string; // エンジンディレクトリのパス executionEnabled: boolean; executionFilePath: string;