Skip to content

Commit

Permalink
feat: 给水印目录添加漫画名,以区分不同的漫画
Browse files Browse the repository at this point in the history
  • Loading branch information
lanyeeee committed Jul 27, 2024
1 parent b07b078 commit f032868
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 59 deletions.
42 changes: 36 additions & 6 deletions src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::errors::CommandResult;
use crate::types::{CommandResponse, JpgImageData, JpgImageInfo, MangaDirData, RectData};
use crate::watermark;
use crate::{utils, watermark};
use anyhow::Context;
use base64::engine::general_purpose;
use base64::Engine;
use path_slash::PathBufExt;
use std::collections::HashMap;
use std::path::PathBuf;
use tauri::{AppHandle, Manager};
use tauri::AppHandle;
use walkdir::WalkDir;

#[tauri::command(async)]
Expand All @@ -23,8 +23,7 @@ pub fn generate_background(
width: u32,
height: u32,
) -> CommandResult<CommandResponse<()>> {
let resource_dir = app.path().resource_dir().map_err(anyhow::Error::from)?;
let output_dir = resource_dir.join(format!("背景水印图/{width}x{height}"));
let output_dir = utils::get_background_dir_abs_path(&app, manga_dir, width, height)?;
let default_rect_data = RectData {
left: (width as f32 * 0.835) as u32,
top: (height as f32 * 0.946) as u32,
Expand Down Expand Up @@ -120,11 +119,10 @@ pub fn get_manga_dir_data(
// 以count降序排序
manga_dir_data.sort_by(|a, b| b.count.cmp(&a.count));
// 获取背景水印图的数据
let resource_dir = app.path().resource_dir().map_err(anyhow::Error::from)?;
for dir_data in &mut manga_dir_data {
let width = dir_data.width;
let height = dir_data.height;
let background_dir = resource_dir.join(format!("背景水印图/{width}x{height}"));
let background_dir = utils::get_background_dir_abs_path(&app, manga_dir, width, height)?;
let black_background_path = background_dir.join("black.png");
let white_background_path = background_dir.join("white.png");
if black_background_path.exists() {
Expand Down Expand Up @@ -185,3 +183,35 @@ pub fn show_path_in_file_manager(path: &str) {
let path = PathBuf::from_slash(path);
showfile::show_path_in_file_manager(path);
}

#[tauri::command(async)]
#[specta::specta]
pub fn get_background_dir_relative_path(
manga_dir: &str,
width: u32,
height: u32,
) -> CommandResult<CommandResponse<PathBuf>> {
let relative_path = utils::get_background_dir_relative_path(manga_dir, width, height)?;
Ok(CommandResponse {
code: 0,
msg: String::new(),
data: relative_path,
})
}

#[tauri::command(async)]
#[specta::specta]
#[allow(clippy::needless_pass_by_value)]
pub fn get_background_dir_abs_path(
app: AppHandle,
manga_dir: &str,
width: u32,
height: u32,
) -> CommandResult<CommandResponse<PathBuf>> {
let abs_path = utils::get_background_dir_abs_path(&app, manga_dir, width, height)?;
Ok(CommandResponse {
code: 0,
msg: String::new(),
data: abs_path,
})
}
6 changes: 5 additions & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#![warn(clippy::unwrap_used)]

use crate::commands::{
generate_background, get_jpg_image_infos, get_manga_dir_data, open_image, remove_watermark,
generate_background, get_background_dir_abs_path, get_background_dir_relative_path,
get_jpg_image_infos, get_manga_dir_data, open_image, remove_watermark,
show_path_in_file_manager,
};
use crate::events::{
Expand All @@ -17,6 +18,7 @@ mod errors;
mod events;
mod extensions;
mod types;
mod utils;
mod watermark;

#[allow(clippy::unwrap_used)]
Expand All @@ -30,6 +32,8 @@ fn main() {
get_manga_dir_data,
get_jpg_image_infos,
show_path_in_file_manager,
get_background_dir_relative_path,
get_background_dir_abs_path,
])
.events(tauri_specta::collect_events![
RemoveWatermarkStartEvent,
Expand Down
28 changes: 28 additions & 0 deletions src-tauri/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use std::path::{Path, PathBuf};
use tauri::{AppHandle, Manager};

pub fn get_background_dir_relative_path(
manga_dir: &str,
width: u32,
height: u32,
) -> anyhow::Result<PathBuf> {
let manga_dir_name = Path::new(manga_dir)
.file_name()
.ok_or(anyhow::anyhow!("获取漫画目录名失败"))?
.to_str()
.ok_or(anyhow::anyhow!("漫画目录名包含非UTF-8字符"))?;
let relative_path = format!("背景水印图/{manga_dir_name}{width}x{height}");
Ok(PathBuf::from(relative_path))
}

pub fn get_background_dir_abs_path(
app: &AppHandle,
manga_dir: &str,
width: u32,
height: u32,
) -> anyhow::Result<PathBuf> {
let resource_dir = app.path().resource_dir()?;
let relative_path = get_background_dir_relative_path(manga_dir, width, height)?;
let abs_path = resource_dir.join(relative_path);
Ok(abs_path)
}
7 changes: 4 additions & 3 deletions src-tauri/src/watermark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ pub fn generate_background(
width: u32,
height: u32,
) -> anyhow::Result<CommandResponse<()>> {
// 保证输出目录存在
std::fs::create_dir_all(output_dir)
.context(format!("创建目录 {} 失败", output_dir.display()))?;
// 收集尺寸符合width和height的图片的路径
let image_paths = create_image_paths(manga_dir, width, height);
// 用于记录是否找到了黑色背景和白色背景的水印图片
let black_status: Mutex<Option<()>> = Mutex::new(None);
Expand Down Expand Up @@ -52,8 +56,6 @@ pub fn generate_background(
*pixel = color;
}
}
std::fs::create_dir_all(output_dir)
.context(format!("创建目录 {} 失败", output_dir.display()))?;
let filename = if is_black { "black.png" } else { "white.png" };
let output_path = output_dir.join(filename);
// 保存黑色背景或白色背景的水印图片
Expand Down Expand Up @@ -324,7 +326,6 @@ fn is_black_background(img: &RgbImage, rect_data: &RectData) -> Option<bool> {
#[allow(clippy::cast_lossless)]
#[allow(clippy::cast_sign_loss)]
fn remove_image_watermark(black: &RgbImage, white: &RgbImage, img: &mut RgbImage) {
// TODO: 处理图片大小不一致的情况
if img.width() != white.width() || img.height() != white.height() {
return;
}
Expand Down
91 changes: 52 additions & 39 deletions src/AppContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import WatermarkCropper from "./components/WatermarkCropper.vue";
import {path} from "@tauri-apps/api";
import {BaseDirectory, exists} from "@tauri-apps/plugin-fs";
import RemoveProgress from "./components/RemoveProgress.vue";
import {showPathInFileManager} from "./utils.ts";
import {
autoGenerateBackground,
getBackgroundDirAbsPath,
getBackgroundDirRelativePath,
showPathInFileManager
} from "./utils.ts";
import MangaDirIndicator from "./components/MangaDirIndicator.vue";
const notification = useNotification();
Expand Down Expand Up @@ -47,7 +52,6 @@ onMounted(async () => {
});
outputDir.value = await path.resourceDir();
await loadBackground();
});
async function removeWatermark() {
Expand Down Expand Up @@ -80,6 +84,28 @@ async function removeWatermark() {
message.success("去水印成功");
}
async function autoGenerateAll() {
if (mangaDir.value === undefined) {
message.error("请选择漫画目录");
return;
}
const generatingMessage = message.loading("尝试自动生成背景水印图", {duration: 0});
for (const mangaDirData of mangaDirDataList.value) {
if (mangaDirData.blackBackground !== null && mangaDirData.whiteBackground !== null) {
message.info(`尺寸(${mangaDirData.width}x${mangaDirData.height})的背景水印图已存在,跳过自动生成`);
continue;
}
const success = await autoGenerateBackground(mangaDir.value, mangaDirData.width, mangaDirData.height, notification);
if (!success) {
continue;
}
message.success(`自动生成背景水印图(${mangaDirData.width}x${mangaDirData.height})成功`);
}
// 使用 nextTick 保证生成消息能够被销毁
await nextTick(generatingMessage.destroy);
await loadBackground();
}
async function selectMangaDir() {
const selectedDirPath = await open({directory: true});
if (selectedDirPath === null) {
Expand All @@ -97,35 +123,7 @@ async function selectMangaDir() {
}
mangaDirDataList.value = response.data;
mangaDir.value = selectedDirPath;
const generatingMessage = message.loading("尝试自动生成背景水印图", {duration: 0});
for (const mangaDirData of mangaDirDataList.value) {
if (mangaDirData.blackBackground !== null && mangaDirData.whiteBackground !== null) {
message.info(`尺寸(${mangaDirData.width}x${mangaDirData.height})的背景水印图已存在,跳过自动生成`);
continue;
}
const generateResult = await commands.generateBackground(mangaDir.value, null, mangaDirData.width, mangaDirData.height);
if (generateResult.status === "error") {
notification.error({
title: `自动生成背景水印图(${mangaDirData.width}x${mangaDirData.height})失败`,
description: generateResult.error
});
continue;
}
const response = generateResult.data;
if (response.code !== 0) {
notification.warning({
title: `自动生成背景水印图(${mangaDirData.width}x${mangaDirData.height})失败`,
description: response.msg,
content: "请尝试手动截取水印",
});
continue;
}
message.success(`自动生成背景水印图(${mangaDirData.width}x${mangaDirData.height})成功`);
}
// 使用 nextTick 保证生成消息能够被销毁
await nextTick(generatingMessage.destroy);
await loadBackground();
await autoGenerateAll();
}
async function selectOutputDir() {
Expand All @@ -140,15 +138,27 @@ async function loadBackground() {
const tasks: Promise<void>[] = [];
for (const mangaDirData of mangaDirDataList.value) {
const load = async (isBlack: boolean) => {
if (mangaDir.value === undefined) {
return;
}
const filename = isBlack ? "black.png" : "white.png";
const backgroundRelativePath = await path.join(`背景水印图/${mangaDirData.width}x${mangaDirData.height}`, filename);
// 检查背景水印图是否存在
const backgroundDirRelativePath = await getBackgroundDirRelativePath(mangaDir.value, mangaDirData.width, mangaDirData.height, notification);
if (backgroundDirRelativePath === null) {
return;
}
const backgroundRelativePath = await path.join(backgroundDirRelativePath, filename);
const backgroundExist = await exists(backgroundRelativePath, {baseDir: BaseDirectory.Resource});
if (!backgroundExist) {
return;
}
const resourceDir = await path.resourceDir();
const backgroundPath = await path.join(resourceDir, backgroundRelativePath);
const result = await commands.openImage(backgroundPath);
// 加载背景水印图
const backgroundDirAbsPath = await getBackgroundDirAbsPath(mangaDir.value, mangaDirData.width, mangaDirData.height, notification);
if (backgroundDirAbsPath === null) {
return;
}
const backgroundAbsPath = await path.join(backgroundDirAbsPath, filename);
const result = await commands.openImage(backgroundAbsPath);
if (result.status === "error") {
notification.error({title: "打开背景水印图失败", description: result.error});
return;
Expand All @@ -172,7 +182,7 @@ async function loadBackground() {
}
async function test() {
console.log(mangaDirDataList.value);
console.log("hello");
}
</script>
Expand Down Expand Up @@ -203,11 +213,13 @@ async function test() {
<n-button :disabled="!outputDirExist" @click="showPathInFileManager(outputDir)">打开目录</n-button>
</div>

<manga-dir-indicator :load-background="loadBackground"
:manga-dir-data-list="mangaDirDataList"
:output-dir-exist="outputDirExist"
<manga-dir-indicator :manga-dir="mangaDir"
:manga-dir-exist="mangaDirExist"
:output-dir-exist="outputDirExist"
:images-exist="imagesExist"
:manga-dir-data-list="mangaDirDataList"
:load-background="loadBackground"
:auto-generate-all="autoGenerateAll"
v-model:cropper-showing="cropperShowing"
v-model:cropper-width="cropperWidth"
v-model:cropper-height="cropperHeight"/>
Expand All @@ -217,6 +229,7 @@ async function test() {
@click="removeWatermark">
开始去水印
</n-button>

<n-button @click="test">测试用</n-button>

<RemoveProgress :remove-watermark-tasks="removeWatermarkTasks"/>
Expand Down
16 changes: 16 additions & 0 deletions src/bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,22 @@ return await TAURI_INVOKE("get_jpg_image_infos", { mangaDir });
},
async showPathInFileManager(path: string) : Promise<void> {
await TAURI_INVOKE("show_path_in_file_manager", { path });
},
async getBackgroundDirRelativePath(mangaDir: string, width: number, height: number) : Promise<Result<CommandResponse<string>, CommandError>> {
try {
return { status: "ok", data: await TAURI_INVOKE("get_background_dir_relative_path", { mangaDir, width, height }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async getBackgroundDirAbsPath(mangaDir: string, width: number, height: number) : Promise<Result<CommandResponse<string>, CommandError>> {
try {
return { status: "ok", data: await TAURI_INVOKE("get_background_dir_abs_path", { mangaDir, width, height }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
}
}

Expand Down
Loading

0 comments on commit f032868

Please # to comment.