some improvements

This commit is contained in:
Shautvast 2026-04-01 19:21:21 +02:00
parent 149bacbcc0
commit ae74e5d211
5 changed files with 96 additions and 18 deletions

2
.gitignore vendored
View file

@ -4,4 +4,4 @@ pkg/
.DS_Store .DS_Store
dist/ dist/
*.iml *.iml
.idea .idea/

View file

@ -1,6 +1,6 @@
use image::imageops::FilterType;
use image::{GenericImage, GenericImageView, Pixel, Rgba, RgbaImage}; use image::{GenericImage, GenericImageView, Pixel, Rgba, RgbaImage};
use photon_rs::PhotonImage; use photon_rs::PhotonImage;
use image::imageops::FilterType;
mod samples; mod samples;
@ -19,9 +19,19 @@ pub fn spiegel(photon_image: PhotonImage, median_kernelsize: u32, preview: bool)
let i1 = RgbaImage::from_vec(width, height, raw_pixels).unwrap(); let i1 = RgbaImage::from_vec(width, height, raw_pixels).unwrap();
let i2 = if preview { let i2 = if preview {
image::imageops::resize(&i1, u32::min(500, width >> 1), u32::min(500, height >> 1), FilterType::Nearest) image::imageops::resize(
&i1,
u32::min(500, width >> 1),
u32::min(500, height >> 1),
FilterType::Nearest,
)
} else { } else {
image::imageops::resize(&i1, u32::min(500, width), u32::min(500, height), FilterType::Nearest) image::imageops::resize(
&i1,
u32::min(500, width),
u32::min(500, height),
FilterType::Nearest,
)
}; };
let mut i3 = imageproc::filter::median_filter(&i2, median_kernelsize, median_kernelsize); let mut i3 = imageproc::filter::median_filter(&i2, median_kernelsize, median_kernelsize);
let i4 = if !preview { let i4 = if !preview {
@ -80,16 +90,16 @@ fn fill(
let yy = y % height; let yy = y % height;
dest.unsafe_put_pixel(x, y, sample.unsafe_get_pixel(xx, yy)); dest.unsafe_put_pixel(x, y, sample.unsafe_get_pixel(xx, yy));
src.unsafe_put_pixel(x, y, BLACK); src.unsafe_put_pixel(x, y, BLACK);
if x > 1 { if x > 1 && src.unsafe_get_pixel(x - 1, y) != BLACK {
points.push(Coord(x - 1, y)); points.push(Coord(x - 1, y));
} }
if y > 1 { if y > 1 && src.unsafe_get_pixel(x, y - 1) != BLACK {
points.push(Coord(x, y - 1)); points.push(Coord(x, y - 1));
} }
if x < src.width() - 1 { if x < src.width() - 1 && src.unsafe_get_pixel(x + 1, y) != BLACK {
points.push(Coord(x + 1, y)); points.push(Coord(x + 1, y));
} }
if y < src.height() - 1 { if y < src.height() - 1 && src.unsafe_get_pixel(x, y + 1) != BLACK {
points.push(Coord(x, y + 1)); points.push(Coord(x, y + 1));
} }
} }

View file

@ -27,6 +27,7 @@
<div id="slidecontainer" class="hide"> <div id="slidecontainer" class="hide">
<label for="slider">Brush stroke size</label><input type="range" id="slider" value="0" min="0" max="100" class="slider"/> <label for="slider">Brush stroke size</label><input type="range" id="slider" value="0" min="0" max="100" class="slider"/>
<button id="apply">Apply</button> <button id="apply">Apply</button>
<button id="reset" onclick="location.reload()">Reset</button>
</div> </div>
</label> </label>
<div class="main-content"> <div class="main-content">
@ -36,6 +37,12 @@
<canvas id="canvas" style="visibility: hidden;"></canvas> <canvas id="canvas" style="visibility: hidden;"></canvas>
</div> </div>
</div> </div>
<div id="clock-overlay">
<div class="clock">
<div class="hand hour-hand"></div>
<div class="hand minute-hand"></div>
</div>
</div>
</div> </div>
<script> <script>
function allowDrop(event) { function allowDrop(event) {

View file

@ -69,6 +69,59 @@ li:hover {
cursor: pointer; cursor: pointer;
} }
#clock-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.6);
display: none;
align-items: center;
justify-content: center;
z-index: 100;
}
#clock-overlay.visible {
display: flex;
}
.clock {
width: 80px;
height: 80px;
border: 6px solid #555;
border-radius: 50%;
position: relative;
}
.hand {
position: absolute;
bottom: 50%;
left: 50%;
transform-origin: bottom center;
border-radius: 4px;
background: #333;
}
.hour-hand {
width: 5px;
height: 22px;
margin-left: -2.5px;
animation: rotate 6s linear infinite;
}
.minute-hand {
width: 3px;
height: 30px;
margin-left: -1.5px;
animation: rotate 1s linear infinite;
}
@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.slidecontainer { .slidecontainer {
align-items: center; align-items: center;
display: flex; display: flex;

View file

@ -10,11 +10,14 @@ let canvas,
import("../../image-processor/pkg").then((module) => { import("../../image-processor/pkg").then((module) => {
const slider = document.querySelector("#slider"); const slider = document.querySelector("#slider");
let debounceTimer; let debounceTimer = null;
slider.oninput = (event) => { slider.oninput = (event) => {
strokeSize = parseInt(event.target.value) / 5; strokeSize = parseInt(event.target.value) / 5;
clearTimeout(debounceTimer); clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => filterImage(event, true), 200); debounceTimer = setTimeout(() => {
debounceTimer = null;
filterImage(event, true);
}, 500);
}; };
slider.value = 0; slider.value = 0;
const applyButton = document.querySelector("#apply"); const applyButton = document.querySelector("#apply");
@ -24,16 +27,21 @@ import("../../image-processor/pkg").then((module) => {
}; };
function filterImage(event, preview) { function filterImage(event, preview) {
ctx.drawImage(sourceImage, 0, 0); const overlay = document.querySelector("#clock-overlay");
overlay.setAttribute("class", "visible");
setTimeout(() => {
ctx.drawImage(sourceImage, 0, 0);
let rust_image = module.open_image(canvas, ctx); let rust_image = module.open_image(canvas, ctx);
const out = module.spiegel(rust_image, strokeSize, preview); const out = module.spiegel(rust_image, strokeSize, preview);
module.putImageData(canvas, ctx, out); module.putImageData(canvas, ctx, out);
canvas.setAttribute( canvas.setAttribute(
"style", "style",
`visibility:visible;position:absolute;top:${canvasTop}px`, `visibility:visible;position:absolute;top:${canvasTop}px`,
); );
overlay.setAttribute("class", "");
}, 50);
} }
}); });
document.querySelector("#spieghel").src = spiegel; document.querySelector("#spieghel").src = spiegel;