Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lossy image loading #1752

Open
demurgos opened this issue Jul 5, 2022 · 0 comments · May be fixed by #1753
Open

Lossy image loading #1752

demurgos opened this issue Jul 5, 2022 · 0 comments · May be fixed by #1753

Comments

@demurgos
Copy link

demurgos commented Jul 5, 2022

I would like to be able to load malformed images, such as truncated files. In particular, once the pixel buffer is allocated, return it even on error so it's possible to recover at least part of the data.

My specific use case for this functionality is to generate thumbnails for a set of files where some of them may be partially invalid (e.g. truncated).

This is more generally applicable to implement more reliable image handling. Instead of failing the whole image load, missing pixels can use a default value. The idea is to handle images similarly to browsers: they are able to display images even if they have some issues (as long as the header is valid).

Draft

The main change would be in the image::decoder_to_vec function:

 /// Reads all of the bytes of a decoder into a Vec<T>. No particular alignment
 /// of the output buffer is guaranteed.
 ///
 /// Panics if there isn't enough memory to decode the image.
 ///
+/// If an error occurs after the pixel buffer was created, it is returned. Note
+/// however that it may be incomplete. Pixels that were not read use their
+/// default "zero" value (the memory is initialized and safe to access).
-pub(crate) fn decoder_to_vec<'a, T>(decoder: impl ImageDecoder<'a>) -> ImageResult<Vec<T>>
+pub(crate) fn decoder_to_vec<'a, T>(decoder: impl ImageDecoder<'a>) -> Result<Vec<T>, (Option<Vec<T>>, ImageError)> 
 where
     T: crate::traits::Primitive + bytemuck::Pod,
 {
     let total_bytes = usize::try_from(decoder.total_bytes());
     if total_bytes.is_err() || total_bytes.unwrap() > isize::max_value() as usize {
-        return Err(ImageError::Limits(LimitError::from_kind(
-            LimitErrorKind::InsufficientMemory,
-        )));
+        return Err((None, ImageError::Limits(LimitError::from_kind(
+            LimitErrorKind::InsufficientMemory,
+        ))));
     }

     let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / std::mem::size_of::<T>()];
-    decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?;
-    Ok(buf)
+    match decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice())) {
+        Ok(()) => Ok(buf),
+        Err(e) => Err((Some(buf), e))
+    }
 }

On error, return the pixel buffer anyway and let the consumer decide what do.

It may be exposed to consumers by adding a load_lossy function, as a lenient version of load where bad pixels use their zero value (instead of failing the whole operation). This is somewhat similar to the relationship between String::from_utf8_lossy and String::from_utf8.

demurgos added a commit to demurgos/image that referenced this issue Jul 5, 2022
Add support for lossy image loading.

The new `load_lossy` function adds error recovery.

If loading reaches the step where it allocates the pixel buffer, then it always succeeds: any error following this step will result in a partially filled buffer where the missing pixels will use their default "zero" value.

This allows for example to read truncated files or other minor issues.

- Closes image-rs#1752
@demurgos demurgos linked a pull request Jul 5, 2022 that will close this issue
demurgos added a commit to demurgos/image that referenced this issue Jul 6, 2022
Add support for lossy image loading.

The new `load_lossy` function adds error recovery.

If loading reaches the step where it allocates the pixel buffer, then it always succeeds: any error following this step will result in a partially filled buffer where the missing pixels will use their default "zero" value.

This allows for example to read truncated files or other minor issues.

- Closes image-rs#1752
demurgos added a commit to demurgos/image that referenced this issue Jul 6, 2022
Add support for lossy image loading.

The new `load_lossy` function adds error recovery.

If loading reaches the step where it allocates the pixel buffer, then it always succeeds: any error following this step will result in a partially filled buffer where the missing pixels will use their default "zero" value.

This allows for example to read truncated files or other minor issues.

- Closes image-rs#1752
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant