use alloc::{sync::Arc, vec::Vec};
use j2k_core::{BatchInfrastructureError, Downscale, TileLayout};
use super::{
prepare_batch, prepare_batch_from_images, BatchDecodeOptions, BatchGroupInfo, DecodeRequest,
EncodedImage, IndexedBatchError, J2kCodestreamRange, PreparationDepth, PreparedClassicPlan,
PreparedHtj2kPlan,
};
use crate::{DecodeSettings, DeviceDecodePlan, J2kSupportInfo};
#[derive(Debug, Clone)]
pub struct PreparedImage {
pub(super) inner: Arc<PreparedImageInner>,
}
#[derive(Debug)]
pub(super) enum PreparedCodecPlan {
MetadataOnly,
Htj2k(PreparedHtj2kPlan),
Classic(PreparedClassicPlan),
}
impl PreparedCodecPlan {
pub(super) const fn preparation_depth(&self) -> PreparationDepth {
match self {
Self::MetadataOnly => PreparationDepth::MetadataOnly,
Self::Htj2k(_) => PreparationDepth::Htj2kOffsetPlan,
Self::Classic(_) => PreparationDepth::ClassicOffsetPlan,
}
}
}
#[derive(Debug)]
pub(super) struct PreparedImageInner {
pub(super) bytes: Arc<[u8]>,
pub(super) request: DecodeRequest,
pub(super) source_index: usize,
pub(super) decode_settings: DecodeSettings,
pub(super) used_lenient_metadata_recovery: bool,
pub(super) support: Arc<J2kSupportInfo>,
pub(super) plan: DeviceDecodePlan,
pub(super) codestream_range: J2kCodestreamRange,
pub(super) codec_plan: PreparedCodecPlan,
}
impl PreparedImage {
#[must_use]
pub fn bytes(&self) -> &Arc<[u8]> {
&self.inner.bytes
}
#[must_use]
pub fn request(&self) -> DecodeRequest {
self.inner.request
}
#[must_use]
pub fn source_index(&self) -> usize {
self.inner.source_index
}
#[must_use]
pub fn decode_settings(&self) -> DecodeSettings {
self.inner.decode_settings
}
#[doc(hidden)]
#[must_use]
pub fn used_lenient_metadata_recovery(&self) -> bool {
self.inner.used_lenient_metadata_recovery
}
#[must_use]
pub fn support(&self) -> &J2kSupportInfo {
&self.inner.support
}
#[must_use]
pub fn plan(&self) -> DeviceDecodePlan {
self.inner.plan
}
#[must_use]
pub fn codestream_range(&self) -> J2kCodestreamRange {
self.inner.codestream_range
}
#[must_use]
pub fn preparation_depth(&self) -> PreparationDepth {
self.inner.codec_plan.preparation_depth()
}
#[must_use]
pub fn htj2k_plan(&self) -> Option<&PreparedHtj2kPlan> {
match &self.inner.codec_plan {
PreparedCodecPlan::Htj2k(plan) => Some(plan),
PreparedCodecPlan::MetadataOnly | PreparedCodecPlan::Classic(_) => None,
}
}
#[must_use]
pub fn classic_plan(&self) -> Option<&PreparedClassicPlan> {
match &self.inner.codec_plan {
PreparedCodecPlan::Classic(plan) => Some(plan),
PreparedCodecPlan::MetadataOnly | PreparedCodecPlan::Htj2k(_) => None,
}
}
pub(super) fn codec_plan(&self) -> &PreparedCodecPlan {
&self.inner.codec_plan
}
}
#[derive(Debug)]
pub struct PreparedBatchGroup {
pub(super) info: BatchGroupInfo,
pub(super) options: BatchDecodeOptions,
pub(super) execution_shape: BatchExecutionShape,
pub(super) images: Vec<PreparedImage>,
pub(super) source_indices: Vec<usize>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct BatchExecutionShape {
pub(super) source_dimensions: (u32, u32),
pub(super) source_rect_dimensions: (u32, u32),
pub(super) scale: Downscale,
pub(super) tile_layout: Option<TileLayout>,
pub(super) resolution_levels: u8,
pub(super) preparation_depth: PreparationDepth,
}
impl PreparedBatchGroup {
#[must_use]
pub fn info(&self) -> &BatchGroupInfo {
&self.info
}
#[must_use]
pub const fn options(&self) -> BatchDecodeOptions {
self.options
}
#[must_use]
pub fn images(&self) -> &[PreparedImage] {
&self.images
}
#[must_use]
pub fn source_indices(&self) -> &[usize] {
&self.source_indices
}
}
#[derive(Debug, Clone)]
pub struct PreparedBatch {
pub(super) groups: Arc<[PreparedBatchGroup]>,
pub(super) errors: Arc<[IndexedBatchError]>,
pub(super) options: BatchDecodeOptions,
}
pub trait BatchDecoder {
type Output;
type Error: From<BatchInfrastructureError>;
fn options(&self) -> BatchDecodeOptions;
fn prepare_batch(&self, inputs: Vec<EncodedImage>) -> Result<PreparedBatch, Self::Error> {
prepare_batch(inputs, self.options()).map_err(Self::Error::from)
}
fn prepare_prepared_images(
&self,
images: Vec<PreparedImage>,
) -> Result<PreparedBatch, Self::Error> {
prepare_batch_from_images(images, self.options()).map_err(Self::Error::from)
}
fn decode_batch(&mut self, inputs: Vec<EncodedImage>) -> Result<Self::Output, Self::Error> {
let prepared = self.prepare_batch(inputs)?;
self.decode_prepared(&prepared)
}
fn decode_prepared_images(
&mut self,
images: Vec<PreparedImage>,
) -> Result<Self::Output, Self::Error> {
let prepared = self.prepare_prepared_images(images)?;
self.decode_prepared(&prepared)
}
fn decode_prepared(&mut self, prepared: &PreparedBatch) -> Result<Self::Output, Self::Error>;
}
impl PreparedBatch {
#[must_use]
pub fn groups(&self) -> &[PreparedBatchGroup] {
&self.groups
}
#[must_use]
pub fn errors(&self) -> &[IndexedBatchError] {
&self.errors
}
#[must_use]
pub const fn options(&self) -> BatchDecodeOptions {
self.options
}
#[must_use]
pub fn into_parts(
self,
) -> (
Arc<[PreparedBatchGroup]>,
Arc<[IndexedBatchError]>,
BatchDecodeOptions,
) {
(self.groups, self.errors, self.options)
}
}