#!/bin/bash echo "๐Ÿš€ SETTING UP WEBP CONVERSION" echo "=============================" # Step 1: Add dependencies echo "๐Ÿ“ฆ Adding WebP dependencies to Cargo.toml..." if grep -q 'image = ' Cargo.toml; then echo "โœ… image dependency already exists" else echo 'image = "0.24"' >> Cargo.toml echo "โœ… Added image dependency" fi if grep -q 'webp = ' Cargo.toml; then echo "โœ… webp dependency already exists" else echo 'webp = "0.2"' >> Cargo.toml echo "โœ… Added webp dependency" fi # Step 2: Create utils directory if it doesn't exist echo "๐Ÿ“ Creating utils directory..." mkdir -p src/utils # Step 3: Create the WebP conversion module echo "๐Ÿ”ง Creating WebP conversion module..." cat > src/utils/images.rs << 'EOF' use image::ImageFormat; use std::io::Cursor; pub async fn convert_to_webp(image_bytes: &[u8]) -> Result, String> { let bytes = image_bytes.to_vec(); tokio::task::spawn_blocking(move || { let img = image::load_from_memory(&bytes) .map_err(|e| format!("Failed to load image: {}", e))?; // Resize if too large (optional optimization) let img = if img.width() > 1920 || img.height() > 1920 { img.resize(1920, 1920, image::imageops::FilterType::Lanczos3) } else { img }; let rgb_img = img.to_rgb8(); let encoder = webp::Encoder::from_rgb(&rgb_img, img.width(), img.height()); let webp = encoder.encode(85.0); // 85% quality Ok(webp.to_vec()) }) .await .map_err(|e| format!("Task failed: {}", e))? } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn test_webp_conversion() { // Create a simple 100x100 red image let img = image::RgbImage::from_fn(100, 100, |_, _| image::Rgb([255, 0, 0])); let mut buffer = Vec::new(); // Encode as PNG first { let mut cursor = Cursor::new(&mut buffer); image::DynamicImage::ImageRgb8(img) .write_to(&mut cursor, ImageFormat::Png) .expect("Failed to write PNG"); } // Convert to WebP let webp_data = convert_to_webp(&buffer).await.expect("WebP conversion failed"); // Verify it's actually WebP data assert!(webp_data.len() > 0); assert!(webp_data.starts_with(b"RIFF")); // WebP signature println!("โœ… WebP conversion test passed!"); println!(" Original PNG: {} bytes", buffer.len()); println!(" WebP result: {} bytes", webp_data.len()); println!(" Compression: {:.1}%", (1.0 - webp_data.len() as f64 / buffer.len() as f64) * 100.0); } #[tokio::test] async fn test_invalid_image() { let fake_data = b"not an image"; let result = convert_to_webp(fake_data).await; assert!(result.is_err()); println!("โœ… Invalid image test passed!"); } } EOF echo "โœ… Created src/utils/images.rs" # Step 4: Update or create utils mod.rs if [ -f src/utils/mod.rs ]; then echo "๐Ÿ“ Updating src/utils/mod.rs..." if ! grep -q "pub mod images;" src/utils/mod.rs; then echo "pub mod images;" >> src/utils/mod.rs fi else echo "๐Ÿ“ Creating src/utils/mod.rs..." echo "pub mod images;" > src/utils/mod.rs fi echo "โœ… Updated utils module" # Step 5: Update main.rs or lib.rs to include utils echo "๐Ÿ“ Checking for utils module inclusion..." main_file="" if [ -f src/main.rs ]; then main_file="src/main.rs" elif [ -f src/lib.rs ]; then main_file="src/lib.rs" fi if [ -n "$main_file" ]; then if ! grep -q "mod utils;" "$main_file"; then echo "mod utils;" >> "$main_file" echo "โœ… Added utils module to $main_file" else echo "โœ… Utils module already included in $main_file" fi else echo "โš ๏ธ Couldn't find main.rs or lib.rs - you'll need to add 'mod utils;' manually" fi # Step 6: Build to check for errors echo "๐Ÿ”จ Building project to verify setup..." if cargo build; then echo "โœ… Build successful!" else echo "โŒ Build failed - check the errors above" exit 1 fi # Step 7: Run tests echo "๐Ÿงช Running WebP conversion tests..." if cargo test images::tests -- --nocapture; then echo "โœ… All tests passed!" else echo "โŒ Tests failed" exit 1 fi # Step 8: Create example usage echo "๐Ÿ“„ Creating example usage file..." cat > webp_example.rs << 'EOF' // Example usage in your upload handler: use crate::utils::images::convert_to_webp; pub async fn handle_image_upload(image_data: Vec) -> Result { // Save original let original_path = format!("uploads/original_{}.jpg", uuid::Uuid::new_v4()); tokio::fs::write(&original_path, &image_data).await .map_err(|e| format!("Failed to save original: {}", e))?; // Convert to WebP let webp_data = convert_to_webp(&image_data).await?; let webp_path = format!("uploads/webp_{}.webp", uuid::Uuid::new_v4()); tokio::fs::write(&webp_data, webp_data).await .map_err(|e| format!("Failed to save WebP: {}", e))?; Ok(webp_path) } // Or for immediate conversion (slower but simpler): pub async fn convert_and_save_webp(image_data: Vec, filename: &str) -> Result { let webp_data = convert_to_webp(&image_data).await?; let webp_path = format!("uploads/{}.webp", filename); tokio::fs::write(&webp_path, webp_data).await .map_err(|e| format!("Failed to save: {}", e))?; Ok(webp_path) } EOF echo "โœ… Created webp_example.rs" echo "" echo "๐ŸŽ‰ WEBP CONVERSION SETUP COMPLETE!" echo "==================================" echo "โœ… Dependencies added to Cargo.toml" echo "โœ… WebP conversion module created" echo "โœ… Tests written and passing" echo "โœ… Example usage provided" echo "" echo "๐Ÿ”ง Next steps:" echo "1. Import in your upload handler: use crate::utils::images::convert_to_webp;" echo "2. Call convert_to_webp(&image_bytes).await in your code" echo "3. Save the returned Vec as a .webp file"