Generate actual images

This commit is contained in:
torbjornmolin
2025-09-27 18:56:32 +02:00
parent 0692ba3b97
commit c2736613a9
4 changed files with 1230 additions and 33 deletions

1186
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,9 @@ edition = "2024"
[dependencies]
axum = "0.8.4"
bytes = "1"
image = "0.25.8"
serde = { version = "1.0.227", features = ["derive"] }
text-to-png = "0.2.0"
tokio = { version = "1.47.1", features = ["fs", "rt-multi-thread"] }
tokio-util = { version = "0.7.16", features = ["io"] }
tower-http = { version = "0.6.6", features = ["fs", "trace"] }

View File

@@ -233,7 +233,8 @@
const formData = {
count: parseInt(form.count.value),
dimensions: `${form.width.value}x${form.height.value}`,
width: Number(form.width.value),
height: Number(form.height.value),
filenames: form.filenames.value
.trim()
.split("\n")

View File

@@ -1,12 +1,12 @@
use std::io::{Cursor, Write};
use axum::{
Json, Router,
body::Body,
http::{Response, StatusCode, header},
routing::post,
};
use image::{GenericImage, GenericImageView};
use serde::Deserialize;
use std::io::{Cursor, Write};
use tower_http::services::ServeFile;
#[tokio::main]
async fn main() {
@@ -29,41 +29,34 @@ async fn main() {
pub struct GenerateOptions {
count: u32,
filenames: Vec<String>,
width: u32,
height: u32,
}
async fn download_zip(Json(payload): Json<GenerateOptions>) -> Response<Body> {
println!(
"Count: {}.\nFiles: ' [ {} ]'",
"Count: {}. w: {}, h: {}, \nFiles: ' [ {} ]'",
payload.count,
payload.width,
payload.height,
payload.filenames.join(",")
);
// Example: Simulate multiple files in memory
let files: Vec<(&str, &[u8])> = vec![
("hello.txt", b"Hello, world!"),
("readme.md", b"# README\nThis is a test."),
("data.json", br#"{"key": "value"}"#),
];
// Create a buffer to hold the ZIP file in memory
let files = get_files(payload);
let mut buffer = Cursor::new(Vec::new());
{
// Create ZIP writer over the buffer
let mut zip = zip::ZipWriter::new(&mut buffer);
let mut zip = zip::ZipWriter::new(&mut buffer);
let options = zip::write::SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Stored)
.unix_permissions(0o644);
let options = zip::write::SimpleFileOptions::default()
.compression_method(zip::CompressionMethod::Stored)
.unix_permissions(0o644);
for (filename, contents) in files {
zip.start_file(filename, options).unwrap();
zip.write_all(contents).unwrap();
}
zip.finish().unwrap();
for (filename, contents) in files {
zip.start_file(filename, options).unwrap();
zip.write_all(&contents).unwrap();
}
zip.finish().unwrap();
let zip_bytes = buffer.into_inner();
Response::builder()
@@ -76,3 +69,34 @@ async fn download_zip(Json(payload): Json<GenerateOptions>) -> Response<Body> {
.body(Body::from(zip_bytes))
.unwrap()
}
fn get_files(options: GenerateOptions) -> Vec<(String, Vec<u8>)> {
let mut files: Vec<(String, Vec<u8>)> = Vec::new();
use text_to_png::TextRenderer;
let renderer = TextRenderer::default();
for f in options.filenames {
let mut imgbuf = image::ImageBuffer::new(options.width, options.height);
for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
*pixel = image::Rgba([255, 0, 2, 255]);
}
let textpngdata = renderer
.render_text_to_png_data(&f, 64, "Dark Turquoise")
.unwrap();
let other = image::ImageReader::new(Cursor::new(textpngdata.data))
.with_guessed_format()
.unwrap()
.decode()
.unwrap();
imgbuf.copy_from(&other, 0, 0).unwrap();
let mut buf = Cursor::new(Vec::new());
imgbuf.write_to(&mut buf, image::ImageFormat::Png).unwrap();
files.push((String::from(format!("{}.png", f)), buf.into_inner()));
}
files
}