#![allow(dead_code)]
use markdown2pdf::config::ConfigSource;
use markdown2pdf::parse_into_bytes;
pub fn render(md: &str, cfg_toml: &str) -> Vec<u8> {
parse_into_bytes(md.to_string(), ConfigSource::Embedded(cfg_toml), None)
.expect("render must succeed")
}
pub fn contains(bytes: &[u8], needle: &[u8]) -> bool {
bytes.windows(needle.len()).any(|w| w == needle)
}
pub fn count_rect_ops(bytes: &[u8]) -> usize {
let mut hits = 0usize;
let mut i = 0usize;
while i + 3 <= bytes.len() {
let prev = bytes[i];
let mid = bytes[i + 1];
let next = bytes[i + 2];
if matches!(prev, b'\n' | b'\r')
&& mid == b'f'
&& matches!(next, b'\n' | b'\r')
{
hits += 1;
i += 2;
} else {
i += 1;
}
}
hits
}
pub fn bytes_have_stroke_op(bytes: &[u8]) -> bool {
let mut i = 0usize;
while i + 2 <= bytes.len() {
let c = bytes[i];
let n = bytes[i + 1];
if (c == b' ' || c == b'\n' || c == b'\r')
&& (n == b'S' || n == b's')
&& bytes
.get(i + 2)
.map(|b| matches!(b, b'\n' | b' ' | b'\r'))
.unwrap_or(true)
{
return true;
}
i += 1;
}
false
}
pub fn multi_page_markdown(n_paragraphs: usize) -> String {
let mut out = String::new();
for i in 0..n_paragraphs {
out.push_str(&format!(
"Paragraph {} with body text long enough to take up real space on the page. {}\n\n",
i,
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. ".repeat(8)
));
}
out
}
pub fn count_substr(bytes: &[u8], needle: &[u8]) -> usize {
let mut count = 0usize;
let mut i = 0usize;
while i + needle.len() <= bytes.len() {
if &bytes[i..i + needle.len()] == needle {
count += 1;
i += needle.len();
} else {
i += 1;
}
}
count
}
pub fn pdf_well_formed(bytes: &[u8]) -> bool {
if !bytes.starts_with(b"%PDF-") {
return false;
}
let tail = &bytes[bytes.len().saturating_sub(16)..];
String::from_utf8_lossy(tail).contains("%%EOF")
}
pub fn page_count(bytes: &[u8]) -> usize {
let s = String::from_utf8_lossy(bytes);
let needle = "/Type/Page";
let mut total = 0usize;
let mut start = 0usize;
while let Some(pos) = s[start..].find(needle) {
let abs = start + pos;
let after = s.as_bytes().get(abs + needle.len()).copied();
match after {
Some(b's') => {} _ => total += 1,
}
start = abs + needle.len();
}
total
}
pub fn contains_text(bytes: &[u8], needle: &str) -> bool {
String::from_utf8_lossy(bytes).contains(needle)
}
pub fn any_system_font() -> Option<String> {
const CANDIDATES: &[&str] = &[
"Georgia",
"DejaVu Sans",
"DejaVuSans",
"Liberation Sans",
"LiberationSans",
"Noto Sans",
"NotoSans",
"Arial",
"Helvetica",
"Verdana",
"FreeSans",
];
CANDIDATES
.iter()
.find(|name| markdown2pdf::fonts::find_system_font(name).is_some())
.map(|s| s.to_string())
}
pub fn temp_jpeg_path() -> String {
use image::{DynamicImage, ImageFormat, RgbImage};
let path = std::env::temp_dir().join("m2p_test_fixture_image.jpg");
let img = DynamicImage::ImageRgb8(RgbImage::from_pixel(
1400,
900,
image::Rgb([88, 110, 150]),
));
let mut buf = Vec::new();
img.write_to(&mut std::io::Cursor::new(&mut buf), ImageFormat::Jpeg)
.expect("encode fixture jpeg");
std::fs::write(&path, buf).expect("write fixture jpeg");
path.to_string_lossy().to_string()
}