Open LegendarySaiyan opened 1 year ago
Here is the code:
let font_data = std::fs::read("src/fonts/Arial-Bold.ttf").unwrap();
let font_dict_id = template_pdf.add_object(dictionary! {
"Type" => "Font",
"Subtype" => "TrueType",
"BaseFont" => "Arial-Bold",
"Encoding" => "WinAnsiEncoding",
});
let font_stream = Stream::new(dictionary!{}, font_data);
let font_file_id = template_pdf.add_object(font_stream);
let font_id = template_pdf.add_object(dictionary! {
"Type" => "Font",
"Subtype" => "TrueType",
"BaseFont" => "Arial-Bold",
"Encoding" => "WinAnsiEncoding",
"FontDescriptor" => dictionary! {
"Type" => "FontDescriptor",
"FontName" => "Arial-Bold",
"FontFile2" => font_file_id,
"Flags" => 32,
"ItalicAngle" => 0,
"Ascent" => 905,
"Descent" => -212,
"CapHeight" => 728,
"XHeight" => 519,
"StemV" => 165,
"FontBBox" => vec![-628, -376, 2000, 1010].into_iter().map(|n| Object::Integer(n)).collect::<Vec<_>>(),
"CharSet" => "/WinAnsiEncoding",
"MaxWidth" => 2000,
},
});
let mut operations = vec![
Operation::new("BT", vec![]),
];
operations.push(Operation::new("BT", vec![]));
operations.push(Operation::new("F1", vec![font_size.into()]));
let color_string = format!("{} {} {} rg", color.0, color.1, color.2);
operations.push(Operation::new(&color_string, vec![]));
operations.push(Operation::new("Td", vec![position.0.into(), position.1.into()]));
operations.push(Operation::new("Tf", vec![font_id.into(), font_size.into()]));
operations.push(Operation::new("Tj", vec![Object::string_literal(text)]));
operations.push(Operation::new("ET", vec![]));
let content = Content {
operations,
};
let text_xobject = xobject::form(
vec![0.0, 0.0, 595.0, 842.0],
vec![1.0, 0.0, 0.0, 1.0, 0.0, 0.0],
content.encode().unwrap(),
);
let mut page = template_pdf.get_page(page_id).unwrap();
let resources = page.resources_mut();
resources.fonts_mut().insert(Name("F1".to_string()), font_id);
page.add_content(text_xobject.to_content());
let a = template_pdf.get_page_fonts(page_id);
println!("{:?}", a);
let p_o = existing_page_id.iter().next().unwrap();
let p_oo = *p_o;
let pages = dictionary! {
"Type" => "Pages",
"Kids" => vec![p_oo.into()],
"Count" => 1,
"Resources" => font_dict_id,
"MediaBox" => vec![0.into(), 0.into(), 595.into(), 842.into()],
};
template_pdf.objects.insert(pages_id, Object::Dictionary(pages));
}
@J-F-Liu Would you be so kind to give the example for exporting the fonts? :)
I haven't tried this before, seems also need to embed the font file, see PDF Reference document for details.
I've done this and it seems to be changing the font:
pub fn example() -> () {
// Load the font data from a file
let font_data = std::fs::read("ClimateCrisis-Regular-VariableFont_YEAR.ttf").unwrap();
// Create a stream object for the font data
let font_stream = Stream::new(dictionary! {}, font_data.clone());
// Create a document object and add the font and font descriptor to it
let mut doc = Document::with_version("1.5");
// Create a font descriptor dictionary object
let font_stream_id = doc.add_object(font_stream);
let font_descriptor_dict = dictionary! {
"Type" => "FontDescriptor",
"FontName" => "MyFont",
"FontFile2" => font_stream_id,
"Flags" => 4,
"Ascent" => 728,
"Descent" => -212,
"CapHeight" => 728,
"ItalicAngle" => 0,
"StemV" => 90,
};
let font_descriptor_id = doc.add_object(font_descriptor_dict);
let encoding = dictionary! {
"Type" => "Encoding",
"BaseEncoding" => "WinAnsiEncoding",
};
// Create a font dictionary object
let font_dict = dictionary! {
"Type" => "Font",
"Subtype" => "TrueType",
"BaseFont" => "MyFont",
"FirstChar" => 32,
"LastChar" => 255,
// "Widths" => Object::Array((32..=255).map(|c| (c, 600)).collect()),
"FontDescriptor" => font_descriptor_id,
"Encoding" => doc.add_object(encoding),
"Length1" => font_data.len() as i32
};
let font_id = doc.add_object(font_dict);
let content = Content {
operations: vec![
Operation::new("BT", vec![]),
Operation::new("Tf", vec!["MyFont".into(), 48.into()]),
Operation::new("Td", vec![100.into(), 600.into()]),
Operation::new(
"Tj",
vec![Object::string_literal("Hello World!ążę Ą Ę Ż Ć")],
),
Operation::new("ET", vec![]),
],
};
let resources_id = doc.add_object(dictionary! {
"Font" => dictionary! {
"MyFont" => font_id,
},
});
let pages_id = doc.new_object_id();
let content_id = doc.add_object(Stream::new(dictionary! {}, content.encode().unwrap()));
let page_id = doc.add_object(dictionary! {
"Type" => "Page",
"Parent" => pages_id,
"Contents" => content_id,
});
let pages = dictionary! {
"Type" => "Pages",
"Kids" => vec![page_id.into()],
"Count" => 1,
"Resources" => resources_id,
"MediaBox" => vec![0.into(), 0.into(), 595.into(), 842.into()],
};
doc.objects.insert(pages_id, Object::Dictionary(pages));
let catalog_id = doc.add_object(dictionary! {
"Type" => "Catalog",
"Pages" => pages_id,
});
doc.trailer.set("Root", catalog_id);
doc.compress();
// Create a resources dictionary object and add the font to it
doc.save("output.pdf").unwrap();
()
}
ClimateCrisis
UbuntuMono
It feels to me like there's a problem in the parser somewhere and it doesn't treat multi-byte characters correctly. Notice how on my screenshots the latin-extended characters are not shown correctly.
I'm completely unfamiliar with character encoding though, so I'm just guessing here.
Thanks for the external font loading code. I have the same problem with encoding regarding greek/cyrillic characters. I have realized that when you create a new pdf from scratch, the non regular characters show normally. However when editing an existing one even if it is written with fonts that support extended characters, the extra text that is added appears obfuscated.
Thanks for the external font loading code. I have the same problem with encoding regarding greek/cyrillic characters. I have realized that when you create a new pdf from scratch, the non regular characters show normally. However when editing an existing one even if it is written with fonts that support extended characters, the extra text that is added appears obfuscated.
Can you provide more detail for this issue?
I tried to add my fonts, but without success. Maybe anyone can share the way?