Fix 12 medium-severity bugs across all crates
- Escape backslashes in Nautilus preset names preventing Python injection - Fix tiled watermarks starting at (spacing,spacing) instead of (0,0) - Fix text watermark width overestimation (1.0x to 0.6x multiplier) - Fix output_dpi forcing re-encoding for metadata-only presets - Fix AVIF/WebP compression detection comparing against wrong preset values - Add shared batch_updating guard for Ctrl+A/Ctrl+Shift+A select actions - Fix overwrite conflict check ignoring preserve_directory_structure - Add changes_filename()/changes_extension() for smarter overwrite checks - Fix watch folder hardcoding "Blog Photos" preset - Fix undo dropping history for partially-trashed batches - Fix skipped files inflating size statistics - Make CLI watch config writes atomic
This commit is contained in:
@@ -398,7 +398,7 @@ impl PipelineExecutor {
|
||||
|
||||
let output_path = match job.overwrite_behavior {
|
||||
crate::operations::OverwriteAction::Skip if output_path.exists() => {
|
||||
return Ok((input_size, 0, std::path::PathBuf::new()));
|
||||
return Ok((0, 0, std::path::PathBuf::new()));
|
||||
}
|
||||
crate::operations::OverwriteAction::AutoRename if output_path.exists() => {
|
||||
find_unique_path(&output_path)
|
||||
@@ -563,7 +563,7 @@ impl PipelineExecutor {
|
||||
crate::operations::OverwriteAction::Skip => {
|
||||
if output_path.exists() {
|
||||
// Return 0 bytes written - file was skipped
|
||||
return Ok((input_size, 0, std::path::PathBuf::new()));
|
||||
return Ok((0, 0, std::path::PathBuf::new()));
|
||||
}
|
||||
output_path
|
||||
}
|
||||
|
||||
@@ -151,8 +151,8 @@ fn install_nautilus() -> Result<()> {
|
||||
\x20 item.connect('activate', self._on_preset, '{}', files)\n\
|
||||
\x20 submenu.append_item(item)\n\n",
|
||||
name.replace(' ', "_"),
|
||||
name.replace('\'', "\\'"),
|
||||
name.replace('\'', "\\'"),
|
||||
name.replace('\\', "\\\\").replace('\'', "\\'"),
|
||||
name.replace('\\', "\\\\").replace('\'', "\\'"),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,11 @@ impl ConvertConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if this conversion will change at least some file extensions.
|
||||
pub fn changes_extension(&self) -> bool {
|
||||
!matches!(self, Self::KeepOriginal)
|
||||
}
|
||||
}
|
||||
|
||||
// --- Compress ---
|
||||
@@ -318,6 +323,18 @@ pub struct RenameConfig {
|
||||
fn default_counter_position() -> u32 { 3 }
|
||||
|
||||
impl RenameConfig {
|
||||
/// Returns true if this rename config would actually change any filename.
|
||||
pub fn changes_filename(&self) -> bool {
|
||||
!self.prefix.is_empty()
|
||||
|| !self.suffix.is_empty()
|
||||
|| self.counter_enabled
|
||||
|| !self.regex_find.is_empty()
|
||||
|| self.case_mode > 0
|
||||
|| self.replace_spaces > 0
|
||||
|| self.special_chars > 0
|
||||
|| self.template.is_some()
|
||||
}
|
||||
|
||||
/// Pre-compile the regex for batch use. Call once before a loop of apply_simple_compiled.
|
||||
pub fn compile_regex(&self) -> Option<regex::Regex> {
|
||||
rename::compile_rename_regex(&self.regex_find)
|
||||
|
||||
@@ -198,7 +198,7 @@ fn render_text_to_image(
|
||||
opacity: f32,
|
||||
) -> image::RgbaImage {
|
||||
let scale = ab_glyph::PxScale::from(font_size);
|
||||
let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 1.0) as u32).saturating_add(4).min(16384);
|
||||
let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 0.6) as u32).saturating_add(4).min(16384);
|
||||
let text_height = ((font_size.min(1000.0) * 1.4) as u32).saturating_add(4).min(4096);
|
||||
|
||||
let alpha = (opacity * 255.0).clamp(0.0, 255.0) as u8;
|
||||
@@ -296,7 +296,7 @@ fn apply_text_watermark(
|
||||
} else {
|
||||
// No rotation - draw text directly (faster)
|
||||
let scale = ab_glyph::PxScale::from(font_size);
|
||||
let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 1.0) as u32).saturating_add(4).min(16384);
|
||||
let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 0.6) as u32).saturating_add(4).min(16384);
|
||||
let text_height = ((font_size.min(1000.0) * 1.4) as u32).saturating_add(4).min(4096);
|
||||
let text_dims = Dimensions {
|
||||
width: text_width,
|
||||
@@ -351,9 +351,9 @@ fn apply_tiled_text_watermark(
|
||||
let tw = tile.width();
|
||||
let th = tile.height();
|
||||
|
||||
let mut y: i64 = spacing as i64;
|
||||
let mut y: i64 = 0;
|
||||
while y < ih as i64 {
|
||||
let mut x: i64 = spacing as i64;
|
||||
let mut x: i64 = 0;
|
||||
while x < iw as i64 {
|
||||
image::imageops::overlay(&mut rgba, &tile, x, y);
|
||||
x += tw as i64 + spacing as i64;
|
||||
@@ -366,12 +366,12 @@ fn apply_tiled_text_watermark(
|
||||
let alpha = (opacity * 255.0).clamp(0.0, 255.0) as u8;
|
||||
let draw_color = Rgba([color[0], color[1], color[2], alpha]);
|
||||
|
||||
let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 1.0) as i64 + 4).min(16384);
|
||||
let text_width = ((text.chars().count().min(10_000) as f32 * font_size.min(1000.0) * 0.6) as i64 + 4).min(16384);
|
||||
let text_height = ((font_size.min(1000.0) * 1.4) as i64 + 4).min(4096);
|
||||
|
||||
let mut y = spacing as i64;
|
||||
let mut y: i64 = 0;
|
||||
while y < ih as i64 {
|
||||
let mut x = spacing as i64;
|
||||
let mut x: i64 = 0;
|
||||
while x < iw as i64 {
|
||||
draw_text_mut(&mut rgba, draw_color, x as i32, y as i32, scale, &font, text);
|
||||
x += text_width + spacing as i64;
|
||||
@@ -413,9 +413,9 @@ fn apply_tiled_image_watermark(
|
||||
let mut base = img.into_rgba8();
|
||||
let (iw, ih) = (base.width(), base.height());
|
||||
|
||||
let mut ty = spacing;
|
||||
let mut ty = 0u32;
|
||||
while ty < ih {
|
||||
let mut tx = spacing;
|
||||
let mut tx = 0u32;
|
||||
while tx < iw {
|
||||
for oy in 0..oh {
|
||||
for ox in 0..ow {
|
||||
|
||||
@@ -67,7 +67,7 @@ impl Preset {
|
||||
crate::operations::CompressConfig::Preset(p) => p.avif_speed(),
|
||||
_ => 6,
|
||||
}).unwrap_or(6),
|
||||
output_dpi: 72,
|
||||
output_dpi: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user