From 4fdc533bd70c99f8e42005fc1a7e2f21ecf16884 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sun, 10 Sep 2023 18:22:39 +0300 Subject: [PATCH 1/4] Change net workaround for node 20 --- server.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 2b0065486..a4f71c935 100644 --- a/server.js +++ b/server.js @@ -90,8 +90,13 @@ function createDefaultFiles() { } const net = require("net"); -// @ts-ignore work around a node v20 bug: https://github.com/nodejs/node/issues/47822#issuecomment-1564708870 -if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false); +// Work around a node v20.0.0, v20.1.0, and v20.2.0 bug. The issue was fixed in v20.3.0. +// https://github.com/nodejs/node/issues/47822#issuecomment-1564708870 +// Safe to remove once support for Node v20 is dropped. +if (process.versions && process.versions.node && process.versions.node.match(/20\.[0-2]\.0/)) { + // @ts-ignore + if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false); +} const cliArguments = yargs(hideBin(process.argv)) .option('disableCsrf', { From 74d627f674b57644c6791a151da3cf1a09377033 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sun, 10 Sep 2023 19:02:58 +0300 Subject: [PATCH 2/4] Set default DNS resolution order to IPv4 first --- server.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index a4f71c935..d1ecd8058 100644 --- a/server.js +++ b/server.js @@ -32,6 +32,8 @@ const multer = require("multer"); const responseTime = require('response-time'); // net related library imports +const net = require("net"); +const dns = require('dns'); const DeviceDetector = require("device-detector-js"); const fetch = require('node-fetch').default; const ipaddr = require('ipaddr.js'); @@ -89,7 +91,6 @@ function createDefaultFiles() { } } -const net = require("net"); // Work around a node v20.0.0, v20.1.0, and v20.2.0 bug. The issue was fixed in v20.3.0. // https://github.com/nodejs/node/issues/47822#issuecomment-1564708870 // Safe to remove once support for Node v20 is dropped. @@ -98,6 +99,9 @@ if (process.versions && process.versions.node && process.versions.node.match(/20 if (net.setDefaultAutoSelectFamily) net.setDefaultAutoSelectFamily(false); } +// Set default DNS resolution order to IPv4 first +dns.setDefaultResultOrder('ipv4first'); + const cliArguments = yargs(hideBin(process.argv)) .option('disableCsrf', { type: 'boolean', From 6c8bd06308c69d51e2eb174541792a870a83d2d6 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Mon, 11 Sep 2023 17:22:31 +0300 Subject: [PATCH 3/4] Reserve 3 extra tokens for each chat completion --- public/scripts/openai.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 3ac66f0df..d4764f02b 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -576,6 +576,7 @@ function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, ty chatCompletion.add(collection, index); }; + chatCompletion.reserveBudget(3); // every reply is primed with <|start|>assistant<|message|> // Character and world information addToChatCompletion('worldInfoBefore'); addToChatCompletion('main'); @@ -1761,9 +1762,12 @@ class ChatCompletion { /** * Reserves the tokens required by the given message from the token budget. * - * @param {Message|MessageCollection} message - The message whose tokens to reserve. + * @param {Message|MessageCollection|number} message - The message whose tokens to reserve. */ - reserveBudget(message) { this.decreaseTokenBudgetBy(message.getTokens()) }; + reserveBudget(message) { + const tokens = typeof message === 'number' ? message : message.getTokens(); + this.decreaseTokenBudgetBy(tokens); + }; /** * Frees up the tokens used by the given message from the token budget. From 2b3055a84adee50a55c97c20f9ca8d6ff061c28d Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 15 Sep 2023 14:56:15 +0300 Subject: [PATCH 4/4] Webp cards format is no longer supported --- .github/readme-zh_cn.md | 2 - .github/readme.md | 3 - package-lock.json | 35 +--------- package.json | 5 +- public/i18n.json | 6 -- public/index.html | 3 +- public/script.js | 3 +- server.js | 99 ++-------------------------- src/character-card-parser.js | 46 +------------ tools/charaverter/main.mjs | 117 --------------------------------- tools/charaverter/package.json | 10 --- 11 files changed, 10 insertions(+), 319 deletions(-) delete mode 100644 tools/charaverter/main.mjs delete mode 100644 tools/charaverter/package.json diff --git a/.github/readme-zh_cn.md b/.github/readme-zh_cn.md index 3ad3a60d9..d1212b8f8 100644 --- a/.github/readme-zh_cn.md +++ b/.github/readme-zh_cn.md @@ -41,8 +41,6 @@ SillyTavern 本身并无用处,因为它只是一个用户聊天界面。你 -Termux 不支持**.Webp 字符卡的导入/导出。请使用 JSON 或 PNG 格式**。 - ## 有问题或建议? ### 我们现在有了 Discord 社区 diff --git a/.github/readme.md b/.github/readme.md index e567330ed..3ff551fbd 100644 --- a/.github/readme.md +++ b/.github/readme.md @@ -41,8 +41,6 @@ Since Tavern is only a user interface, it has tiny hardware requirements, it wil -**.webp character cards import/export is not supported in Termux. Use either JSON or PNG formats instead.** - ## Questions or suggestions? ### We now have a community Discord server @@ -71,7 +69,6 @@ Get in touch with the developers directly: * [Oobabooga's TextGen WebUI](https://github.com/oobabooga/text-generation-webui) API connection * [AI Horde](https://horde.koboldai.net/) connection * Prompt generation formatting tweaking -* webp character card interoperability (PNG is still an internal format) ## Extensions diff --git a/package-lock.json b/package-lock.json index 9bde269ce..7e62b870e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sillytavern", - "version": "1.10.2", + "version": "1.10.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sillytavern", - "version": "1.10.2", + "version": "1.10.3", "license": "AGPL-3.0", "dependencies": { "@agnai/sentencepiece-js": "^1.1.1", @@ -18,7 +18,6 @@ "cors": "^2.8.5", "csrf-csrf": "^2.2.3", "device-detector-js": "^3.0.3", - "exifreader": "^4.12.0", "express": "^4.18.2", "google-translate-api-browser": "^3.0.1", "gpt3-tokenizer": "^1.1.5", @@ -32,7 +31,6 @@ "multer": "^1.4.5-lts.1", "node-fetch": "^2.6.11", "open": "^8.4.2", - "piexifjs": "^1.0.6", "png-chunk-text": "^1.0.0", "png-chunks-encode": "^1.0.0", "png-chunks-extract": "^1.0.0", @@ -40,7 +38,6 @@ "sanitize-filename": "^1.6.3", "simple-git": "^3.19.1", "uniqolor": "^1.1.0", - "webp-converter": "2.3.2", "write-file-atomic": "^5.0.1", "ws": "^8.13.0", "yargs": "^17.7.1", @@ -652,15 +649,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.9", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.9.tgz", - "integrity": "sha512-4VSbbcMoxc4KLjb1gs96SRmi7w4h1SF+fCoiK0XaQX62buCc1G5d0DC5bJ9xJBNPDSVCmIrcl8BiYxzjrqaaJA==", - "optional": true, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -1281,15 +1269,6 @@ "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" }, - "node_modules/exifreader": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.13.0.tgz", - "integrity": "sha512-IhJBpyXDLbCdgzVHkthadOvrMiZOR2XS7POVp0b5JoVfScRoCJ6YazZ+stTkbDTE5TRTP44bE5RKsujckAs45Q==", - "hasInstallScript": true, - "optionalDependencies": { - "@xmldom/xmldom": "^0.8.8" - } - }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -2381,11 +2360,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/piexifjs": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/piexifjs/-/piexifjs-1.0.6.tgz", - "integrity": "sha512-0wVyH0cKohzBQ5Gi2V1BuxYpxWfxF3cSqfFXfPIpl5tl9XLS5z4ogqhUCD20AbHi0h9aJkqXNJnkVev6gwh2ag==" - }, "node_modules/pixelmatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", @@ -3385,11 +3359,6 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, - "node_modules/webp-converter": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/webp-converter/-/webp-converter-2.3.2.tgz", - "integrity": "sha512-9kQ9Q/MPzUV2mye8Tv7vA6vDIPk77rI4AWWm2vSaCyGAEsxqyVZYeVU2MSJY5fLkf6u7G5K343vLxKubOxz16Q==" - }, "node_modules/whatwg-fetch": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", diff --git a/package.json b/package.json index 0dc6193d3..2f39298a7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,6 @@ "cors": "^2.8.5", "csrf-csrf": "^2.2.3", "device-detector-js": "^3.0.3", - "exifreader": "^4.12.0", "express": "^4.18.2", "google-translate-api-browser": "^3.0.1", "gpt3-tokenizer": "^1.1.5", @@ -23,7 +22,6 @@ "multer": "^1.4.5-lts.1", "node-fetch": "^2.6.11", "open": "^8.4.2", - "piexifjs": "^1.0.6", "png-chunk-text": "^1.0.0", "png-chunks-encode": "^1.0.0", "png-chunks-extract": "^1.0.0", @@ -31,7 +29,6 @@ "sanitize-filename": "^1.6.3", "simple-git": "^3.19.1", "uniqolor": "^1.1.0", - "webp-converter": "2.3.2", "write-file-atomic": "^5.0.1", "ws": "^8.13.0", "yargs": "^17.7.1", @@ -49,7 +46,7 @@ "type": "git", "url": "https://github.com/SillyTavern/SillyTavern.git" }, - "version": "1.10.2", + "version": "1.10.3", "scripts": { "start": "node server.js", "start-multi": "node server.js --disableCsrf", diff --git a/public/i18n.json b/public/i18n.json index 8c055d552..af0a330e5 100644 --- a/public/i18n.json +++ b/public/i18n.json @@ -284,7 +284,6 @@ "Regenerate": "重新生成", "PNG": "PNG", "JSON": "JSON", - "WEBP": "WEBP", "presets": "预设", "Message Sound": "AI 消息提示音", "Author's Note": "作者注释", @@ -836,7 +835,6 @@ "Regenerate": "再生成", "PNG": "PNG", "JSON": "JSON", - "WEBP": "WEBP", "presets": "プリセット", "Message Sound": "メッセージ音", "Author's Note": "作者の注記", @@ -1392,7 +1390,6 @@ "Regenerate": "재생성", "PNG": "PNG", "JSON": "JSON", - "WEBP": "WEBP", "presets": "기본설정", "Message Sound": "메시지 효과음", "Author's Note": "글쓴이 쪽지", @@ -2016,7 +2013,6 @@ "Regenerate": "Повторная генерация", "PNG": "PNG", "JSON": "JSON", - "WEBP": "WEBP", "presets": "Предустановки", "Message Sound": "Звук сообщения", "Author's Note": "Авторские заметки", @@ -2580,7 +2576,6 @@ "Regenerate": "Rigenera", "PNG": "PNG", "JSON": "JSON", - "WEBP": "WEBP", "presets": "preset", "Message Sound": "Suono del messaggio", "Author's Note": "Note d'autore", @@ -3259,7 +3254,6 @@ "Regenerate": "Regenereren", "PNG": "PNG", "JSON": "JSON", - "WEBP": "WEBP", "presets": "sjablonen", "Message Sound": "Berichtgeluid", "Author's Note": "Notitie van auteur", diff --git a/public/index.html b/public/index.html index 616e69e15..f8732fed8 100644 --- a/public/index.html +++ b/public/index.html @@ -3482,7 +3482,7 @@ @@ -4445,7 +4445,6 @@
PNG
JSON
-
WEBP
diff --git a/public/script.js b/public/script.js index 078319658..e6f3a67ef 100644 --- a/public/script.js +++ b/public/script.js @@ -6746,7 +6746,6 @@ export function processDroppedFiles(files) { const allowedMimeTypes = [ 'application/json', 'image/png', - 'image/webp', ]; for (const file of files) { @@ -6762,7 +6761,7 @@ function importCharacter(file) { const ext = file.name.match(/\.(\w+)$/); if ( !ext || - (ext[1].toLowerCase() != "json" && ext[1].toLowerCase() != "png" && ext[1] != "webp") + (ext[1].toLowerCase() != "json" && ext[1].toLowerCase() != "png") ) { return; } diff --git a/server.js b/server.js index d1ecd8058..ad26df9c2 100644 --- a/server.js +++ b/server.js @@ -42,13 +42,11 @@ const json5 = require('json5'); const WebSocket = require('ws'); // image processing related library imports -const exif = require('piexifjs'); const encode = require('png-chunks-encode'); const extract = require('png-chunks-extract'); const jimp = require('jimp'); const mime = require('mime-types'); const PNGtext = require('png-chunk-text'); -const webp = require('webp-converter'); const yauzl = require('yauzl'); // tokenizing related library imports @@ -1137,7 +1135,7 @@ app.post("/renamecharacter", jsonParser, async function (request, response) { try { // Read old file, replace name int it const rawOldData = await charaRead(oldAvatarPath); - if (rawOldData === false || rawOldData === undefined) throw new Error("Failed to read character file"); + if (rawOldData === undefined) throw new Error("Failed to read character file"); const oldData = getCharaCardV2(json5.parse(rawOldData)); _.set(oldData, 'data.name', newName); @@ -1384,7 +1382,7 @@ const calculateDataSize = (data) => { const processCharacter = async (item, i) => { try { const img_data = await charaRead(charactersPath + item); - if (img_data === false || img_data === undefined) throw new Error("Failed to read character file"); + if (img_data === undefined) throw new Error("Failed to read character file"); let jsonObject = getCharaCardV2(json5.parse(img_data)); jsonObject.avatar = item; @@ -2221,26 +2219,13 @@ app.post("/importcharacter", urlencodedParser, async function (request, response } else { try { var img_data = await charaRead(uploadPath, format); - if (img_data === false || img_data === undefined) throw new Error('Failed to read character data'); + if (img_data === undefined) throw new Error('Failed to read character data'); let jsonData = json5.parse(img_data); jsonData.name = sanitize(jsonData.data?.name || jsonData.name); png_name = getPngName(jsonData.name); - if (format == 'webp') { - try { - let convertedPath = path.join(UPLOADS_PATH, path.basename(uploadPath, ".webp") + ".png") - await webp.dwebp(uploadPath, convertedPath, "-o"); - fs.unlinkSync(uploadPath); - uploadPath = convertedPath; - } - catch { - console.error('WEBP image conversion failed. Using the default character image.'); - uploadPath = defaultAvatarPath; - } - } - if (jsonData.spec !== undefined) { console.log('Found a v2 character file.'); importRisuSprites(jsonData); @@ -2420,7 +2405,7 @@ app.post("/exportcharacter", jsonParser, async function (request, response) { case 'json': { try { let json = await charaRead(filename); - if (json === false || json === undefined) return response.sendStatus(400); + if (json === undefined) return response.sendStatus(400); let jsonObject = getCharaCardV2(json5.parse(json)); return response.type('json').send(jsonObject) } @@ -2428,39 +2413,6 @@ app.post("/exportcharacter", jsonParser, async function (request, response) { return response.sendStatus(400); } } - case 'webp': { - try { - let json = await charaRead(filename); - if (json === false || json === undefined) return response.sendStatus(400); - let stringByteArray = utf8Encode.encode(json).toString(); - let inputWebpPath = path.join(UPLOADS_PATH, `${Date.now()}_input.webp`); - let outputWebpPath = path.join(UPLOADS_PATH, `${Date.now()}_output.webp`); - let metadataPath = path.join(UPLOADS_PATH, `${Date.now()}_metadata.exif`); - let metadata = - { - "Exif": { - [exif.ExifIFD.UserComment]: stringByteArray, - }, - }; - const exifString = exif.dump(metadata); - writeFileAtomicSync(metadataPath, exifString, 'binary'); - - await webp.cwebp(filename, inputWebpPath, '-q 95'); - await webp.webpmux_add(inputWebpPath, outputWebpPath, metadataPath, 'exif'); - - response.sendFile(outputWebpPath, { root: process.cwd() }, () => { - fs.rmSync(inputWebpPath); - fs.rmSync(metadataPath); - fs.rmSync(outputWebpPath); - }); - - return; - } - catch (err) { - console.log(err); - return response.sendStatus(400); - } - } } return response.sendStatus(400); @@ -4089,8 +4041,6 @@ const setupTasks = async function () { contentManager.checkForNewContent(); cleanUploads(); - await convertWebp(); - [spp_llama, spp_nerd, spp_nerd_v2, claude_tokenizer] = await Promise.all([ loadSentencepieceTokenizer('src/sentencepiece/tokenizer.model'), loadSentencepieceTokenizer('src/sentencepiece/nerdstash.model'), @@ -4150,47 +4100,6 @@ if (true === cliArguments.ssl) { ); } -async function convertWebp() { - const files = fs.readdirSync(directories.characters).filter(e => e.endsWith(".webp")); - - if (!files.length) { - return; - } - - console.log(`${files.length} WEBP files will be automatically converted.`); - - for (const file of files) { - try { - const source = path.join(directories.characters, file); - const dest = path.join(directories.characters, path.basename(file, ".webp") + ".png"); - - if (fs.existsSync(dest)) { - console.log(`${dest} already exists. Delete ${source} manually`); - continue; - } - - console.log(`Read... ${source}`); - const data = await charaRead(source); - - console.log(`Convert... ${source} -> ${dest}`); - await webp.dwebp(source, dest, "-o"); - - console.log(`Write... ${dest}`); - const success = await charaWrite(dest, data, path.parse(dest).name); - - if (!success) { - console.log(`Failure on ${source} -> ${dest}`); - continue; - } - - console.log(`Remove... ${source}`); - fs.rmSync(source); - } catch (err) { - console.log(err); - } - } -} - function backupSettings() { const MAX_BACKUPS = 25; diff --git a/src/character-card-parser.js b/src/character-card-parser.js index 6f2e73479..adbdca6c7 100644 --- a/src/character-card-parser.js +++ b/src/character-card-parser.js @@ -1,56 +1,12 @@ const fs = require('fs'); -const json5 = require('json5'); -const ExifReader = require('exifreader'); const extract = require('png-chunks-extract'); const PNGtext = require('png-chunk-text'); -const utf8Decode = new TextDecoder('utf-8', { ignoreBOM: true }); - const parse = async (cardUrl, format) => { - let fileFormat; - if (format === undefined) { - if (cardUrl.indexOf('.webp') !== -1) - fileFormat = 'webp'; - else - fileFormat = 'png'; - } - else - fileFormat = format; + let fileFormat = format === undefined ? 'png' : format; switch (fileFormat) { - case 'webp': - try { - const exif_data = await ExifReader.load(fs.readFileSync(cardUrl)); - let char_data; - - if (exif_data['UserComment']['description']) { - let description = exif_data['UserComment']['description']; - if (description === 'Undefined' && exif_data['UserComment'].value && exif_data['UserComment'].value.length === 1) { - description = exif_data['UserComment'].value[0]; - } - - try { - json5.parse(description); - char_data = description; - } catch { - const byteArr = description.split(",").map(Number); - const uint8Array = new Uint8Array(byteArr); - const char_data_string = utf8Decode.decode(uint8Array); - char_data = char_data_string; - } - } - else { - console.log('No description found in EXIF data.'); - return false; - } - - return char_data; - } - catch (err) { - console.log(err); - return false; - } case 'png': const buffer = fs.readFileSync(cardUrl); const chunks = extract(buffer); diff --git a/tools/charaverter/main.mjs b/tools/charaverter/main.mjs deleted file mode 100644 index da7f3123d..000000000 --- a/tools/charaverter/main.mjs +++ /dev/null @@ -1,117 +0,0 @@ -import fs from 'fs'; -import jimp from 'jimp'; -import extract from 'png-chunks-extract'; -import encode from 'png-chunks-encode'; -import PNGtext from 'png-chunk-text'; -import ExifReader from 'exifreader'; -import webp from 'webp-converter'; -import path from 'path'; - -async function charaRead(img_url, input_format){ - let format; - if(input_format === undefined){ - if(img_url.indexOf('.webp') !== -1){ - format = 'webp'; - }else{ - format = 'png'; - } - }else{ - format = input_format; - } - - switch(format){ - case 'webp': - const exif_data = await ExifReader.load(fs.readFileSync(img_url)); - const char_data = exif_data['UserComment']['description']; - if (char_data === 'Undefined' && exif_data['UserComment'].value && exif_data['UserComment'].value.length === 1) { - return exif_data['UserComment'].value[0]; - } - return char_data; - case 'png': - const buffer = fs.readFileSync(img_url); - const chunks = extract(buffer); - - const textChunks = chunks.filter(function (chunk) { - return chunk.name === 'tEXt'; - }).map(function (chunk) { - //console.log(text.decode(chunk.data)); - return PNGtext.decode(chunk.data); - }); - var base64DecodedData = Buffer.from(textChunks[0].text, 'base64').toString('utf8'); - return base64DecodedData;//textChunks[0].text; - //console.log(textChunks[0].keyword); // 'hello' - //console.log(textChunks[0].text); // 'world' - default: - break; - } - -} - -async function charaWrite(img_url, data, target_img, response = undefined, mes = 'ok') { - try { - // Read the image, resize, and save it as a PNG into the buffer - - webp - - const rawImg = await jimp.read(img_url); - const image = await rawImg.cover(400, 600).getBufferAsync(jimp.MIME_PNG); - - // Get the chunks - const chunks = extract(image); - const tEXtChunks = chunks.filter(chunk => chunk.create_date === 'tEXt'); - - // Remove all existing tEXt chunks - for (let tEXtChunk of tEXtChunks) { - chunks.splice(chunks.indexOf(tEXtChunk), 1); - } - // Add new chunks before the IEND chunk - const base64EncodedData = Buffer.from(data, 'utf8').toString('base64'); - chunks.splice(-1, 0, PNGtext.encode('chara', base64EncodedData)); - //chunks.splice(-1, 0, text.encode('lorem', 'ipsum')); - - fs.writeFileSync(target_img, new Buffer.from(encode(chunks))); - if (response !== undefined) response.send(mes); - return true; - - - } catch (err) { - console.log(err); - if (response !== undefined) response.status(500).send(err); - return false; - } -} - - -(async function() { - const spath = process.argv[2] - const dpath = process.argv[3] || spath - const files = fs.readdirSync(spath).filter(e => e.endsWith(".webp")) - if (!files.length) { - console.log("Nothing to convert.") - return - } - - try { fs.mkdirSync(dpath) } catch {} - - for(const f of files) { - const source = path.join(spath, f), - dest = path.join(dpath, path.basename(f, ".webp") + ".png") - - console.log(`Read... ${source}`) - const data = await charaRead(source) - - console.log(`Convert... ${source} -> ${dest}`) - await webp.dwebp(source, dest, "-o") - - console.log(`Write... ${dest}`) - const success = await charaWrite(dest, data, path.parse(dest).name); - - if (!success) { - console.log(`Failure on ${source} -> ${dest}`); - continue; - } - - console.log(`Remove... ${source}`) - fs.rmSync(source) - } -})() \ No newline at end of file diff --git a/tools/charaverter/package.json b/tools/charaverter/package.json deleted file mode 100644 index 5f4db5583..000000000 --- a/tools/charaverter/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "dependencies": { - "exifreader": "^4.12.0", - "jimp": "^0.22.7", - "png-chunk-text": "^1.0.0", - "png-chunks-encode": "^1.0.0", - "png-chunks-extract": "^1.0.0", - "webp-converter": "^2.3.3" - } -}