diff --git a/crates/automation/src/documents.rs b/crates/automation/src/documents.rs
--- a/crates/automation/src/documents.rs
+++ b/crates/automation/src/documents.rs
@@ -461,8 +461,17 @@ impl Automation {
                     Some(_) => a.opt_str("text")?.unwrap_or_default().to_string(),
                     None => a.str("text")?.to_string(),
                 };
+                let font = match a.opt_str("font")? {
+                    None | Some("Helvetica") | Some("helvetica") => pdfcraft_engine::FontFamily::Helvetica,
+                    Some("Times") | Some("times") => pdfcraft_engine::FontFamily::Times,
+                    Some("Courier") | Some("courier") => pdfcraft_engine::FontFamily::Courier,
+                    Some(other) => {
+                        return Err(ToolError::InvalidArgs(format!("font must be \"Helvetica\", \"Times\" or \"Courier\", not {other:?}")));
+                    }
+                };
                 let wm = Watermark {
                     text,
+                    font,
                     source: None,
                     scale: a.opt_num("scale")?.unwrap_or(d.scale).clamp(0.01, 1.0),
                     font_size: a.opt_num("font_size")?.unwrap_or(0.0),
diff --git a/crates/automation/src/tools.rs b/crates/automation/src/tools.rs
--- a/crates/automation/src/tools.rs
+++ b/crates/automation/src/tools.rs
@@ -975,7 +975,7 @@ pub fn tools() -> Vec<ToolDef> {
             }),
             &["doc"],
         )),
