Handle more already supported image formats across the codebase (#54326)

This commit is contained in:
Kirill Bulatov authored and GitHub committed 2026-04-22 20:02:27 +03:00
1 parent 7fd07dda55
commit c92833611e
3 files changed
+40 -50

No files matched your search

+5 -1
View File
@@ -839,7 +839,11 @@ fn image_format_from_external_content(format: image::ImageFormat) -> Option<Imag
image::ImageFormat::Bmp => Some(ImageFormat::Bmp),
image::ImageFormat::Tiff => Some(ImageFormat::Tiff),
image::ImageFormat::Ico => Some(ImageFormat::Ico),
_ => None,
image::ImageFormat::Pnm => Some(ImageFormat::Pnm),
_ => {
debug_panic!("An unhandled image format: {format:?}");
None
}
}
}
+13 -9
View File
@@ -2001,17 +2001,21 @@ impl ImageFormat {
}
}
/// Returns the ImageFormat for the given mime type
/// Returns the ImageFormat for the given mime type, including known aliases.
pub fn from_mime_type(mime_type: &str) -> Option<Self> {
use strum::IntoEnumIterator;
Self::iter()
.find(|format| format.mime_type() == mime_type)
.or_else(|| Self::from_mime_type_alias(mime_type))
}
/// Non-canonical mime types that some producers use in the wild.
/// Unlike `mime_type()` which returns the single canonical form,
/// these are legacy or shortened variants we still need to recognize.
fn from_mime_type_alias(mime_type: &str) -> Option<Self> {
match mime_type {
"image/png" => Some(Self::Png),
"image/jpeg" | "image/jpg" => Some(Self::Jpeg),
"image/webp" => Some(Self::Webp),
"image/gif" => Some(Self::Gif),
"image/svg+xml" => Some(Self::Svg),
"image/bmp" => Some(Self::Bmp),
"image/tiff" | "image/tif" => Some(Self::Tiff),
"image/ico" => Some(Self::Ico),
"image/jpg" => Some(Self::Jpeg),
"image/tif" => Some(Self::Tiff),
_ => None,
}
}
+22 -40
View File
@@ -48,6 +48,7 @@ use x11rb::{
};
use gpui::{ClipboardItem, Image, ImageFormat, hash};
use strum::IntoEnumIterator;
type Result<T, E = Error> = std::result::Result<T, E>;
@@ -989,14 +990,8 @@ impl Clipboard {
self.inner.write(data, selection, wait)
}
#[allow(unused)]
pub(crate) fn set_image(
&self,
image: Image,
selection: ClipboardKind,
wait: WaitConfig,
) -> Result<()> {
let format = match image.format {
fn image_format_atom(&self, format: ImageFormat) -> Atom {
match format {
ImageFormat::Png => self.inner.atoms.PNG__MIME,
ImageFormat::Jpeg => self.inner.atoms.JPEG_MIME,
ImageFormat::Webp => self.inner.atoms.WEBP_MIME,
@@ -1006,7 +1001,17 @@ impl Clipboard {
ImageFormat::Tiff => self.inner.atoms.TIFF_MIME,
ImageFormat::Ico => self.inner.atoms.ICO__MIME,
ImageFormat::Pnm => self.inner.atoms.PNM__MIME,
};
}
}
#[allow(unused)]
pub(crate) fn set_image(
&self,
image: Image,
selection: ClipboardKind,
wait: WaitConfig,
) -> Result<()> {
let format = self.image_format_atom(image.format);
let data = vec![ClipboardData {
bytes: image.bytes,
format: self.inner.atoms.PNG__MIME,
@@ -1015,28 +1020,11 @@ impl Clipboard {
}
pub(crate) fn get_any(&self, selection: ClipboardKind) -> Result<ClipboardItem> {
const IMAGE_FORMAT_COUNT: usize = 7;
let image_format_atoms: [Atom; IMAGE_FORMAT_COUNT] = [
self.inner.atoms.PNG__MIME,
self.inner.atoms.JPEG_MIME,
self.inner.atoms.WEBP_MIME,
self.inner.atoms.GIF__MIME,
self.inner.atoms.SVG__MIME,
self.inner.atoms.BMP__MIME,
self.inner.atoms.TIFF_MIME,
];
let image_formats: [ImageFormat; IMAGE_FORMAT_COUNT] = [
ImageFormat::Png,
ImageFormat::Jpeg,
ImageFormat::Webp,
ImageFormat::Gif,
ImageFormat::Svg,
ImageFormat::Bmp,
ImageFormat::Tiff,
];
let image_entries = ImageFormat::iter()
.map(|format| (self.image_format_atom(format), format))
.collect::<Vec<_>>();
const TEXT_FORMAT_COUNT: usize = 6;
let text_format_atoms: [Atom; TEXT_FORMAT_COUNT] = [
let text_format_atoms: &[Atom] = &[
self.inner.atoms.UTF8_STRING,
self.inner.atoms.UTF8_MIME_0,
self.inner.atoms.UTF8_MIME_1,
@@ -1045,17 +1033,11 @@ impl Clipboard {
self.inner.atoms.TEXT_MIME_UNKNOWN,
];
let atom_none: Atom = AtomEnum::NONE.into();
const FORMAT_ATOM_COUNT: usize = TEXT_FORMAT_COUNT + IMAGE_FORMAT_COUNT;
let mut format_atoms: [Atom; FORMAT_ATOM_COUNT] = [atom_none; FORMAT_ATOM_COUNT];
// image formats first, as they are more specific, and read will return the first
// format that the contents can be converted to
format_atoms[0..IMAGE_FORMAT_COUNT].copy_from_slice(&image_format_atoms);
format_atoms[IMAGE_FORMAT_COUNT..].copy_from_slice(&text_format_atoms);
debug_assert!(!format_atoms.contains(&atom_none));
let mut format_atoms = Vec::with_capacity(image_entries.len() + text_format_atoms.len());
format_atoms.extend(image_entries.iter().map(|(atom, _)| *atom));
format_atoms.extend_from_slice(text_format_atoms);
let result = self.inner.read(&format_atoms, selection)?;
@@ -1064,7 +1046,7 @@ impl Clipboard {
self.inner.atom_name(result.format)
);
for (format_atom, image_format) in image_format_atoms.into_iter().zip(image_formats) {
for (format_atom, image_format) in image_entries {
if result.format == format_atom {
let bytes = result.bytes;
let id = hash(&bytes);