feat: import Xournal++ and Xournal notebooks (Issue #47)
The import menu entry (formerly "Import PDF") and drag & drop now also accept .xopp and .xoj files. Each Xournal page becomes a page of a new notebook: strokes with pen pressure, highlighters, texts, embedded images, lined/squared/dotted paper, image backgrounds and PDF backgrounds (looked up at the stored path and next to the file). All layers are flattened in order; LaTeX formulas are skipped and counted in the status message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b5d9d72e79
commit
2bd697ef82
11 files changed
+902
-44
No files matched your search
+25
-13
@@ -2216,10 +2216,10 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
}
|
||||
|
||||
// Bilddatei ins Fenster gezogen: an der Ablagestelle einfügen
|
||||
// Bilddatei ins Fenster gezogen: an der Ablagestelle einfügen; PDF/Xournal++: importieren
|
||||
WindowEvent::DroppedFile(path) => {
|
||||
if crate::file_picker::is_pdf_path(&path) {
|
||||
ui_state.queued_actions.push(UiAction::ImportPdf(path));
|
||||
if crate::file_picker::is_pdf_path(&path) || crate::xopp::is_xopp_path(&path) {
|
||||
ui_state.queued_actions.push(UiAction::ImportFile(path));
|
||||
} else if crate::assets::is_supported_image_path(&path) {
|
||||
let (sx, sy) = cursor_screen_pos;
|
||||
let center = canvas.screen_to_page_clamped(sx, sy);
|
||||
@@ -3837,18 +3837,23 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
}
|
||||
}
|
||||
UiAction::ImportPdf(path) => {
|
||||
UiAction::ImportFile(path) => {
|
||||
// Neben das gerade geöffnete Notizbuch
|
||||
let folder = ui_state.library.folder_of(&manifest.id).to_string();
|
||||
let title = path
|
||||
.file_stem()
|
||||
.map(|s| s.to_string_lossy().into_owned())
|
||||
.unwrap_or_else(|| "PDF".to_string());
|
||||
let result = std::fs::read(&path)
|
||||
.map_err(|e| e.to_string())
|
||||
.and_then(|bytes| storage::create_notebook_from_pdf(&storage_base_dir, &title, bytes));
|
||||
.unwrap_or_else(|| "Import".to_string());
|
||||
let result = if crate::xopp::is_xopp_path(&path) {
|
||||
crate::xopp::create_notebook_from_xopp(&storage_base_dir, &title, &path)
|
||||
} else {
|
||||
std::fs::read(&path)
|
||||
.map_err(|e| e.to_string())
|
||||
.and_then(|bytes| storage::create_notebook_from_pdf(&storage_base_dir, &title, bytes))
|
||||
.map(|(nb, m, dir)| (nb, m, dir, crate::xopp::ImportReport::default()))
|
||||
};
|
||||
match result {
|
||||
Ok((new_nb, new_manifest, new_dir)) => {
|
||||
Ok((new_nb, new_manifest, new_dir, report)) => {
|
||||
let id = new_manifest.id.clone();
|
||||
change_library(&storage_base_dir, &mut ui_state, |library| {
|
||||
library.move_notebook(&id, &folder)
|
||||
@@ -3867,15 +3872,22 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
canvas.reset_view();
|
||||
canvas.sync_page(notebook.current_page_mut());
|
||||
update_window_title(&window, ¬ebook, &manifest, ui_state.active_tool, autosave.status());
|
||||
ui_state.set_export_message(t!(
|
||||
let mut message = t!(
|
||||
"'{title}' importiert ({count} Seiten)",
|
||||
title = manifest.title,
|
||||
count = notebook.pages.len()
|
||||
));
|
||||
);
|
||||
if let Some(pdf) = &report.missing_pdf {
|
||||
message.push_str(&t!(", PDF-Hintergrund nicht gefunden: {file}", file = pdf));
|
||||
}
|
||||
if report.skipped > 0 {
|
||||
message.push_str(&t!(", {count} Elemente übersprungen", count = report.skipped));
|
||||
}
|
||||
ui_state.set_export_message(message);
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("[PDF-Import] '{}': {err}", path.display());
|
||||
ui_state.set_export_message(t!("PDF nicht importiert: {err}", err = err));
|
||||
eprintln!("[Import] '{}': {err}", path.display());
|
||||
ui_state.set_export_message(t!("Nicht importiert: {err}", err = err));
|
||||
}
|
||||
}
|
||||
window.request_redraw();
|
||||
|
||||
Reference in new issue
Block a user