mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-24 09:46:59 -06:00
Map the WMF window onto the placeable box (#2673)
This commit is contained in:
committed by
bflatastic
parent
b5164825d6
commit
f999688b41
@@ -99,6 +99,13 @@ fn window(bytes: &[u8], mut at: usize) -> Option<Rect> {
|
||||
Some(Rect::new(o.x, o.y, o.x + e.x, o.y + e.y).abs())
|
||||
}
|
||||
|
||||
/// Logical → document for a placeable file whose window (`org`, `ext`) is mapped onto its box `b`;
|
||||
/// a negative extent flips that axis, as in GDI.
|
||||
fn window_map(b: Rect, k: f64, org: Point, ext: Point) -> Affine {
|
||||
let ratio = |box_len: f64, e: f64| if e.abs() > 1e-12 { box_len / e } else { 1.0 };
|
||||
Affine::scale_non_uniform(k * ratio(b.width(), ext.x), k * ratio(b.height(), ext.y)) * Affine::translate(-org.to_vec2())
|
||||
}
|
||||
|
||||
pub(super) fn play(bytes: &[u8]) -> Result<Imported, String> {
|
||||
let (start, placeable) = header(bytes).ok_or("the WMF header is damaged")?;
|
||||
let (frame, inch) = match placeable {
|
||||
@@ -109,6 +116,9 @@ pub(super) fn play(bytes: &[u8]) -> Result<Imported, String> {
|
||||
let origin = frame.map_or(Point::ZERO, |f| f.origin());
|
||||
let artboard = frame.map_or(Rect::new(0.0, 0.0, 1.0, 1.0), |f| Rect::new(0.0, 0.0, f.width() * k, f.height() * k));
|
||||
let mut p = Player::new(Kind::Wmf, Affine::scale(k) * Affine::translate(-origin.to_vec2()), 25.4 / inch, artboard);
|
||||
// With a placeable header, the window records map the window onto the box.
|
||||
let placed = placeable.map(|(b, _)| b).filter(|b| b.width() > 0.0 && b.height() > 0.0);
|
||||
let mut win = (placed.map_or(Point::ZERO, |b| b.origin()), placed.map_or(Point::ZERO, |b| Point::new(b.width(), b.height())));
|
||||
let mut at = start;
|
||||
let mut ended = false;
|
||||
while let Some(head) = bytes.get(at..at + 6) {
|
||||
@@ -122,7 +132,16 @@ pub(super) fn play(bytes: &[u8]) -> Result<Imported, String> {
|
||||
if !matches!(function, 0x0213 | 0x0214) {
|
||||
p.flush();
|
||||
}
|
||||
if record(&mut p, function, rec.get(6..).unwrap_or_default()).is_none() {
|
||||
if let (Some(b), 0x020B | 0x020C) = (placed, function) {
|
||||
if let Some(v) = point_yx(&mut Reader::new(rec.get(6..).unwrap_or_default())) {
|
||||
if function == 0x020B {
|
||||
win.0 = v;
|
||||
} else {
|
||||
win.1 = v;
|
||||
}
|
||||
p.dev_to_doc = window_map(b, k, win.0, win.1);
|
||||
}
|
||||
} else if record(&mut p, function, rec.get(6..).unwrap_or_default()).is_none() {
|
||||
p.skip();
|
||||
}
|
||||
at += rec.len();
|
||||
|
||||
@@ -289,6 +289,25 @@ fn hand_built_wmf_plays_like_gdi() {
|
||||
assert_eq!(fill_rgb(&p[1]), Some([0, 255, 0]), "the new brush took the freed slot");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wmf_window_is_mapped_onto_the_placeable_box() {
|
||||
// The box is 1000 × 500 units at 1440 an inch: 50 × 25 pt.
|
||||
let want = Rect::new(12.5, 6.25, 37.5, 18.75);
|
||||
// Window 0,0 – 4000 × 2000: the rectangle 1000,500 – 3000,1500 is the middle half.
|
||||
let ext = vec![(0x020C, le16(&[2000, 4000])), (0x041B, le16(&[1500, 3000, 500, 1000]))];
|
||||
// Window 10000,20000 – 1000 × 500 (the box): the rectangle 10250,20125 – 10750,20375.
|
||||
let org = vec![(0x020B, le16(&[20000, 10000])), (0x020C, le16(&[500, 1000])), (0x041B, le16(&[20375, 10750, 20125, 10250]))];
|
||||
// Window 0,2000 – 4000 × -2000 (y up): the same rectangle, flipped onto the same place.
|
||||
let flip = vec![(0x020B, le16(&[2000, 0])), (0x020C, le16(&[-2000, 4000])), (0x041B, le16(&[1500, 3000, 500, 1000]))];
|
||||
for records in [ext, org, flip] {
|
||||
let back = import(&hand_wmf(1000, 500, &records)).unwrap();
|
||||
assert!(near(back.document.artboards[0].rect, Rect::new(0.0, 0.0, 50.0, 25.0), 1e-9));
|
||||
let p = paths(&back.document);
|
||||
assert_eq!(p.len(), 1);
|
||||
assert!(near(p[0].geometric_bounds().unwrap(), want, 1e-6), "{:?}", p[0].geometric_bounds());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn damaged_files_fail_or_import_partly() {
|
||||
let good = emf(&sample()).bytes;
|
||||
|
||||
Reference in New Issue
Block a user