libdnrs: avoid data copies

This commit is contained in:
p
2026-09-28 21:26:28 +02:00
parent 98d3005469
commit ed43b467b0
2 changed files with 22 additions and 15 deletions
+11 -14
View File
@@ -747,29 +747,28 @@ fn decode_raw(
}
fn decode_image(
data: Vec<u8>,
data: &[u8],
first_frame_only: bool,
) -> Result<dnrs_decoder, String> {
image_extras::register();
if let Ok(format) = image::guess_format(&data) {
return decode_image_rs(&data, format, first_frame_only);
if let Ok(format) = image::guess_format(data) {
return decode_image_rs(data, format, first_frame_only);
}
#[cfg(feature = "jpeg2000")]
if data.starts_with(&[0xff, 0x4f, 0xff, 0x51])
|| data.starts_with(&[0, 0, 0, 12, b'j', b'P', b' ', b' '])
{
return decode_jpeg2000(&data);
return decode_jpeg2000(data);
}
if let Ok(decoder) =
image::codecs::tga::TgaDecoder::new(Cursor::new(data.as_slice()))
if let Ok(decoder) = image::codecs::tga::TgaDecoder::new(Cursor::new(data))
{
return decoder_from_still("image-rs/Tga", decoder);
}
// XPM registers a signature with image, while XBM is C source with no
// magic number and has to be tried explicitly.
if let Ok(reader) =
ImageReader::new(Cursor::new(data.as_slice())).with_guessed_format()
ImageReader::new(Cursor::new(data)).with_guessed_format()
{
if let Ok((frame, metadata)) = decode_still(reader) {
return decoder_from_frames(
@@ -780,13 +779,11 @@ fn decode_image(
);
}
}
if let Ok(decoder) =
image_extras::xbm::XbmDecoder::new(Cursor::new(data.as_slice()))
{
if let Ok(decoder) = image_extras::xbm::XbmDecoder::new(Cursor::new(data)) {
return decoder_from_still("image-extras/XBM", decoder);
}
#[cfg(feature = "raw")]
if let Ok(rawfile) = libopenraw::rawfile_from_memory(data, None) {
if let Ok(rawfile) = libopenraw::rawfile_from_memory(data.to_vec(), None) {
return decode_raw(&rawfile);
}
Err("unrecognised image data".into())
@@ -903,10 +900,10 @@ pub unsafe extern "C" fn dnrs_decoder_new(
if length > isize::MAX as usize {
return Err("input is too large".into());
}
let input = if length == 0 {
Vec::new()
let input: &[u8] = if length == 0 {
&[]
} else {
unsafe { std::slice::from_raw_parts(data, length) }.to_vec()
unsafe { std::slice::from_raw_parts(data, length) }
};
decode_image(input, first_frame_only)
.map(|decoder| Box::into_raw(Box::new(decoder)))
+11 -1
View File
@@ -43,7 +43,7 @@ enum dnrs_pixel_format {
};
struct dnrs_document_info {
const char *codec;
const char *codec; ///< Borrowed from the decoder.
uint32_t page_count;
};
@@ -62,6 +62,8 @@ struct dnrs_page_info {
size_t text_length;
};
// Pixel data is owned by the caller, and released by dnrs_frame_clear(),
// which also accepts a zero-initialized frame.
struct dnrs_frame {
uint32_t width;
uint32_t height;
@@ -73,16 +75,24 @@ struct dnrs_frame {
};
const char *const *dnrs_mime_types(size_t *length);
// Decodes everything at once, so the input is only needed during the call.
// Functions that fail return false or NULL, and set any non-NULL `error`,
// which must then be freed with dnrs_error_free(). They reset it on success.
struct dnrs_decoder *dnrs_decoder_new(const uint8_t *data, size_t length,
bool first_frame_only, struct dnrs_error **error);
bool dnrs_decoder_get_info(const struct dnrs_decoder *decoder,
struct dnrs_document_info *info, struct dnrs_error **error);
// Iteration only moves forward. False without an error means exhaustion.
// Frames are those of the current page, which next_page() must select first.
bool dnrs_decoder_next_page(struct dnrs_decoder *decoder,
struct dnrs_page_info *page, struct dnrs_error **error);
// Overwrites `frame`, which must be cleared first if it holds pixels.
bool dnrs_decoder_next_frame(struct dnrs_decoder *decoder,
struct dnrs_frame *frame, struct dnrs_error **error);
const char *dnrs_error_message(const struct dnrs_error *error);
void dnrs_frame_clear(struct dnrs_frame *frame);
// Invalidates everything borrowed from it, but not frames already returned.
void dnrs_decoder_free(struct dnrs_decoder *decoder);
void dnrs_error_free(struct dnrs_error *error);