Skip to content

Commit

Permalink
Allow multiple pages
Browse files Browse the repository at this point in the history
  • Loading branch information
mattfbacon committed Mar 27, 2024
1 parent ea03545 commit 6ee37f3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 35 deletions.
20 changes: 14 additions & 6 deletions bot/src/bot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,14 +324,17 @@ async fn render(

match res {
Ok(res) => {
let image = CreateAttachment::bytes(res.image, "rendered.png");
let mut message = CreateReply::default().attachment(image).reply(true);
let mut message = CreateReply::default().reply(true);

let mut content = String::new();

if let Some(more_pages) = res.more_pages {
let more_pages = more_pages.get();
write!(
if res.images.is_empty() {
writeln!(content, "Note: no pages generated").unwrap();
}

if res.more_pages > 0 {
let more_pages = res.more_pages;
writeln!(
content,
"Note: {more_pages} more page{s} ignored",
s = if more_pages == 1 { "" } else { "s" },
Expand All @@ -340,7 +343,7 @@ async fn render(
}

if !res.warnings.is_empty() {
write!(
writeln!(
content,
"Render succeeded with warnings:\n```ansi\n{}\n```",
sanitize_code_block(&res.warnings),
Expand All @@ -352,6 +355,11 @@ async fn render(
message = message.content(content);
}

for (i, image) in res.images.into_iter().enumerate() {
let image = CreateAttachment::bytes(image, format!("page-{}.png", i + 1));
message = message.attachment(image);
}

ctx.send(message).await?;
}
Err(error) => {
Expand Down
6 changes: 2 additions & 4 deletions protocol/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::num::NonZeroUsize;

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand All @@ -11,8 +9,8 @@ pub enum Request {

#[derive(Debug, Serialize, Deserialize)]
pub struct Rendered {
pub image: Vec<u8>,
pub more_pages: Option<NonZeroUsize>,
pub images: Vec<Vec<u8>>,
pub more_pages: usize,
pub warnings: String,
}

Expand Down
65 changes: 40 additions & 25 deletions worker/src/render.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use std::io::Cursor;
use std::num::NonZeroUsize;

use protocol::Rendered;
use typst::eval::Tracer;
Expand Down Expand Up @@ -50,6 +49,9 @@ fn to_string(v: impl ToString) -> String {
v.to_string()
}

const PAGE_LIMIT: usize = 5;
const BYTES_LIMIT: usize = 25 * 1024 * 1024;

pub fn render(sandbox: &Sandbox, source: String) -> Result<Rendered, String> {
let world = sandbox.with_source(source);

Expand All @@ -58,34 +60,47 @@ pub fn render(sandbox: &Sandbox, source: String) -> Result<Rendered, String> {
typst::compile(&world, &mut tracer).map_err(|diags| format_diagnostics(&world, &diags))?;
let warnings = tracer.warnings();

let frame = &document
let transparent = Color::from_u8(0, 0, 0, 0);
let mut total_attachment_size = 0;

let images = document
.pages
.first()
.ok_or("no pages in rendered output")?
.frame;
let more_pages = NonZeroUsize::new(document.pages.len().saturating_sub(1));
.iter()
.take(PAGE_LIMIT)
.map(|page| {
let frame = &page.frame;
let pixels_per_point = determine_pixels_per_point(frame.size()).map_err(to_string)?;
let pixmap = typst_render::render(frame, pixels_per_point, transparent);

let mut writer = Cursor::new(Vec::new());

// The unwrap will never fail since `Vec`'s `Write` implementation is infallible.
image::write_buffer_with_format(
&mut writer,
bytemuck::cast_slice(pixmap.pixels()),
pixmap.width(),
pixmap.height(),
image::ColorType::Rgba8,
image::ImageFormat::Png,
)
.unwrap();

Ok(writer.into_inner())
})
.take_while(|image| {
if let Ok(image) = image {
total_attachment_size += image.len();
total_attachment_size <= BYTES_LIMIT
} else {
true
}
})
.collect::<Result<Vec<_>, String>>()?;

let pixels_per_point = determine_pixels_per_point(frame.size()).map_err(to_string)?;
let more_pages = document.pages.len() - images.len();

let transparent = Color::from_u8(0, 0, 0, 0);
let pixmap = typst_render::render(frame, pixels_per_point, transparent);

let mut writer = Cursor::new(Vec::new());

// The unwrap will never fail since `Vec`'s `Write` implementation is infallible.
image::write_buffer_with_format(
&mut writer,
bytemuck::cast_slice(pixmap.pixels()),
pixmap.width(),
pixmap.height(),
image::ColorType::Rgba8,
image::ImageFormat::Png,
)
.unwrap();

let image = writer.into_inner();
Ok(Rendered {
image,
images,
more_pages,
warnings: format_diagnostics(&world, &warnings),
})
Expand Down

0 comments on commit 6ee37f3

Please sign in to comment.