use alloc::vec::Vec;
use crate::allocation::checked_add_allocation_bytes;
use super::super::{
additional_decode_scratch_bytes, allocate_output_buffer_with_live_budget,
checked_output_geometry, output_format_from_parts, scaled_dimensions, scaled_rect_covering,
DecodeOutcome, DecodeRequest, Decoder, JpegError, Rect, ScratchPool, DEFAULT_SCRATCH,
};
impl Decoder<'_> {
pub fn decode_request(
&self,
request: DecodeRequest,
) -> Result<(Vec<u8>, DecodeOutcome), JpegError> {
self.decode_request_with_external_live(request, 0)
}
#[doc(hidden)]
pub fn decode_request_with_external_live(
&self,
request: DecodeRequest,
external_live_bytes: usize,
) -> Result<(Vec<u8>, DecodeOutcome), JpegError> {
DEFAULT_SCRATCH.with(|pool| {
self.decode_request_with_scratch_and_external_live(
&mut pool.borrow_mut(),
request,
external_live_bytes,
)
})
}
#[doc(hidden)]
pub fn decode_request_with_scratch_and_external_live(
&self,
pool: &mut ScratchPool,
request: DecodeRequest,
external_live_bytes: usize,
) -> Result<(Vec<u8>, DecodeOutcome), JpegError> {
let legacy = output_format_from_parts(self.info.sof_kind, request.fmt, request.scale)?;
let source_roi = request
.region
.unwrap_or_else(|| Rect::full(self.info.dimensions));
if !source_roi.is_within(self.info.dimensions) {
return Err(JpegError::RectOutOfBounds {
rect: source_roi,
width: self.info.dimensions.0,
height: self.info.dimensions.1,
});
}
let output_rect = if request.region.is_some() {
scaled_rect_covering(source_roi, legacy.downscale())?
} else {
let (width, height) = scaled_dimensions(self.info.dimensions, legacy.downscale());
Rect::full((width, height))
};
let (stride, len) =
checked_output_geometry(output_rect.w, output_rect.h, legacy.bytes_per_pixel())?;
let additional_scratch = additional_decode_scratch_bytes(
self.info.sof_kind,
self.info.dimensions,
legacy,
source_roi,
output_rect,
legacy.downscale(),
)?;
let planned_output_live = checked_add_allocation_bytes(external_live_bytes, len)?;
self.prepare_decode_workspace_with_additional(
pool,
planned_output_live,
additional_scratch,
)?;
let workspace_cap = self.decode_workspace_cap()?;
let mut allocation_live =
checked_add_allocation_bytes(external_live_bytes, pool.retained_bytes())?;
let mut out =
allocate_output_buffer_with_live_budget(len, &mut allocation_live, workspace_cap)?;
let decode_external_live =
checked_add_allocation_bytes(external_live_bytes, out.capacity())?;
let outcome = if let Some(roi) = request.region {
self.decode_region_into_output_format_with_scratch_and_external(
pool,
&mut out,
stride,
legacy,
roi,
decode_external_live,
)?
} else {
self.decode_into_output_format_with_scratch_and_external(
pool,
&mut out,
stride,
legacy,
decode_external_live,
)?
};
Ok((out, outcome))
}
}