-        t("doc_watermark", "Add watermark", "Add a watermark to pages: text, or a picture from `file` (an image, or page `file_page` of a PDF) at `scale` of the page (default 0.5); rotated (degrees counter-clockwise, default 45), semi-transparent (opacity 0–1, default 0.5), text fitted to the page unless font_size is given, on top unless behind: true; moved from the page centre by `offset_x` (right) and `offset_y` (up) points (default 0). replace: true swaps out existing ones. Undoable.")
+        t("doc_watermark", "Add watermark", "Add a watermark to pages: text, or a picture from `file` (an image, or page `file_page` of a PDF) at `scale` of the page (default 0.5); rotated (degrees counter-clockwise, default 45), semi-transparent (opacity 0–1, default 0.5), text fitted to the page unless font_size is given, font \"Helvetica\" (default), \"Times\" or \"Courier\", on top unless behind: true; moved from the page centre by `offset_x` (right) and `offset_y` (up) points (default 0). replace: true swaps out existing ones. Undoable.")
             .cmd("edit.watermark")
             .with(schema(
                 json!({
@@ -985,6 +985,7 @@ pub fn tools() -> Vec<ToolDef> {
                     "file": { "type": "string" },
                     "file_page": { "type": "integer", "minimum": 1 },
                     "scale": { "type": "number", "exclusiveMinimum": 0, "maximum": 1 },
+                    "font": { "type": "string", "enum": ["Helvetica", "Times", "Courier"] },
                     "font_size": { "type": "number", "exclusiveMinimum": 0 },
                     "color": { "type": "string" },
                     "opacity": { "type": "number", "minimum": 0, "maximum": 1 },
diff --git a/crates/automation/tests/it/automation.rs b/crates/automation/tests/it/automation.rs
--- a/crates/automation/tests/it/automation.rs
+++ b/crates/automation/tests/it/automation.rs
@@ -2698,6 +2698,8 @@ fn watermarks_move_from_the_page_centre_through_tools() {
     // Huge offsets are clamped, and a value that isn't a number is refused.
     ok(&mut a, "doc_watermark", json!({ "doc": doc, "pages": [1], "text": "DRAFT", "offset_y": 1e300, "replace": true }));
     assert!(matches!(a.call("doc_watermark", &json!({ "doc": doc, "text": "X", "offset_x": "left" })), Err(ToolError::InvalidArgs(_))));
+    ok(&mut a, "doc_watermark", json!({ "doc": doc, "pages": [1], "text": "COURIER", "font": "Courier", "replace": true }));
+    assert!(matches!(a.call("doc_watermark", &json!({ "doc": doc, "text": "X", "font": "ComicSans" })), Err(ToolError::InvalidArgs(_))));
 }
 
 #[test]
diff --git a/crates/edit/src/apply.rs b/crates/edit/src/apply.rs
--- a/crates/edit/src/apply.rs
+++ b/crates/edit/src/apply.rs
@@ -164,14 +164,21 @@ pub fn add_watermark(doc: &mut Document, pages: &[usize], wm: &Watermark, replac
             place(doc, page, MarkKind::Watermark, content.into_bytes(), wm.behind)?;
             continue;
         }
-        let widest = lines.iter().map(|l| helvetica_width(l, 1.0)).fold(0.0, f64::max).max(0.01);
+        let preferred = match wm.font {
+            added::Family::Helvetica => "PCHelv",
+            added::Family::Times => "PCTimes",
+            added::Family::Courier => "PCCour",
+        };
+        let base = wm.font.base_font(false, false);
+        let resource = free_font_name(doc, &page_fonts(doc, &page), preferred, base);
+        let widest = lines.iter().map(|l| wm.font.width(l, 1.0, false, false)).fold(0.0, f64::max).max(0.01);
         let size = if wm.font_size > 0.0 { wm.font_size } else { ((w * w + h * h).sqrt() * 0.5 / widest).clamp(6.0, 300.0) };
         let (s, c) = wm.rotation.to_radians().sin_cos();
         let (cx, cy) = (w / 2.0 + wm.offset[0], h / 2.0 + wm.offset[1]);
         let mut content = begin(MarkKind::Watermark, "Watermark", page.view_matrix(doc)).into_bytes();
         content.extend(
             format!(
-                "/PCGS{} gs\n{} {} {} {} {} {} cm\nBT\n/PCHelv {} Tf\n{}\n",
+                "/PCGS{} gs\n{} {} {} {} {} {} cm\nBT\n/{resource} {} Tf\n{}\n",
                 (opacity * 100.0).round() as i64,
                 n(c),
                 n(s),
@@ -187,12 +194,13 @@ pub fn add_watermark(doc: &mut Document, pages: &[usize], wm: &Watermark, replac
         let line_h = size * 1.15;
         let total = line_h * (lines.len() as f64 - 1.0);
         for (li, line) in lines.iter().enumerate() {
-            let tw = helvetica_width(line, size);
+            let tw = wm.font.width(line, size, false, false);
             content.extend(text_op(-tw / 2.0, total / 2.0 - li as f64 * line_h - size * 0.35, line));
         }
         content.extend_from_slice(b"ET\n");
         content.extend_from_slice(END.as_bytes());
-        add_resources(doc, &page, Some(opacity), None)?;
+        let faces = if !page_fonts(doc, &page).contains(resource.as_bytes()) { vec![(resource.into_bytes(), base)] } else { Vec::new() };
+        add_page_resources(doc, &page, Some(opacity), &faces)?;
         let page = &page_list(doc)[i];
         place(doc, page, MarkKind::Watermark, content, wm.behind)?;
     }
diff --git a/crates/edit/src/lib.rs b/crates/edit/src/lib.rs
--- a/crates/edit/src/lib.rs
+++ b/crates/edit/src/lib.rs
@@ -18,7 +18,7 @@
 #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
 
 use pdfcraft_cos::{Dict, Document, ObjRef, Object, Stream};
-use pdfcraft_fonts::{helvetica_width, literal, win_ansi};
+use pdfcraft_fonts::{literal, win_ansi};
 
 #[derive(Debug, thiserror::Error, PartialEq)]
 pub enum EditError {
diff --git a/crates/edit/src/marks.rs b/crates/edit/src/marks.rs
--- a/crates/edit/src/marks.rs
+++ b/crates/edit/src/marks.rs
@@ -121,12 +121,17 @@ pub struct MarkSource {
 /// A watermark: text, or a picture from a file (`source`; the text is then ignored).
 #[derive(Clone, Debug, PartialEq)]
 pub struct Watermark {
+    /// Text drawn when there is no picture source.
     pub text: String,
+    /// The standard font family used for text watermarks (default Helvetica).
+    pub font: added::Family,
+    /// Optional picture from a file or another page; when present, text is ignored.
     pub source: Option<MarkSource>,
     /// Pictures: size relative to the page (1.0 fits the page).
     pub scale: f64,
     /// 0 = fit: about half the page diagonal.
     pub font_size: f64,
+    /// Colour for text watermarks.
     pub color: Rgb,
     /// 0–1.
     pub opacity: f64,
@@ -143,8 +148,8 @@ impl Watermark {
     /// standard fonts can't draw it (#125). A picture watermark draws no text.
     pub fn first_undrawable(&self) -> Option<char> {
         match self.source {
-            Some(_) => None,
             None => self.text.trim().lines().find_map(pdfcraft_fonts::first_non_win_ansi),
+            Some(_) => None,
         }
     }
 }
@@ -153,6 +158,7 @@ impl Default for Watermark {
     fn default() -> Self {
         Self {
             text: String::new(),
+            font: added::Family::Helvetica,
             source: None,
             scale: 0.5,
             font_size: 0.0,
diff --git a/crates/edit/src/tests.rs b/crates/edit/src/tests.rs
--- a/crates/edit/src/tests.rs
+++ b/crates/edit/src/tests.rs
@@ -462,6 +462,28 @@ fn a_watermark_offset_that_is_not_finite_is_refused() {
     }
 }
 
+#[test]
+fn watermarks_support_font_selection() {
+    let mut doc = fixture();
+    let wm_times = Watermark { text: "TIMES WATERMARK".into(), font: added::Family::Times, font_size: 24.0, rotation: 0.0, ..Watermark::default() };
+    add_watermark(&mut doc, &[0], &wm_times, false).unwrap();
+    let s = streams(&doc, 0);
+    let mark = s.iter().find(|c| c.contains("/PCMark /Watermark")).expect("the watermark stream");
+    assert!(mark.contains("/PCTimes 24 Tf"), "uses Times font: {mark}");
+    let res = page_fonts(&doc, &page_list(&doc)[0]);
+    assert!(res.contains(b"PCTimes"), "page resources include PCTimes");
+
+    let mut doc = fixture();
+    let wm_cour =
+        Watermark { text: "COURIER WATERMARK".into(), font: added::Family::Courier, font_size: 24.0, rotation: 0.0, ..Watermark::default() };
+    add_watermark(&mut doc, &[0], &wm_cour, false).unwrap();
+    let s = streams(&doc, 0);
+    let mark = s.iter().find(|c| c.contains("/PCMark /Watermark")).expect("the watermark stream");
+    assert!(mark.contains("/PCCour 24 Tf"), "uses Courier font: {mark}");
+    let res = page_fonts(&doc, &page_list(&doc)[0]);
+    assert!(res.contains(b"PCCour"), "page resources include PCCour");
+}
+
 #[test]
 fn invalid_requests_change_nothing() {
     let mut doc = fixture();
diff --git a/crates/ui-egui/src/dialogs/marks_ui.rs b/crates/ui-egui/src/dialogs/marks_ui.rs
--- a/crates/ui-egui/src/dialogs/marks_ui.rs
+++ b/crates/ui-egui/src/dialogs/marks_ui.rs
@@ -314,8 +314,16 @@ pub(crate) fn body(ui: &mut egui::Ui, app: &mut PdfCraftApp, t: &Tokens, kind: M
                         );
                     });
                     ui.horizontal(|ui| {
+                        ui.add_enabled_ui(!d.use_file, |ui| {
+                            ui.label(tl!("Font"));
+                            egui::ComboBox::from_id_salt("wm-font").selected_text(d.wm.font.label()).width(100.0).show_ui(ui, |ui| {
+                                for f in [FontFamily::Helvetica, FontFamily::Times, FontFamily::Courier] {
+                                    ui.selectable_value(&mut d.wm.font, f, f.label());
+                                }
+                            });
+                        });
                         ui.add_enabled_ui(!d.use_file, |ui| ui.add(widgets::checkbox(&mut d.fit, tl!("Fit to page"))));
-                        ui.add_enabled_ui(!d.fit, |ui| {
+                        ui.add_enabled_ui(!d.fit && !d.use_file, |ui| {
                             ui.label(tl!("Size"));
                             if d.wm.font_size == 0.0 {
                                 d.wm.font_size = 72.0;
@@ -436,7 +444,8 @@ pub(crate) fn body(ui: &mut egui::Ui, app: &mut PdfCraftApp, t: &Tokens, kind: M
                 } else {
                     (wm.font_size as f32 * s).max(5.0)
                 };
-                let galley = p.layout_no_wrap(text.to_string(), egui::FontId::proportional(size), rgb32(wm.color).gamma_multiply(wm.opacity as f32));
+                let font_id = if wm.font == FontFamily::Courier { egui::FontId::monospace(size) } else { egui::FontId::proportional(size) };
+                let galley = p.layout_no_wrap(text.to_string(), font_id, rgb32(wm.color).gamma_multiply(wm.opacity as f32));
                 let angle = -(wm.rotation as f32).to_radians();
                 let half = galley.size() / 2.0;
                 let (sn, cs) = angle.sin_cos();
diff --git a/crates/ui-egui/tests/it/marks.rs b/crates/ui-egui/tests/it/marks.rs
--- a/crates/ui-egui/tests/it/marks.rs
+++ b/crates/ui-egui/tests/it/marks.rs
@@ -123,6 +123,31 @@ fn watermark_and_background_dialogs() {
     assert_eq!(marks(&h).len(), 2);
 }
 
+#[test]
+fn watermark_dialog_draws_in_the_chosen_face() {
+    let mut h = harness();
+    assert!(h.state_mut().execute("edit.watermark"));
+    h.run_steps(3);
+    h.get_by_label("Font");
+    h.get_by_value("Helvetica").click();
+    h.run_steps(2);
+    h.get_by_label("Times").click();
+    h.run_steps(2);
+    assert_eq!(h.state().marks_draft.wm.font, pdfcraft_engine::FontFamily::Times);
+    h.state_mut().marks_draft.wm.text = "Serif Watermark".into();
+    h.run_steps(2);
+    h.get_by_label("OK").click();
+    h.run_steps(4);
+    assert_eq!(marks(&h), [MarkKind::Watermark]);
+    let s = h.state();
+    let doc = pdfcraft_cos::Document::open(s.session.get(s.views[0].id).unwrap().bytes.clone()).unwrap();
+    let page = &pdfcraft_model::pages(&doc)[0];
+    let res = doc.resolve(page.dict.get(b"Resources").unwrap());
+    let fonts = doc.resolve(res.as_dict().unwrap().get(b"Font").unwrap()).as_dict().cloned().unwrap();
+    let face = doc.resolve(fonts.get(b"PCTimes").expect("Times is added")).as_dict().cloned().unwrap();
+    assert_eq!(face.name(b"BaseFont"), Some(&b"Times-Roman"[..]));
+}
+
 #[test]
 fn backgrounds_and_watermarks_from_a_file() {
     let mut h = harness();
