-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
512 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
node_modules | ||
dist | ||
package-lock.json | ||
rcc/qresource/ | ||
*.rcc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,24 @@ | ||
# Nekiro-s-Rcc-Editor | ||
# Nekiro's Rcc Editor | ||
|
||
You need nodejs and npm installed. | ||
|
||
### How to use? | ||
|
||
- Navigate to project directory | ||
- npm i | ||
- npm run start | ||
|
||
To compile write | ||
|
||
- npm run dist | ||
|
||
Compiled binaries are located in "dist" directory. | ||
By default both win32 and x64 versions are being compiled | ||
|
||
If you don't want to compile, download latest version from releases. | ||
|
||
Enjoy. | ||
|
||
## Donate | ||
|
||
If you like my work and respect my time, consider becoming [Github Sponsor](https://github.com/sponsors/nekiro). |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
body { | ||
margin: 0; | ||
padding: 0; | ||
height: 100vh; | ||
background-color: #222831; | ||
display: grid; | ||
grid-template-columns: 1fr 4fr; | ||
user-select: none; | ||
} | ||
|
||
div::-webkit-scrollbar-track { | ||
background-color: #222831; | ||
border: 1px solid black; | ||
border-right: 1px transparent; | ||
} | ||
div::-webkit-scrollbar { | ||
width: 12px; | ||
} | ||
div::-webkit-scrollbar-thumb { | ||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); | ||
background-color: #393e46; | ||
} | ||
|
||
.list { | ||
background-color: #393e46; | ||
border: 1px solid black; | ||
overflow: auto; | ||
overflow-x: hidden; | ||
} | ||
.list button { | ||
text-align: end; | ||
width: 100%; | ||
min-height: 30px; | ||
max-height: 200px; | ||
border: transparent; | ||
border-bottom: 1px solid black; | ||
background: transparent; | ||
color: lightgray; | ||
display: grid; | ||
grid-template-columns: 80% 20%; | ||
align-items: center; | ||
column-gap: 10px; | ||
justify-content: center; | ||
} | ||
.list button:hover { | ||
color: gold; | ||
background-color: #222831; | ||
} | ||
.focused { | ||
background-color: #222831 !important; | ||
color: gold !important; | ||
} | ||
|
||
.preview { | ||
background-color: #393e46; | ||
padding: 25px; | ||
} | ||
|
||
.center-container { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
} | ||
.miniature-holder { | ||
overflow: auto; | ||
margin-left: 30px; | ||
margin-right: 30px; | ||
} | ||
.miniature { | ||
width: auto; | ||
height: auto; | ||
max-width: 40px; | ||
justify-self: start; | ||
max-height: 30px; | ||
object-fit: contain; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta | ||
http-equiv="Content-Security-Policy" | ||
content="default-src 'self'; img-src 'self' data:; script-src 'self' 'unsafe-inline'" | ||
/> | ||
<link rel="stylesheet" href="../css/style.css" /> | ||
</head> | ||
<body> | ||
<div class="list"></div> | ||
<div class="center-container miniature-holder"> | ||
<img | ||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" | ||
class="preview" | ||
/> | ||
</div> | ||
<script src="../js/mainRenderer.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
const { ipcMain } = require("electron"); | ||
const { getImageByIndex, replaceImage } = require("./reader"); | ||
|
||
ipcMain.on("get-image-data", (event, index) => { | ||
event.reply("update-preview", getImageByIndex(index)); | ||
}); | ||
|
||
ipcMain.on("replace-image", async (event, obj) => { | ||
const data = await replaceImage(obj.index, obj.path); | ||
if (data) { | ||
event.reply("update-preview", data); | ||
event.reply("update-miniature", { index: obj.index, data }); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
//renderer process | ||
const { ipcRenderer } = require("electron"); | ||
|
||
const preview = document.querySelector(".preview"); | ||
const list = document.querySelector(".list"); | ||
let focused = null; | ||
|
||
preview.addEventListener("drop", (event) => { | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
|
||
if (!focused) { | ||
return; | ||
} | ||
|
||
ipcRenderer.send("replace-image", { | ||
index: parseInt(focused.id.split("-")[1]), | ||
path: fevent.dataTransfer.files[0].path, | ||
}); | ||
}); | ||
|
||
preview.addEventListener("dragover", (e) => { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
}); | ||
|
||
ipcRenderer.on("update-preview", (event, data) => { | ||
preview.src = `data:image/png;base64,${Buffer.from(data).toString("base64")}`; | ||
}); | ||
|
||
ipcRenderer.on("update-miniature", (event, { index, data }) => { | ||
list.querySelector( | ||
`#btn-${index} > img` | ||
).src = `data:image/png;base64,${Buffer.from(data).toString("base64")}`; | ||
}); | ||
|
||
ipcRenderer.on("populate-list", (event, images) => { | ||
focused = null; | ||
|
||
while (list.firstChild) { | ||
list.removeChild(list.firstChild); | ||
} | ||
|
||
for (let index = 0; index < images.length; ++index) { | ||
const image = images[index]; | ||
|
||
if (!image.isImage) { | ||
continue; | ||
} | ||
|
||
let btn = document.createElement("button"); | ||
btn.innerText = `${image.name}`; | ||
btn.id = `btn-${index}`; | ||
btn.onclick = (event) => { | ||
if (focused == event.target) { | ||
return; | ||
} | ||
|
||
if (focused) { | ||
focused.classList.remove("focused"); | ||
} | ||
|
||
focused = event.target; | ||
focused.classList.add("focused"); | ||
ipcRenderer.send("get-image-data", index); | ||
}; | ||
|
||
let img = document.createElement("img"); | ||
img.className = "miniature"; | ||
img.src = `data:image/png;base64,${Buffer.from(image.data).toString( | ||
"base64" | ||
)}`; | ||
btn.appendChild(img); | ||
|
||
list.appendChild(btn); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
const { dialog, BrowserWindow, app } = require("electron"); | ||
const path = require("path"); | ||
const util = require("util"); | ||
const execFile = util.promisify(require("child_process").execFile); | ||
|
||
const Promise = require("bluebird"); | ||
const fs = Promise.promisifyAll(require("fs-extra")); | ||
|
||
let loadedFilePath = null; | ||
let images = []; | ||
|
||
const getResourcePath = () => { | ||
if (app.isPackaged) { | ||
return process.resourcesPath; | ||
} else { | ||
return "."; | ||
} | ||
}; | ||
|
||
const getFiles = async (path = "./") => { | ||
const entries = await fs.readdir(path, { withFileTypes: true }); | ||
const files = entries | ||
.filter((file) => !file.isDirectory()) | ||
.map((file) => ({ ...file, path: path + file.name })); | ||
|
||
const folders = entries.filter((folder) => folder.isDirectory()); | ||
for (const folder of folders) { | ||
files.push(...(await getFiles(`${path}/${folder.name}/`))); | ||
} | ||
return files; | ||
}; | ||
|
||
const loadRcc = async (filePath) => { | ||
const localPath = `${path.resolve(getResourcePath(), "rcc")}`; | ||
|
||
// clear previous images | ||
images = []; | ||
|
||
// delete res directory | ||
try { | ||
await fs.rmdir(`${localPath}/qresource`, { recursive: true }); | ||
} catch {} | ||
|
||
await fs.copyFile(filePath, `${localPath}/res.rcc`); | ||
|
||
const result = await execFile(`${localPath}/rcc.exe`, ["--reverse"], { | ||
cwd: `${localPath}/`, | ||
}); | ||
|
||
// get directory content | ||
const files = await getFiles(`${localPath}/qresource/res/res.rcc`); | ||
for (const file of files) { | ||
const ext = path.extname(file.path); | ||
images.push({ | ||
name: path.parse(file.name).name, | ||
path: path.relative(`${localPath}/qresource/res/res.rcc`, file.path), | ||
isImage: ext === ".png" || ext === ".jpg", | ||
data: Buffer.from(await fs.readFile(file.path, "binary"), "binary"), | ||
}); | ||
} | ||
|
||
// sort by name | ||
images.sort((a, b) => a.name.localeCompare(b.name)); | ||
|
||
// cleanup | ||
await fs.rmdir(`${localPath}/qresource`, { recursive: true }); | ||
await fs.rm(`${localPath}/res.rcc`); | ||
|
||
loadedFilePath = filePath; | ||
|
||
BrowserWindow.getAllWindows()[0].webContents.send("populate-list", images); | ||
}; | ||
|
||
const extractToPng = async (directoryPath) => { | ||
if (images.length === 0) { | ||
dialog.showErrorBox("Error", "Nothing to extract."); | ||
return; | ||
} | ||
|
||
for (const image of images) { | ||
if (image.isImage) { | ||
await fs.outputFileAsync(`${directoryPath}/${image.path}`, image.data); | ||
} | ||
} | ||
|
||
dialog.showMessageBox(null, { | ||
message: `Png images extracted successfully. Extracted ${images.length} images.`, | ||
type: "info", | ||
}); | ||
}; | ||
|
||
const saveRcc = async (filePath) => { | ||
if (images.length === 0) { | ||
return; | ||
} | ||
|
||
filePath = filePath || loadedFilePath; | ||
|
||
const localPath = `${path.resolve(getResourcePath(), "rcc")}`; | ||
|
||
// create .qrc file | ||
let data = `<!DOCTYPE RCC><RCC version="1.0">\n<qresource>\n`; | ||
|
||
for (const image of images) { | ||
data += `<file>${image.path}</file>\n`; | ||
} | ||
|
||
data += `</qresource>\n</RCC>`; | ||
|
||
await fs.outputFileAsync(`${localPath}/res/res.qrc`, data); | ||
|
||
// dump images | ||
for (const image of images) { | ||
await fs.outputFileAsync(`${localPath}/res/${image.path}`, image.data); | ||
} | ||
|
||
const result = await execFile( | ||
`${localPath}/rcc.exe`, | ||
[ | ||
"--format-version", | ||
"1", | ||
"--binary", | ||
`./res/res.qrc`, | ||
"-o", | ||
"./res/res_output.rcc", | ||
], | ||
{ | ||
cwd: `${localPath}/`, | ||
} | ||
); | ||
|
||
await fs.move("./rcc/res/res_output.rcc", `${filePath}`, { overwrite: true }); | ||
|
||
// cleanup | ||
await fs.rmdir(`${localPath}/res`, { recursive: true }); | ||
|
||
dialog.showMessageBox(null, { | ||
message: `Rcc saved successfully.`, | ||
type: "info", | ||
}); | ||
}; | ||
|
||
const replaceImage = async (index, filePath) => { | ||
const image = images[index]; | ||
if (!image) { | ||
return null; | ||
} | ||
|
||
image.data = Buffer.from(await fs.readFile(filePath, "binary"), "binary"); | ||
return image.data; | ||
}; | ||
|
||
const getImageByIndex = (index) => { | ||
return images[index]?.data; | ||
}; | ||
|
||
module.exports = { | ||
loadRcc, | ||
saveRcc, | ||
replaceImage, | ||
getImageByIndex, | ||
extractToPng, | ||
}; |
Oops, something went wrong.