diff --git a/crates/effects/src/lib.rs b/crates/effects/src/lib.rs index 5045962f4..a2b0f2a02 100644 --- a/crates/effects/src/lib.rs +++ b/crates/effects/src/lib.rs @@ -148,6 +148,7 @@ fn lengths_of(id: &str) -> Lengths { "stylize.innerGlow" | "stylize.outerGlow" => always(&["blur"]), "stylize.glowingEdges" => always(&["edgeWidth", "smoothness"]), "brushStrokes.accentedEdges" => always(&["edgeWidth"]), + "artistic.paletteKnife" => always(&["strokeSize"]), "brushStrokes.angledStrokes" | "brushStrokes.crosshatch" | "brushStrokes.inkOutlines" => always(&["strokeLength"]), "brushStrokes.spatter" => always(&["sprayRadius"]), "brushStrokes.sprayedStrokes" => always(&["strokeLength", "sprayRadius"]), @@ -377,6 +378,13 @@ pub fn effect_catalog() -> Vec { "{glowSize: -24..24 (5; above 0 the light areas glow, below 0 the dark ones; farther from 0 spreads the glow wider), glowBrightness: 0..50 (15; a stronger glow over dimmer greys), color: \"#rrggbb\" (\"#4da6ff\"; the glow's colour)} redraws the object in greys lit by a coloured glow, keeping its coverage. Original visual approximation; chosen VectorCraft defaults.", json!({"glowSize": 5.0, "glowBrightness": 15.0, "color": "#4da6ff"}), ), + r( + "artistic.paletteKnife", + "Palette Knife…", + ARTISTIC, + "{strokeSize: 1..50 (10; length of the knife strokes in document units), strokeDetail: 1..3 (2; more detail keeps more of the original), softness: 0..10 (3; softens the strokes)} smears the object's colours with short angled knife strokes, keeping its coverage. Original visual approximation; chosen VectorCraft defaults.", + json!({"strokeSize": 10.0, "strokeDetail": 2.0, "softness": 3.0}), + ), r( "artistic.plasticWrap", "Plastic Wrap…", diff --git a/crates/effects/src/pixel/artistic.rs b/crates/effects/src/pixel/artistic.rs index edd5b9342..33eb43f5f 100644 --- a/crates/effects/src/pixel/artistic.rs +++ b/crates/effects/src/pixel/artistic.rs @@ -1,11 +1,13 @@ -//! Effect › Artistic (Cutout, Dry Brush, Film Grain, Neon Glow, Plastic Wrap, Poster Edges, Smudge Stick, Sponge and +//! Effect › Artistic (Cutout, Dry Brush, Film Grain, Neon Glow, Palette Knife, Plastic Wrap, Poster Edges, Smudge Stick, Sponge and //! Watercolor). Original filters built from //! public behaviour documentation: //! and //! . //! These are visual approximations, not reproductions of a proprietary algorithm. -use super::brushstrokes::stroke_reach; +use std::f64::consts::TAU; + +use super::brushstrokes::{Smear, mix, stroke_reach, unit, unpremultiply}; use super::edges::sobel; use super::pixelate::{Place, cell, rand, value_noise}; use super::texture::{luma, premultiply, straight}; @@ -472,3 +474,52 @@ pub(super) fn dry_brush(px: &mut [[u8; 4]], w: usize, h: usize, space: &PixelSpa } px.copy_from_slice(&out); } + +const SALT_KNIFE: u64 = 208; + +/// How far Palette Knife reaches with strokes `stroke_size` long and Softness `softness` (0..10). +pub(super) fn palette_knife_reach(stroke_size: f64, softness: f64) -> f64 { + stroke_reach(stroke_size) + 3.0 * 0.35 * softness.clamp(0.0, 10.0) + 1.0 +} + +/// Artistic › Palette Knife: the object repainted with short, angled knife strokes that smear its +/// colours; `stroke_size` (1..50) sets their length, `stroke_detail` (1..3) keeps more of the +/// original where it's higher, and `softness` (0..10) softens the strokes. Coverage is kept. +pub(super) fn palette_knife(px: &mut [[u8; 4]], w: usize, h: usize, space: &PixelSpace, stroke_size: f64, stroke_detail: f64, softness: f64) { + let Some(place) = Place::new(space, w, h) else { return }; + if !(stroke_size.is_finite() && stroke_detail.is_finite() && softness.is_finite()) { + return; + } + let len = stroke_size.clamp(1.0, 50.0); + let keep = ((stroke_detail.clamp(1.0, 3.0) - 1.0) / 2.0) as f32; + let smear = Smear::new(px, w, h, &place, len); + let row = (0.25 * smear.len).max(1.0); + let cell = len * 0.35; + let src = px.to_vec(); + place.each(px, |x, y, p| { + if p[3] == 0 { + return; + } + let q = place.at(x, y); + let angle = TAU * value_noise(SALT_KNIFE, q.x / cell, q.y / cell); + let dir = Vec2::new(angle.cos(), angle.sin()); + let pm = smear.stroke(SALT_KNIFE + 1, q, dir, row); + let orig = unit(src.get(y * w + x).copied().unwrap_or([0; 4])); + let coverage = orig[3]; + let (c, _) = unpremultiply(mix(orig, pm, 1.0 - keep)); + *p = premultiply(c, coverage); + }); + let sigma = 0.35 * softness.clamp(0.0, 10.0) / place.px; + if sigma > 0.0 { + let (mut colour, alpha) = planes(px); + let cover = alpha.clone(); + soften(&mut colour, &alpha, w, h, sigma); + for (k, p) in px.iter_mut().enumerate() { + if cover[k] == 0.0 { + continue; + } + let c = [colour[0][k], colour[1][k], colour[2][k]]; + *p = premultiply(c, cover[k]); + } + } +} diff --git a/crates/effects/src/pixel/mod.rs b/crates/effects/src/pixel/mod.rs index 2e2325173..253abf45b 100644 --- a/crates/effects/src/pixel/mod.rs +++ b/crates/effects/src/pixel/mod.rs @@ -43,11 +43,12 @@ pub use sketch::{HALFTONE_TYPES, HalftonePattern}; pub use texture::{GRAIN_TYPES, Grain, LIGHT_DIRECTIONS, Light, TEXTURES, TEXTURES_LOADED, Texture}; /// The Photoshop-style effect ids (all raster effects, see [`crate::is_raster`]). -pub const PIXEL_EFFECTS: [&str; 48] = [ +pub const PIXEL_EFFECTS: [&str; 49] = [ "artistic.cutout", "artistic.dryBrush", "artistic.filmGrain", "artistic.neonGlow", + "artistic.paletteKnife", "artistic.plasticWrap", "artistic.posterEdges", "artistic.smudgeStick", @@ -122,6 +123,10 @@ pub enum PixelFx { /// light areas (`size` above 0) or the dark ones (below 0), spread by |`size`| (-24..24), as /// strong as `brightness` (0..50). NeonGlow { size: f64, brightness: f64, colour: [f32; 3] }, + /// Artistic › Palette Knife: knife strokes `stroke_size` (1..50) long smear the colours; + /// `stroke_detail` (1..3) keeps more original detail when higher; `softness` (0..10) softens + /// the strokes. + PaletteKnife { stroke_size: f64, stroke_detail: f64, softness: f64 }, /// Artistic › Plastic Wrap: specular highlights as strong as `highlight` (0..20) on a relief /// wrinkled by `detail` (0..15) and softened by `smoothness` (1..15). PlasticWrap { highlight: f64, detail: f64, smoothness: f64 }, @@ -307,6 +312,11 @@ pub(crate) fn parse(id: &str, p: &Value) -> Option { brightness: num(p, "glowBrightness", 15.0).clamp(0.0, 50.0), colour: crate::raster::color_param(p, vectorcraft_doc::color::Color::rgb(0.3, 0.65, 1.0)).to_rgb(), }, + "artistic.paletteKnife" => PixelFx::PaletteKnife { + stroke_size: num(p, "strokeSize", 10.0).clamp(1.0, 50.0), + stroke_detail: num(p, "strokeDetail", 2.0).clamp(1.0, 3.0), + softness: num(p, "softness", 3.0).clamp(0.0, 10.0), + }, "artistic.posterEdges" => PixelFx::PosterEdges { thickness: num(p, "edgeThickness", 2.0).clamp(0.0, 10.0), intensity: num(p, "edgeIntensity", 1.0).clamp(0.0, 10.0), @@ -523,6 +533,7 @@ impl PixelFx { PixelFx::SmartBlur { radius, .. } => radius, PixelFx::AccentedEdges { .. } => 0.0, // Strokes reach out of the object as far as they reach into it. + PixelFx::PaletteKnife { stroke_size, softness, .. } => artistic::palette_knife_reach(stroke_size, softness), PixelFx::AngledStrokes { length, .. } | PixelFx::GraphicPen { length, .. } | PixelFx::InkOutlines { length, .. } => { brushstrokes::stroke_reach(length) } @@ -581,6 +592,7 @@ impl PixelFx { PixelFx::Watercolor { detail, .. } => Some(paint::watercolor_reach(detail)), PixelFx::AccentedEdges { width, smoothness, .. } => Some(brushstrokes::accent_reach(width, smoothness)), // The strokes, and the softened tones that choose them. + PixelFx::PaletteKnife { stroke_size, softness, .. } => Some(artistic::palette_knife_reach(stroke_size, softness)), PixelFx::AngledStrokes { length, .. } | PixelFx::GraphicPen { length, .. } => { Some(brushstrokes::stroke_reach(length).max(brushstrokes::TONE_REACH)) } @@ -651,6 +663,9 @@ impl PixelFx { PixelFx::Watercolor { detail, shadow, texture } => paint::watercolor(px, w, h, space, detail, shadow, texture), PixelFx::PlasticWrap { highlight, detail, smoothness } => artistic::plastic_wrap(px, w, h, space, highlight, detail, smoothness), PixelFx::NeonGlow { size, brightness, colour } => artistic::neon_glow(px, w, h, space, size, brightness, colour), + PixelFx::PaletteKnife { stroke_size, stroke_detail, softness } => { + artistic::palette_knife(px, w, h, space, stroke_size, stroke_detail, softness) + } PixelFx::PosterEdges { thickness, intensity, posterization } => { artistic::poster_edges(px, w, h, space, thickness, intensity, posterization) } diff --git a/crates/effects/src/pixel/tests.rs b/crates/effects/src/pixel/tests.rs index 28f07e380..09a8d811c 100644 --- a/crates/effects/src/pixel/tests.rs +++ b/crates/effects/src/pixel/tests.rs @@ -2647,3 +2647,30 @@ fn artistic_filters_look_the_same_at_any_resolution() { assert!(diff < 12.0, "{id}: mean difference {diff}"); } } + +#[test] +fn palette_knife_params_take_defaults_and_stay_in_range() { + assert_eq!(fx("artistic.paletteKnife", json!({})), PixelFx::PaletteKnife { stroke_size: 10.0, stroke_detail: 2.0, softness: 3.0 }); + assert_eq!( + fx("artistic.paletteKnife", json!({"strokeSize": 0, "strokeDetail": 0, "softness": 99})), + PixelFx::PaletteKnife { stroke_size: 1.0, stroke_detail: 1.0, softness: 10.0 } + ); + assert!(fx("artistic.paletteKnife", json!({})).outset(Rect::new(0.0, 0.0, 40.0, 30.0)) > 0.0); +} + +#[test] +fn palette_knife_smears_a_ramp_and_keeps_coverage() { + let (w, h) = (48, 24); + let src = ramp(w, h); + let mut out = src.clone(); + fx("artistic.paletteKnife", json!({"strokeSize": 20, "strokeDetail": 1, "softness": 0})).apply(&mut out, w, h, &space(w, h)); + assert_ne!(out, src); + assert!(out.as_chunks::<4>().0.iter().zip(src.as_chunks::<4>().0).all(|(o, s)| o[3] == s[3])); + let mut gentle = src.clone(); + fx("artistic.paletteKnife", json!({"strokeSize": 20, "strokeDetail": 3, "softness": 0})).apply(&mut gentle, w, h, &space(w, h)); + let mean = |buf: &Vec| { + let n = buf.len() / 4; + buf.as_chunks::<4>().0.iter().map(|p| f64::from(p[0])).sum::() / n as f64 + }; + assert!((mean(&gentle) - mean(&src)).abs() < (mean(&out) - mean(&src)).abs()); +} diff --git a/crates/engine/src/tests_rasterfilters.rs b/crates/engine/src/tests_rasterfilters.rs index e46b5eef6..e5b17f02a 100644 --- a/crates/engine/src/tests_rasterfilters.rs +++ b/crates/engine/src/tests_rasterfilters.rs @@ -31,11 +31,12 @@ const BRUSH_STROKES: [(&str, &str); 8] = [ ]; /// Effect › Artistic, at their defaults. -const ARTISTIC: [(&str, &str); 9] = [ +const ARTISTIC: [(&str, &str); 10] = [ ("artistic.cutout", "{}"), ("artistic.dryBrush", "{}"), ("artistic.filmGrain", "{}"), ("artistic.neonGlow", "{}"), + ("artistic.paletteKnife", "{}"), ("artistic.plasticWrap", "{}"), ("artistic.posterEdges", "{}"), ("artistic.smudgeStick", "{}"), diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index c817a8707..b59d8399f 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -4555,7 +4555,9 @@ lighting Light Светлина Dry Brush… Суха четка… Dry Brush Суха четка Neon Glow… Неоново сияние… + Palette Knife… Нож за палитра… Neon Glow Неоново сияние + Palette Knife Нож за палитра Poster Edges… Плакатни ръбове… Poster Edges Плакатни ръбове Levels Нива diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 61bb3dc96..4d425327f 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -5054,7 +5054,9 @@ imageTrace Outline Obrys Dry Brush… Suchý štětec… Dry Brush Suchý štětec Neon Glow… Neonová záře… + Palette Knife… Špachtle… Neon Glow Neonová záře + Palette Knife Špachtle Poster Edges… Plakátové okraje… Poster Edges Plakátové okraje Levels Úrovně diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index faffd623a..a2a9517ed 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -5178,10 +5178,12 @@ swatch Bright Violet Kraftig violet Cutout… Udklip… Dry Brush… Tør pensel… Neon Glow… Neonglød… + Palette Knife… Paletkniv… Poster Edges… Plakatkanter… Cutout Udklip Dry Brush Tør pensel Neon Glow Neonglød + Palette Knife Paletkniv Poster Edges Plakatkanter Apply Data Set Anvend datasæt Cancel Pattern Editing Annullér redigering af mønster diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index 7175e78c5..e174368fd 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4642,7 +4642,9 @@ lighting Light Licht Dry Brush… Trockenpinsel… Dry Brush Trockenpinsel Neon Glow… Neonglühen… + Palette Knife… Palettenmesser… Neon Glow Neonglühen + Palette Knife Palettenmesser Poster Edges… Posterkanten… Poster Edges Posterkanten Levels Stufen diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 37a50d8bd..8d844f800 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -2264,7 +2264,9 @@ lighting Light Φως Dry Brush… Ξηρό πινέλο… Dry Brush Ξηρό πινέλο Neon Glow… Λάμψη νέον… + Palette Knife… Μαχαίρι παλέτας… Neon Glow Λάμψη νέον + Palette Knife Μαχαίρι παλέτας Poster Edges… Άκρες αφίσας… Poster Edges Άκρες αφίσας Levels Επίπεδα diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index d746a00ed..f98165673 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -4642,7 +4642,9 @@ lighting Light Luz Dry Brush… Pincel seco… Dry Brush Pincel seco Neon Glow… Resplandor de neón… + Palette Knife… Espátula… Neon Glow Resplandor de neón + Palette Knife Espátula Poster Edges… Bordes de póster… Poster Edges Bordes de póster Levels Niveles diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index be6a0d47e..8e5e631bd 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -4949,7 +4949,9 @@ imageTrace Outline Ääriviiva Dry Brush… Kuiva sivellin… Dry Brush Kuiva sivellin Neon Glow… Neonhehku… + Palette Knife… Palettiveitsi… Neon Glow Neonhehku + Palette Knife Palettiveitsi Poster Edges… Julisteen reunat… Poster Edges Julisteen reunat Levels Tasot diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 3206cb52f..80a96e071 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -4652,7 +4652,9 @@ lighting Light Lumière Dry Brush… Pinceau sec… Dry Brush Pinceau sec Neon Glow… Néon… + Palette Knife… Couteau à palette… Neon Glow Néon + Palette Knife Couteau à palette Poster Edges… Bords d’affiche… Poster Edges Bords d’affiche Levels Niveaux diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 9b34c44ec..9f101d129 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -1585,7 +1585,9 @@ file-filter Templates Sablonok Dry Brush… Száraz ecset… Dry Brush Száraz ecset Neon Glow… Neonfény… + Palette Knife… Palettakés… Neon Glow Neonfény + Palette Knife Palettakés Poster Edges… Poszterszélek… Poster Edges Poszterszélek Levels Szintek diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index e5bf05582..769a989a6 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -5178,10 +5178,12 @@ swatch Bright Violet Violet cerah Cutout… Potongan… Dry Brush… Kuas kering… Neon Glow… Pendar neon… + Palette Knife… Pisau palet… Poster Edges… Tepi poster… Cutout Potongan Dry Brush Kuas kering Neon Glow Pendar neon + Palette Knife Pisau palet Poster Edges Tepi poster Apply Data Set Terapkan set data Cancel Pattern Editing Batalkan pengeditan pola diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 264c9a961..223e9ebf1 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4684,7 +4684,9 @@ lighting Light Luce Dry Brush… Pennello secco… Dry Brush Pennello secco Neon Glow… Bagliore neon… + Palette Knife… Spatola… Neon Glow Bagliore neon + Palette Knife Spatola Poster Edges… Bordi poster… Poster Edges Bordi poster Levels Livelli diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index f52179340..27418db9e 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4723,7 +4723,9 @@ lighting Light ライト Dry Brush… ドライブラシ… Dry Brush ドライブラシ Neon Glow… ネオングロー… + Palette Knife… パレットナイフ… Neon Glow ネオングロー + Palette Knife パレットナイフ Poster Edges… ポスターエッジ… Poster Edges ポスターエッジ Levels レベル数 diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 7c4fa5668..b1ad1d76c 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -5077,7 +5077,9 @@ imageTrace Outline კონტური Move Slice ნაჭრის გადაადგილება Move Type on a Path ტრაექტორიაზე ტექსტის გადაადგილება Neon Glow ნეონის ნათება + Palette Knife პალეტის დანა Neon Glow… ნეონის ნათება… + Palette Knife… პალეტის დანა… New Artboard Options… ახალი სამუშაო დაფის პარამეტრები… New Guide ახალი დამხმარე ხაზი Next Artboard შემდეგი სამუშაო დაფა diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index a58ee3a03..51cde1959 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4647,7 +4647,9 @@ lighting Light 광원 Dry Brush… 드라이 브러시… Dry Brush 드라이 브러시 Neon Glow… 네온 글로… + Palette Knife… 팔레트 나이프… Neon Glow 네온 글로 + Palette Knife 팔레트 나이프 Poster Edges… 포스터 가장자리… Poster Edges 포스터 가장자리 Levels 레벨 수 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 5cb96f8c6..8c334db44 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -5189,10 +5189,12 @@ swatch Bright Violet Felviolet Cutout… Knipsel… Dry Brush… Droog penseel… Neon Glow… Neongloed… + Palette Knife… Paletmes… Poster Edges… Posterranden… Cutout Knipsel Dry Brush Droog penseel Neon Glow Neongloed + Palette Knife Paletmes Poster Edges Posterranden Apply Data Set Gegevensset toepassen Cancel Pattern Editing Patroon bewerken annuleren diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 8a755a6d0..3706f95d0 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -4887,7 +4887,9 @@ imageTrace Outline Kontur Dry Brush… Suchy pędzel… Dry Brush Suchy pędzel Neon Glow… Neonowa poświata… + Palette Knife… Szpachel… Neon Glow Neonowa poświata + Palette Knife Szpachel Poster Edges… Krawędzie plakatu… Poster Edges Krawędzie plakatu Levels Poziomy diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 80ed66f89..442547160 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -4044,7 +4044,9 @@ axis Both Ambos Dry Brush… Pincel seco… Dry Brush Pincel seco Neon Glow… Brilho neon… + Palette Knife… Espátula… Neon Glow Brilho neon + Palette Knife Espátula Poster Edges… Bordas de pôster… Poster Edges Bordas de pôster Levels Níveis diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 2cdbdc41a..34b8835b2 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4680,7 +4680,9 @@ lighting Light Свет Dry Brush… Сухая кисть… Dry Brush Сухая кисть Neon Glow… Неоновое свечение… + Palette Knife… Нож для палитры… Neon Glow Неоновое свечение + Palette Knife Нож для палитры Poster Edges… Края плаката… Poster Edges Края плаката Levels Уровни diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index d396e82be..eb1f68f4b 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -4561,7 +4561,9 @@ lighting Light Ljus Dry Brush… Torr pensel… Dry Brush Torr pensel Neon Glow… Neonsken… + Palette Knife… Palettkniv… Neon Glow Neonsken + Palette Knife Palettkniv Poster Edges… Affischkanter… Poster Edges Affischkanter Levels Nivåer diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index d70d2ad9f..114a75ad8 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4664,7 +4664,9 @@ lighting Light Світло Dry Brush… Суха кисть… Dry Brush Суха кисть Neon Glow… Неонове сяйво… + Palette Knife… Ніж палітри… Neon Glow Неонове сяйво + Palette Knife Ніж палітри Poster Edges… Плакатні краї… Poster Edges Плакатні краї Levels Рівні diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 464b0d377..8407ddc08 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -1273,7 +1273,9 @@ Dry Brush… Cọ khô… Dry Brush Cọ khô Neon Glow… Ánh neon… + Palette Knife… Dao palette… Neon Glow Ánh neon + Palette Knife Dao palette Poster Edges… Viền áp phích… Poster Edges Viền áp phích Levels Số mức diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 08ac98c29..d5e999fd8 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -4948,7 +4948,9 @@ lighting Light 光源 Cutout 剪纸 Dry Brush 干画笔 Neon Glow… 霓虹灯光… + Palette Knife… 调色刀… Neon Glow 霓虹灯光 + Palette Knife 调色刀 Poster Edges… 海报边缘… Poster Edges 海报边缘 Levels 色阶数 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 3917676c6..2eeeb9017 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -4754,7 +4754,9 @@ lighting Light 光源 Cutout 剪紙 Dry Brush 乾畫筆 Neon Glow… 霓虹光… + Palette Knife… 調色刀… Neon Glow 霓虹光 + Palette Knife 調色刀 Poster Edges… 海報邊緣… Poster Edges 海報邊緣 Levels 色階數 diff --git a/crates/ui-egui/src/tests_labels.rs b/crates/ui-egui/src/tests_labels.rs index 1a2c3dc2c..e264be563 100644 --- a/crates/ui-egui/src/tests_labels.rs +++ b/crates/ui-egui/src/tests_labels.rs @@ -88,7 +88,18 @@ fn effect_menu_lists_the_artistic_filters_before_blur() { let labels: Vec<&str> = artistic.iter().map(|e| e.label.as_str()).collect(); assert_eq!( labels, - ["Cutout…", "Dry Brush…", "Film Grain…", "Neon Glow…", "Plastic Wrap…", "Poster Edges…", "Smudge Stick…", "Sponge…", "Watercolor…"] + [ + "Cutout…", + "Dry Brush…", + "Film Grain…", + "Neon Glow…", + "Palette Knife…", + "Plastic Wrap…", + "Poster Edges…", + "Smudge Stick…", + "Sponge…", + "Watercolor…" + ] ); assert!(artistic.iter().all(|e| e.command.as_deref() == Some("effect.dialog"))); assert_eq!(artistic[1].params, json!({"effect": "artistic.dryBrush"}));