[feat] experimental canvas screenshot

This commit is contained in:
kwaroran
2023-07-21 00:27:03 +09:00
parent f58aaf6565
commit 0edf8d8045
5 changed files with 80 additions and 6 deletions

View File

@@ -30,6 +30,7 @@
"fflate": "^0.8.0",
"gpt-3-encoder": "^1.1.4",
"gpt3-tokenizer": "^1.1.5",
"html-to-image": "^1.11.11",
"isomorphic-dompurify": "^1.2.0",
"localforage": "^1.10.0",
"lodash": "^4.17.21",

7
pnpm-lock.yaml generated
View File

@@ -53,6 +53,9 @@ dependencies:
gpt3-tokenizer:
specifier: ^1.1.5
version: 1.1.5
html-to-image:
specifier: ^1.11.11
version: 1.11.11
isomorphic-dompurify:
specifier: ^1.2.0
version: 1.2.0
@@ -1655,6 +1658,10 @@ packages:
whatwg-encoding: 2.0.0
dev: false
/html-to-image@1.11.11:
resolution: {integrity: sha512-9gux8QhvjRO/erSnDPv28noDZcPZmYE7e1vFsBLKLlRlKDSqNJYebj6Qz1TGd5lsRV+X+xYyjCKjuZdABinWjA==}
dev: false
/http-errors@2.0.0:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}

View File

@@ -346,5 +346,7 @@ export const languageEnglish = {
createBotInternetAlert: "Please provide the character's name and the corresponding series/game.",
able:"Able",
assetWidth: "Asset Images Max Width",
animationSpeed: "Animation Speed"
animationSpeed: "Animation Speed",
screenshot: "Screenshot",
screenshotSaved: "Screenshot Saved",
}

View File

@@ -76,7 +76,7 @@
$: displaya(message)
</script>
<div class="flex max-w-full justify-center" class:bgc={isLastMemory}>
<div class="flex max-w-full justify-center risu-chat" class:bgc={isLastMemory}>
<div class="text-neutral-200 mt-1 ml-4 mr-4 mb-1 p-2 bg-transparent flex-grow border-t-gray-900 border-opacity-30 border-transparent flexium items-start max-w-full" >
{#await img}
<div class="shadow-lg bg-gray-500 mt-2" style={`height:${$DataBase.iconsize * 3.5 / 100}rem;width:${$DataBase.iconsize * 3.5 / 100}rem;min-width:${$DataBase.iconsize * 3.5 / 100}rem`}

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import Suggestion from './Suggestion.svelte';
import { DatabaseIcon, DicesIcon, LanguagesIcon, Laugh, MenuIcon, MicOffIcon, RefreshCcwIcon, ReplyIcon, Send } from "lucide-svelte";
import { CameraIcon, DatabaseIcon, DicesIcon, LanguagesIcon, Laugh, MenuIcon, MicOffIcon, RefreshCcwIcon, ReplyIcon, Send } from "lucide-svelte";
import { selectedCharID } from "../../ts/stores";
import Chat from "./Chat.svelte";
import { DataBase, type Message, type character, type groupChat } from "../../ts/storage/database";
@@ -9,7 +9,7 @@
import { findCharacterbyId, messageForm, sleep } from "../../ts/util";
import { language } from "../../lang";
import { translate } from "../../ts/translator/translator";
import { alertError } from "../../ts/alert";
import { alertError, alertNormal, alertWait } from "../../ts/alert";
import sendSound from '../../etc/send.mp3'
import {cloneDeep} from 'lodash'
import { processScript } from "src/ts/process/scripts";
@@ -18,6 +18,7 @@
import MainMenu from '../UI/MainMenu.svelte';
import Help from '../Others/Help.svelte';
import AssetInput from './AssetInput.svelte';
import { downloadFile } from 'src/ts/storage/globalApi';
let messageInput:string = ''
let messageInputTranslate:string = ''
@@ -222,6 +223,59 @@
})
}
async function screenShot(){
try {
loadPages = Infinity
const html2canvas = await import('html-to-image');
const chats = document.querySelectorAll('.default-chat-screen .risu-chat')
alertWait("Taking screenShot...")
let canvases:HTMLCanvasElement[] = []
for(const chat of chats){
const cnv = await html2canvas.toCanvas(chat as HTMLElement)
canvases.push(cnv)
}
canvases.reverse()
let mergedCanvas = document.createElement('canvas');
mergedCanvas.width = 0;
mergedCanvas.height = 0;
let mergedCtx = mergedCanvas.getContext('2d');
let totalHeight = 0;
let maxWidth = 0;
for(let i = 0; i < canvases.length; i++) {
let canvas = canvases[i];
totalHeight += canvas.height;
maxWidth = Math.max(maxWidth, canvas.width);
mergedCanvas.width = maxWidth;
mergedCanvas.height = totalHeight;
}
mergedCtx.fillStyle = '#282a36'
mergedCtx.fillRect(0, 0, maxWidth, totalHeight);
let indh = 0
for(let i = 0; i < canvases.length; i++) {
let canvas = canvases[i];
indh += canvas.height
mergedCtx.drawImage(canvas, 0, indh - canvas.height);
canvases[i].remove();
}
if(mergedCanvas){
await downloadFile("chat.png", Buffer.from(mergedCanvas.toDataURL('png').split(',').at(-1), 'base64'))
mergedCanvas.remove();
}
alertNormal(language.screenshotSaved)
loadPages = 30
} catch (error) {
console.error(error)
alertError("Error while taking screenshot")
}
}
$: {
currentCharacter = $DataBase.characters[$selectedCharID]
}
@@ -233,7 +287,7 @@
{#if $selectedCharID < 0}
<MainMenu />
{:else}
<div class="h-full w-full flex flex-col-reverse overflow-y-auto relative" on:scroll={(e) => {
<div class="h-full w-full flex flex-col-reverse overflow-y-auto relative default-chat-screen" on:scroll={(e) => {
//@ts-ignore
const scrolled = (e.target.scrollHeight - e.target.clientHeight + e.target.scrollTop)
if(scrolled < 100 && $DataBase.characters[$selectedCharID].chats[$DataBase.characters[$selectedCharID].chatPage].message.length > loadPages){
@@ -470,6 +524,16 @@
{/if}
{#if $DataBase.useExperimental}
<div class="flex items-center cursor-pointer hover:text-green-500 transition-colors" on:click={() => {
screenShot()
}}>
<CameraIcon />
<span class="ml-2">{language.screenshot} <Help key="experimental"/></span>
</div>
{/if}
<div class={"flex items-center cursor-pointer "+ ($DataBase.useAutoSuggestions ? 'text-green-500':'lg:hover:text-green-500')} on:click={async () => {
$DataBase.useAutoSuggestions = !$DataBase.useAutoSuggestions
}}>