Skip to content

Commit

Permalink
Compress image to fit in Bluesky size limit
Browse files Browse the repository at this point in the history
  • Loading branch information
rgwood committed Jan 4, 2025
1 parent 45739e8 commit 5c5a9b2
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ publish/*
/target
.aider*
.env

resized.jpg
69 changes: 68 additions & 1 deletion src/bluesky.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{num::NonZero, vec};

use anyhow::{Context, Result};
use anyhow::{bail, Context, Result};
use atrium_api::{
app::bsky::{
embed::{
Expand All @@ -12,9 +12,13 @@ use atrium_api::{
types::Union,
};
use bsky_sdk::{rich_text::RichText, BskyAgent};
use image::codecs::jpeg::JpegEncoder;

use crate::models::Project;

// Hard limit on image size to post to Bluesky
const MAX_IMAGE_SIZE_BYTES: usize = 1_000_000;

pub async fn post_to_bluesky(
project: &Project,
tweet_text: &str,
Expand All @@ -34,6 +38,8 @@ pub async fn post_to_bluesky(
let img_bytes = reqwest::get(img_url).await?.bytes().await?;
eprintln!("Downloaded image: {}", img_url);

let img_bytes = compress_image_until_under_size(&img_bytes)?;

let img = image::load_from_memory(&img_bytes)?;
let height = NonZero::new(img.height() as u64).context("Image height is zero")?;
let width = NonZero::new(img.width() as u64).context("Image width is zero")?;
Expand Down Expand Up @@ -90,3 +96,64 @@ pub async fn post_to_bluesky(

Ok(())
}

fn compress_image_until_under_size(img: &[u8]) -> Result<Vec<u8>> {
if img.len() < MAX_IMAGE_SIZE_BYTES {
return Ok(img.to_vec());
}

let img = image::load_from_memory(img)?;
let mut buffer = vec![];
let mut quality = 90;

loop {
buffer.clear();

JpegEncoder::new_with_quality(&mut buffer, quality).encode_image(&img)?;

eprintln!(
"Resized image (quality: {}) size: {}b",
quality,
buffer.len()
);

if buffer.len() < MAX_IMAGE_SIZE_BYTES {
return Ok(buffer);
}

quality = quality.saturating_sub(5);

if quality == 0 {
break;
}
}

bail!(
"Failed to compress image to under {}b",
MAX_IMAGE_SIZE_BYTES
)
}

#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;

#[test]
fn resize_image() {
let img_bytes = include_bytes!("../test_files/too_big.jpg");

eprintln!("Image size: {}b", img_bytes.len());

assert!(img_bytes.len() > MAX_IMAGE_SIZE_BYTES);

let buffer = compress_image_until_under_size(img_bytes).unwrap();
eprintln!("Resized image size: {}b", buffer.len());

// write buffer to disk as resized.jpg
let mut file = std::fs::File::create("resized.jpg").unwrap();
file.write_all(buffer.as_slice()).unwrap();

// todo!()
}
}
Binary file added test_files/too_big.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5c5a9b2

Please sign in to comment.