mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 04:07:12 -06:00
Clipboard: a .ai or .ait file copied in a file manager pastes as its art
Paste takes a file copied in a file manager by its flavor, which file_flavour tells from the file's first 4,096 bytes through fileio::detect. detect names PDF or PostScript bytes in a file called .ai or .ait by that extension, and file_flavour gave no flavor for the format ids ai and ait. So a copied .ai or .ait file did not paste as its art, while the same bytes in a .pdf or .eps file did. A copied .ai or .ait file whose bytes are a PDF now pastes through the PDF flavor (clipboard.importPdf), and one whose bytes are PostScript pastes through the EPS flavor (clipboard.importEps). Other files with those extensions paste as before. A .ai saved without its PDF part also gets the PDF flavor, and Paste answers it with clipboard.importPdf's error, as it does for the same file named .pdf. Docs: docs/control-protocol.md, docs/development.md, docs/target-app-parity.md.
This commit is contained in:
@@ -71,13 +71,16 @@ pub const FILE_HEAD: usize = 4096;
|
||||
|
||||
/// What a file copied in a file manager pastes as, if one of `mimes` (`image/*`: any bitmap):
|
||||
/// SVG, PDF, EPS, a Windows metafile or a bitmap (its own `image/…` type), told from its first
|
||||
/// [`FILE_HEAD`] bytes and its name. The file's bytes are that flavour's data.
|
||||
/// [`FILE_HEAD`] bytes and its name. A `.ai` or `.ait` file pastes as PDF when its bytes are a
|
||||
/// PDF and as EPS when they are PostScript. The file's bytes are that flavour's data.
|
||||
pub fn file_flavour(name: &str, head: &[u8], mimes: &[&str]) -> Option<&'static str> {
|
||||
let f = fileio::detect(name, head)?;
|
||||
let (asked, mime) = match f.id {
|
||||
"svg" => (SVG, SVG),
|
||||
"pdf" => (PDF, PDF),
|
||||
"eps" => (EPS, EPS),
|
||||
"ai" | "ait" if head.starts_with(b"%PDF") => (PDF, PDF),
|
||||
"ai" | "ait" if vectorcraft_pdf::is_postscript(head) => (EPS, EPS),
|
||||
"emf" | "wmf" => (EMF, EMF),
|
||||
_ if f.raster => (BITMAP, f.mime),
|
||||
_ => return None,
|
||||
|
||||
@@ -7,7 +7,7 @@ use vectorcraft_geom::Point;
|
||||
use vectorcraft_tools::{Mods, PointerEvent, PointerKind, ToolKey};
|
||||
|
||||
use super::*;
|
||||
use crate::cmd::clipboard::{BITMAP, FILE_HEAD, PASTE_ORDER, PDF, PNG, SVG, TEXT, file_flavour};
|
||||
use crate::cmd::clipboard::{BITMAP, EPS, FILE_HEAD, PASTE_ORDER, PDF, PNG, SVG, TEXT, file_flavour};
|
||||
|
||||
fn session() -> Session {
|
||||
let mut s = Session::new();
|
||||
@@ -141,6 +141,27 @@ fn copied_files_paste_by_their_content() {
|
||||
assert_eq!(file_flavour("art.svg", svg, &[BITMAP]), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copied_ai_files_paste_as_the_pdf_or_postscript_inside() {
|
||||
let mut s = session();
|
||||
copy_red_square(&mut s);
|
||||
let pdf = decode(&run(&mut s, "clipboard.exportPdf", json!({})));
|
||||
let ps = b"%!PS-Adobe-3.0\n%%BoundingBox: 0 0 40 40\n%%EndComments\n1 0 0 setrgbcolor\nnewpath 0 0 moveto 40 0 lineto 40 40 lineto closepath fill\nshowpage\n";
|
||||
let of = |name: &str, bytes: &[u8]| file_flavour(name, &bytes[..bytes.len().min(FILE_HEAD)], &PASTE_ORDER);
|
||||
for name in ["art.ai", "art.ait", "ART.AI"] {
|
||||
assert_eq!(of(name, &pdf), Some(PDF), "{name}");
|
||||
assert_eq!(of(name, ps), Some(EPS), "{name}");
|
||||
}
|
||||
// Neither PDF nor PostScript: nothing to paste, whatever the name says.
|
||||
assert_eq!(of("art.ai", b"hello"), None);
|
||||
// Only what was asked for.
|
||||
assert_eq!(file_flavour("art.ai", &pdf, &[EPS]), None);
|
||||
assert_eq!(file_flavour("art.ait", ps, &[PDF]), None);
|
||||
// clipboard.importEps, the EPS flavor's command, reads the PostScript.
|
||||
let r = run(&mut s, "clipboard.importEps", json!({"dataBase64": vectorcraft_format::base64_encode(ps)}));
|
||||
assert_eq!(r["count"], 1, "{r}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_text_then_paste_gives_point_text() {
|
||||
let mut s = session();
|
||||
|
||||
Reference in New Issue
Block a user