Repository: fschutt/printpdf (language: rust)

Issue:
UTF-8 vs PDF built-in fonts
It seems the PDF built-in fonts use the ISO-8859-1 encoding which causes output of a lot of "national" characters look wrong.  Could printpdf be modified to check if the selected font is built-in and then translate the String contents into something that looks right on output?  If the String contains characters not available in ISO-8859-1 they could maybe just be discarded?

The recoding of the String is quite straightforward - if the character code value is less than 256 then use it, otherwise discard it (or replace with NBSP or something else?).

If the chosen built-in font is 'Symbol' or 'Zapf Dingbats' then something more convoluted may have to be done, if at all.


Discussion / hints:
Yeah, I haven't looked into that, mostly because it's a size optimization. Usually it's easier to just embed a proper font. You can also try to use an external tool to do that, i.e. embed your font and then let a PDF-fixing tool such as xpdf or similar process the PDF file again (to reduce the size).
`printpdf` should at least provide a method to print ISO-8859-1 encoded bytes.  Currently, it can only print Rust strings, which are always UTF-8 encoded, so it’s impossible to use non-ASCII characters and builtin fonts.

Would you accept a PR that adds a `write_text_builtin` method to `PdfLayerReference` that takes a byte slice and a `Builtin` variant?
Well `write_text` uses a font ID so you can either use a built-in or an external font. Making a separate function for builtin vs external fonts and all the different encodings could duplicate functionality unnecessarily.

Instead it would be better to just make a static function like `check_iso_8859` or `convert_text_to_iso_8859` or something like that. Then the user of the library can decide what to do if the text isn't ISO-conform.

Fix patch:
diff --git a/src/types/pdf_document.rs b/src/types/pdf_document.rs
index 8d8b61c..f516afe 100644
--- a/src/types/pdf_document.rs
+++ b/src/types/pdf_document.rs
@@ -202,6 +202,11 @@ impl PdfDocumentReference {
     }
 
     /// Add a built-in font to the document
+    ///
+    /// Built-in fonts can only be used to print characters that are supported by the
+    /// [Windows-1252][] encoding.  All other characters will be ignored.
+    ///
+    /// [Windows-1252]: https://en.wikipedia.org/wiki/Windows-1252
     pub fn add_builtin_font(&self, builtin_font: BuiltinFont)
     -> ::std::result::Result<IndirectFontRef, Error>
     {
diff --git a/src/types/pdf_layer.rs b/src/types/pdf_layer.rs
index c4e1d20..86e737f 100644
--- a/src/types/pdf_layer.rs
+++ b/src/types/pdf_layer.rs
@@ -429,6 +429,11 @@ impl PdfLayerReference {
     }
 
     /// Add text to the file at the current position
+    ///
+    /// If the given font is a built-in font and the given text contains characters that are not
+    /// supported by the [Windows-1252][] encoding, these characters will be ignored.
+    ///
+    /// [Windows-1252]: https://en.wikipedia.org/wiki/Windows-1252
     #[inline]
     pub fn write_text<S>(&self, text: S, font: &IndirectFontRef)
     -> () where S: Into<String>
@@ -478,7 +483,9 @@ impl PdfLayerReference {
                     .flat_map(|x| vec!((x >> 8) as u8, (x & 255) as u8))
                     .collect::<Vec<u8>>()
             } else {
-                text.as_bytes().to_vec()
+                // For built-in fonts, we selected the WinAnsiEncoding, see the Into<LoDictionary>
+                // implementation for BuiltinFont.
+                lopdf::Document::encode_text(Some("WinAnsiEncoding"), &text)
             }
         };
 
@@ -502,6 +509,11 @@ impl PdfLayerReference {
     }
 
     /// Add text to the file, x and y are measure in millimeter from the bottom left corner
+    ///
+    /// If the given font is a built-in font and the given text contains characters that are not
+    /// supported by the [Windows-1252][] encoding, these characters will be ignored.
+    ///
+    /// [Windows-1252]: https://en.wikipedia.org/wiki/Windows-1252
     #[inline]
     pub fn use_text<S>(&self, text: S, font_size: i64,
                        x: Mm, y: Mm, font: &IndirectFontRef)


Test patch: