Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 32 additions & 12 deletions ui-crates/ui_fab_search/src/image_loader.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
//! Background image downloader for asset thumbnails and gallery images.
//!
//! Downloads image bytes via reqwest, decodes them into a BGRA8 `image::Frame`,
//! Downloads image bytes via reqwest, decodes them into an RGBA8 `image::Frame`,
//! and wraps the result in a `gpui::RenderImage`.

use std::sync::Arc;
use gpui::RenderImage;
use image::RgbaImage;
use std::sync::Arc;

fn decode_image_bytes(bytes: &[u8]) -> Result<RgbaImage, String> {
image::load_from_memory(bytes)
.map_err(|e| format!("image decode: {e}"))
.map(|image| image.into_rgba8())
}

/// Download `url` and decode it into a `RenderImage` ready for
/// `ImageSource::Render`. Always called from an OS thread.
Expand Down Expand Up @@ -36,16 +43,29 @@ pub fn fetch_and_decode(url: &str) -> Result<Arc<RenderImage>, String> {
.map_err(|e: reqwest::Error| e.to_string())
})?;

// Decode to RGBA8
let mut rgba = image::load_from_memory(&bytes)
.map_err(|e| format!("image decode: {e}"))?
.into_rgba8();

// GPUI expects BGRA8, so swap R and B channels in-place.
for pixel in rgba.chunks_exact_mut(4) {
pixel.swap(0, 2);
}

let rgba = decode_image_bytes(&bytes)?;
let frame = image::Frame::new(rgba);
Ok(Arc::new(RenderImage::new(smallvec::smallvec![frame])))
}

#[cfg(test)]
mod tests {
use super::decode_image_bytes;

#[test]
fn decode_image_bytes_preserves_rgba_channel_order() {
let source = image::RgbaImage::from_raw(1, 1, vec![0x12, 0x34, 0x56, 0x78]).unwrap();
let dynamic = image::DynamicImage::ImageRgba8(source);

let mut bytes = Vec::new();
dynamic
.write_to(
&mut std::io::Cursor::new(&mut bytes),
image::ImageFormat::Png,
)
.unwrap();

let decoded = decode_image_bytes(&bytes).unwrap();
assert_eq!(decoded.as_raw(), &[0x12, 0x34, 0x56, 0x78]);
}
}