Repository: image-rs/image (language: rust)

Issue:
Add serde support for image::ImageFormat
<!-- Please fill out the relevant sections below, and delete all that do not apply: -->

I would like to be able to store the format of an image in a metadata database and send them between systems in a natively serialized way and not as strings.

My specific use case for this functionality is a photo system which automatically transforms images into multiple formats using a task queue which gets processed by another service. Each task contains the target size and format and for this I need to serialize the format so it can be send to the processing service.
Right now this is possible by using a mime type string, but that makes the API not as nice to use and makes the API partly "stringly typed".

At the moment creating and reading a task looks something like this:

```rust
manager.push_task(Task {
  original_s3_path: source_path,
  target_s3_path: target_path,
  target_format_mime_type: format.to_mime_type(),
  target_max_size: Size::Width(1000),
});

// Sometime later

let task = manager.pop_task();
let format = ImageFormat::from_mime_type(task.target_format_mime_type);
```

## Draft

<!-- Can you show a possible way to provide this functionality? Consider that a good
draft drastically reduces mental overhead, gives context, and overall makes it
much more likely to be implemented. The draft does not need to be an actual
implementation but should provide a starting point for discussion. -->

(Optionally/feature gated) implementing `serde::Deserialize` and `serde::Serialize` on ImageFormat would allow to use serde on structs/enums that contain an ImageFormat. The implementation could use the mime type internally. Same could be useful for ColorType enums.
Add serde support for image::ImageFormat
<!-- Please fill out the relevant sections below, and delete all that do not apply: -->

I would like to be able to store the format of an image in a metadata database and send them between systems in a natively serialized way and not as strings.

My specific use case for this functionality is a photo system which automatically transforms images into multiple formats using a task queue which gets processed by another service. Each task contains the target size and format and for this I need to serialize the format so it can be send to the processing service.
Right now this is possible by using a mime type string, but that makes the API not as nice to use and makes the API partly "stringly typed".

At the moment creating and reading a task looks something like this:

```rust
manager.push_task(Task {
  original_s3_path: source_path,
  target_s3_path: target_path,
  target_format_mime_type: format.to_mime_type(),
  target_max_size: Size::Width(1000),
});

// Sometime later

let task = manager.pop_task();
let format = ImageFormat::from_mime_type(task.target_format_mime_type);
```

## Draft

<!-- Can you show a possible way to provide this functionality? Consider that a good
draft drastically reduces mental overhead, gives context, and overall makes it
much more likely to be implemented. The draft does not need to be an actual
implementation but should provide a starting point for discussion. -->

(Optionally/feature gated) implementing `serde::Deserialize` and `serde::Serialize` on ImageFormat would allow to use serde on structs/enums that contain an ImageFormat. The implementation could use the mime type internally. Same could be useful for ColorType enums.


Discussion / hints:
I think we could derive Serialize/Deserialize for these types. Though, it would require placing the derive within a `cfg_attr` so it was only enabled when serde a serde feature was on.

The enums are marked non-exhaustive which I don't think matters, but I could be wrong?
I think something like this should work:
```rust
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
```

As far as I'm aware it doesn't matter if an enum is non-exhaustive.
I think we could derive Serialize/Deserialize for these types. Though, it would require placing the derive within a `cfg_attr` so it was only enabled when serde a serde feature was on.

The enums are marked non-exhaustive which I don't think matters, but I could be wrong?
I think something like this should work:
```rust
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
```

As far as I'm aware it doesn't matter if an enum is non-exhaustive.

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index 7cd5fbdf60..90c01e7e5b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -56,6 +56,7 @@ rgb = { version = "0.8.48", default-features = false, optional = true }
 tiff = { version = "0.9.0", optional = true }
 zune-core = { version = "0.4.12", default-features = false, optional = true }
 zune-jpeg = { version = "0.4.13", optional = true }
+serde = { version = "1.0.214", optional = true, features = ["derive"] }
 
 [dev-dependencies]
 crc32fast = "1.2.0"
@@ -92,6 +93,7 @@ nasm = ["ravif?/asm"] # Enables use of nasm by rav1e (requires nasm to be instal
 color_quant = ["dep:color_quant"] # Enables color quantization
 avif-native = ["dep:mp4parse", "dep:dcv-color-primitives", "dep:dav1d"] # Enable native dependency libdav1d
 benchmarks = [] # Build some inline benchmarks. Useful only during development (requires nightly Rust)
+serde = ["dep:serde"]
 
 [[bench]]
 path = "benches/decode.rs"
diff --git a/src/image.rs b/src/image.rs
index 81aebbd083..b150e41519 100644
--- a/src/image.rs
+++ b/src/image.rs
@@ -5,6 +5,9 @@ use std::mem::size_of;
 use std::ops::{Deref, DerefMut};
 use std::path::Path;
 
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Serialize};
+
 use crate::color::{ColorType, ExtendedColorType};
 use crate::error::{
     ImageError, ImageFormatHint, ImageResult, LimitError, LimitErrorKind, ParameterError,
@@ -20,6 +23,7 @@ use crate::animation::Frames;
 /// An enumeration of supported image formats.
 /// Not all formats support both encoding and decoding.
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
+#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
 #[non_exhaustive]
 pub enum ImageFormat {
     /// An Image in PNG Format


Test patch: