Files
codex/codex-rs/utils/image/src/error.rs
T
Curtis 'Fjord' Hawthorne c72205239f image: add shared data URL preparation utilities (#27245)
## Summary

Add shared image-processing primitives needed for centralized image
preparation in a follow-up PR.

- Add `load_data_url_for_prompt` for decoding and preparing base64 image
data URLs.
- Add configurable maximum-dimension and 32px patch-budget resizing.
- Enforce a 1 GiB sanity limit on both encoded and decoded data-URL
representations.
- Preserve original PNG, JPEG, and WebP bytes when resizing is
unnecessary.
- Preserve the existing GIF-to-PNG behavior.
- Move image utility tests into the existing sidecar test module.

## Behavior

This PR is intended to be runtime behavior-preserving.

Existing production callers continue using
`PromptImageMode::ResizeToFit` and `PromptImageMode::Original` with
their existing semantics. The new data-URL entrypoint and configurable
resize mode have no production callers in this PR; they are used by the
next PR in the stack.

This PR does not change user-input handling, `view_image`, history
insertion, request construction, HTTP image URL forwarding, or
app-server behavior.


#### [git stack](https://github.com/magus/git-stack-cli)
- 👉 `1` https://github.com/openai/codex/pull/27245
-  `2` https://github.com/openai/codex/pull/27247
-  `3` https://github.com/openai/codex/pull/27246
-  `4` https://github.com/openai/codex/pull/27266
2026-06-10 15:27:34 -07:00

64 lines
1.7 KiB
Rust

use image::ImageError;
use image::ImageFormat;
use std::path::PathBuf;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ImageProcessingError {
#[error("failed to read image at {path}: {source}")]
Read {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to decode image at {path}: {source}")]
Decode {
path: PathBuf,
#[source]
source: image::ImageError,
},
#[error("failed to encode image as {format:?}: {source}")]
Encode {
format: ImageFormat,
#[source]
source: image::ImageError,
},
#[error("unsupported image `{mime}`")]
UnsupportedImageFormat { mime: String },
#[error("invalid image data URL: {reason}")]
InvalidDataUrl { reason: String },
#[error("image {representation} is too large ({size} bytes; max {max} bytes)")]
ImageTooLarge {
representation: &'static str,
size: usize,
max: usize,
},
}
impl ImageProcessingError {
pub fn decode_error(path: &std::path::Path, source: image::ImageError) -> Self {
if matches!(source, ImageError::Decoding(_)) {
return ImageProcessingError::Decode {
path: path.to_path_buf(),
source,
};
}
let mime = mime_guess::from_path(path)
.first()
.map(|mime_guess| mime_guess.essence_str().to_owned())
.unwrap_or_else(|| "unknown".to_string());
ImageProcessingError::UnsupportedImageFormat { mime }
}
pub fn is_invalid_image(&self) -> bool {
matches!(
self,
ImageProcessingError::Decode {
source: ImageError::Decoding(_),
..
}
)
}
}