mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-11 06:01:23 +00:00
address review: shrink a one-pixel-over vector thumbnail to the requested size
This commit is contained in:
@@ -101,14 +101,17 @@ impl Session {
|
||||
let scale = (max_side.max(1) as f64 / f.width.max(f.height).max(1) as f64).min(1.0);
|
||||
let src = footage.vector_frame(item, &f, scale).or_else(|| footage.frame(item, &f, Tick(0)))?;
|
||||
let img = effectcraft_render::cineon_frame(src, &f);
|
||||
// Point-sample down to at most `max_side` on the long side.
|
||||
let step = (img.width.max(img.height) as f32 / max_side.max(1) as f32).ceil().max(1.0) as u32;
|
||||
let (w, h) = (img.width.div_ceil(step), img.height.div_ceil(step));
|
||||
// Point-sample down to at most `max_side` on the long side (a drawn size one
|
||||
// pixel over it, from rounding, is shrunk by that pixel, not halved).
|
||||
let (long, max) = (u64::from(img.width.max(img.height)), u64::from(max_side.max(1)));
|
||||
let fit = |side: u32| if long <= max { side } else { ((u64::from(side) * max + long / 2) / long).max(1) as u32 };
|
||||
let (w, h) = (fit(img.width), fit(img.height));
|
||||
let full = img.to_rgba8();
|
||||
let mut px = Vec::with_capacity((w * h * 4) as usize);
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let i = (((y * step) * img.width + x * step) * 4) as usize;
|
||||
let (sx, sy) = (u64::from(x) * u64::from(img.width) / u64::from(w), u64::from(y) * u64::from(img.height) / u64::from(h));
|
||||
let i = ((sy * u64::from(img.width) + sx) * 4) as usize;
|
||||
px.extend_from_slice(&full[i..i + 4]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,3 +411,30 @@ fn vector_footage_thumbnails_are_drawn_at_thumbnail_size() {
|
||||
assert_eq!((w, h), (64, 32));
|
||||
assert_eq!(*source.0.lock().unwrap(), [64.0 / 16_000.0]);
|
||||
}
|
||||
|
||||
/// A vector footage thumbnail whose drawn size is a pixel over the requested one is shrunk by
|
||||
/// that pixel, not halved by an integer step.
|
||||
#[test]
|
||||
fn a_vector_thumbnail_one_pixel_over_is_not_halved() {
|
||||
use std::sync::Arc;
|
||||
|
||||
use effectcraft_project::{Footage, ItemId};
|
||||
use effectcraft_raster::Image;
|
||||
use effectcraft_time::Tick;
|
||||
|
||||
struct Over;
|
||||
impl crate::render::FootageSource for Over {
|
||||
fn frame(&self, _: ItemId, _: &Footage, _: Tick) -> Option<Arc<Image>> {
|
||||
None
|
||||
}
|
||||
fn vector_frame(&self, _: ItemId, _: &Footage, _: f64) -> Option<Arc<Image>> {
|
||||
Some(Arc::new(Image::new(64, 64)))
|
||||
}
|
||||
}
|
||||
let mut s = Session { footage: Arc::new(Over), ..Default::default() };
|
||||
let f = Footage { path: "/m/sq.svg".into(), codec: "SVG".into(), width: 121, height: 121, has_video: true, ..Default::default() };
|
||||
let item = std::sync::Arc::make_mut(&mut s.project).add_item("sq.svg", effectcraft_color::Label::Sandstone, None, ItemKind::Footage(f));
|
||||
let (w, h, px) = (s.thumbnail_job(item, Tick::ZERO, 63).unwrap())().unwrap();
|
||||
assert_eq!((w, h), (63, 63));
|
||||
assert_eq!(px.len(), 63 * 63 * 4);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user