Path: blob/main/crates/bevy_image/src/serialized_image.rs
6595 views
use crate::{Image, ImageSampler};1use bevy_asset::RenderAssetUsages;2use core::fmt::Debug;3use serde::{Deserialize, Serialize};4use wgpu_types::{5TextureAspect, TextureDataOrder, TextureDescriptor, TextureFormat, TextureUsages,6TextureViewDescriptor, TextureViewDimension,7};89/// A version of [`Image`] suitable for serializing for short-term transfer.10///11/// [`Image`] does not implement [`Serialize`] / [`Deserialize`] because it is made with the renderer in mind.12/// It is not a general-purpose image implementation, and its internals are subject to frequent change.13/// As such, storing an [`Image`] on disk is highly discouraged.14/// Use an existing image asset format such as `.png` instead!15///16/// But there are still some valid use cases for serializing an [`Image`], namely transferring images between processes.17/// To support this, you can create a [`SerializedImage`] from an [`Image`] with [`SerializedImage::from_image`],18/// and then deserialize it with [`SerializedImage::into_image`].19///20/// The caveats are:21/// - The image representation is not valid across different versions of Bevy.22/// - This conversion is lossy. The following information is not preserved:23/// - texture descriptor and texture view descriptor labels24/// - texture descriptor view formats25#[derive(Debug, Clone, Serialize, Deserialize)]26pub struct SerializedImage {27data: Option<Vec<u8>>,28data_order: SerializedTextureDataOrder,29texture_descriptor: TextureDescriptor<(), ()>,30sampler: ImageSampler,31texture_view_descriptor: Option<SerializedTextureViewDescriptor>,32}3334#[derive(Debug, Clone, Serialize, Deserialize)]35struct SerializedTextureViewDescriptor {36format: Option<TextureFormat>,37dimension: Option<TextureViewDimension>,38usage: Option<TextureUsages>,39aspect: TextureAspect,40base_mip_level: u32,41mip_level_count: Option<u32>,42base_array_layer: u32,43array_layer_count: Option<u32>,44}4546impl SerializedTextureViewDescriptor {47fn from_texture_view_descriptor(48descriptor: TextureViewDescriptor<Option<&'static str>>,49) -> Self {50Self {51format: descriptor.format,52dimension: descriptor.dimension,53usage: descriptor.usage,54aspect: descriptor.aspect,55base_mip_level: descriptor.base_mip_level,56mip_level_count: descriptor.mip_level_count,57base_array_layer: descriptor.base_array_layer,58array_layer_count: descriptor.array_layer_count,59}60}6162fn into_texture_view_descriptor(self) -> TextureViewDescriptor<Option<&'static str>> {63TextureViewDescriptor {64// Not used for asset-based images other than debugging65label: None,66format: self.format,67dimension: self.dimension,68usage: self.usage,69aspect: self.aspect,70base_mip_level: self.base_mip_level,71mip_level_count: self.mip_level_count,72base_array_layer: self.base_array_layer,73array_layer_count: self.array_layer_count,74}75}76}7778#[derive(Debug, Clone, Serialize, Deserialize)]79enum SerializedTextureDataOrder {80LayerMajor,81MipMajor,82}8384impl SerializedTextureDataOrder {85fn from_texture_data_order(order: TextureDataOrder) -> Self {86match order {87TextureDataOrder::LayerMajor => SerializedTextureDataOrder::LayerMajor,88TextureDataOrder::MipMajor => SerializedTextureDataOrder::MipMajor,89}90}9192fn into_texture_data_order(self) -> TextureDataOrder {93match self {94SerializedTextureDataOrder::LayerMajor => TextureDataOrder::LayerMajor,95SerializedTextureDataOrder::MipMajor => TextureDataOrder::MipMajor,96}97}98}99100impl SerializedImage {101/// Creates a new [`SerializedImage`] from an [`Image`].102pub fn from_image(image: Image) -> Self {103Self {104data: image.data,105data_order: SerializedTextureDataOrder::from_texture_data_order(image.data_order),106texture_descriptor: TextureDescriptor {107label: (),108size: image.texture_descriptor.size,109mip_level_count: image.texture_descriptor.mip_level_count,110sample_count: image.texture_descriptor.sample_count,111dimension: image.texture_descriptor.dimension,112format: image.texture_descriptor.format,113usage: image.texture_descriptor.usage,114view_formats: (),115},116sampler: image.sampler,117texture_view_descriptor: image.texture_view_descriptor.map(|descriptor| {118SerializedTextureViewDescriptor::from_texture_view_descriptor(descriptor)119}),120}121}122123/// Create an [`Image`] from a [`SerializedImage`].124pub fn into_image(self) -> Image {125Image {126data: self.data,127data_order: self.data_order.into_texture_data_order(),128texture_descriptor: TextureDescriptor {129// Not used for asset-based images other than debugging130label: None,131size: self.texture_descriptor.size,132mip_level_count: self.texture_descriptor.mip_level_count,133sample_count: self.texture_descriptor.sample_count,134dimension: self.texture_descriptor.dimension,135format: self.texture_descriptor.format,136usage: self.texture_descriptor.usage,137// Not used for asset-based images138view_formats: &[],139},140sampler: self.sampler,141texture_view_descriptor: self142.texture_view_descriptor143.map(SerializedTextureViewDescriptor::into_texture_view_descriptor),144asset_usage: RenderAssetUsages::RENDER_WORLD,145copy_on_resize: false,146}147}148}149150#[cfg(test)]151mod tests {152use wgpu_types::{Extent3d, TextureDimension};153154use super::*;155156#[test]157fn serialize_deserialize_image() {158let image = Image::new(159Extent3d {160width: 3,161height: 1,162depth_or_array_layers: 1,163},164TextureDimension::D2,165vec![255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255],166TextureFormat::Rgba8UnormSrgb,167RenderAssetUsages::RENDER_WORLD,168);169170let serialized_image = SerializedImage::from_image(image.clone());171let serialized_string = serde_json::to_string(&serialized_image).unwrap();172let serialized_image_from_string: SerializedImage =173serde_json::from_str(&serialized_string).unwrap();174let deserialized_image = serialized_image_from_string.into_image();175assert_eq!(image, deserialized_image);176}177}178179180