1use super::{
6 checked_scratch_len, jpeg_downscale, scaled_rect_covering, ColorSpace, ComponentRowWriter,
7 CroppedWriter, DecodeOutcome, Decoder, Downscale, DownscaleFactor, JpegError, Rect, RowSink,
8 ScratchPool, SinkWriter, DEFAULT_SCRATCH,
9};
10
11impl Decoder<'_> {
12 pub fn decode_rows<S>(&self, sink: &mut S) -> Result<DecodeOutcome, JpegError>
22 where
23 S: RowSink<u8, Error = JpegError>,
24 {
25 DEFAULT_SCRATCH.with(|pool| self.decode_rows_with_scratch(&mut pool.borrow_mut(), sink))
26 }
27
28 pub fn decode_rows_with_scratch<S>(
35 &self,
36 pool: &mut ScratchPool,
37 sink: &mut S,
38 ) -> Result<DecodeOutcome, JpegError>
39 where
40 S: RowSink<u8, Error = JpegError>,
41 {
42 if self.lossless_plan.is_some() {
43 return self.decode_lossless_rows_with_scratch(pool, sink);
44 }
45 let width = self.info.dimensions.0 as usize;
46 let scratch_bytes = self.prepare_decode_workspace(pool, 0)?;
47 let rows = pool.take_sink_rows(width.saturating_mul(3), scratch_bytes)?;
48 let mut writer = SinkWriter::new(sink, rows, self.backend);
49 let result = self.decode_rgb_with_writer(
50 pool,
51 &mut writer,
52 DownscaleFactor::Full,
53 Rect::full(self.info.dimensions),
54 );
55 pool.restore_sink_rows(writer.into_rows());
56 result
57 }
58
59 fn decode_lossless_rows_with_scratch<S>(
60 &self,
61 pool: &mut ScratchPool,
62 sink: &mut S,
63 ) -> Result<DecodeOutcome, JpegError>
64 where
65 S: RowSink<u8, Error = JpegError>,
66 {
67 let plan = self
68 .lossless_plan
69 .as_ref()
70 .ok_or(JpegError::NotImplemented {
71 sof: self.info.sof_kind,
72 })?;
73 if !(1..=7).contains(&plan.predictor) {
74 return Err(JpegError::UnsupportedPredictor {
75 predictor: plan.predictor,
76 });
77 }
78
79 let width = self.info.dimensions.0 as usize;
80 let scratch_bytes = self.prepare_decode_workspace(pool, 0)?;
81 match (self.info.color_space, plan.bit_depth) {
82 (ColorSpace::Grayscale, 8) => {
83 let predictor_len = checked_scratch_len(&[width])?;
84 let sink_len = checked_scratch_len(&[width, 3])?;
85 let mut rows =
86 pool.prepare_lossless_rows(predictor_len, sink_len, scratch_bytes)?;
87 let result = self.decode_lossless_gray8_rows(
88 sink,
89 &mut pool.lossless_prev_row,
90 &mut pool.lossless_curr_row,
91 &mut rows.top_row,
92 );
93 pool.restore_sink_rows(rows);
94 result
95 }
96 (ColorSpace::Grayscale, 16) => {
97 let predictor_len = checked_scratch_len(&[width, 2])?;
98 let _rows = pool.prepare_lossless_rows(predictor_len, 0, scratch_bytes)?;
99 self.decode_lossless_gray16_rows(
100 sink,
101 &mut pool.lossless_prev_row,
102 &mut pool.lossless_curr_row,
103 )
104 }
105 (ColorSpace::Rgb, 8) => {
106 let predictor_len = checked_scratch_len(&[width, 3])?;
107 let _rows = pool.prepare_lossless_rows(predictor_len, 0, scratch_bytes)?;
108 self.decode_lossless_color8_rows(
109 sink,
110 &mut pool.lossless_prev_row,
111 &mut pool.lossless_curr_row,
112 None,
113 ColorSpace::Rgb,
114 )
115 }
116 (ColorSpace::YCbCr, 8) => {
117 let row_len = checked_scratch_len(&[width, 3])?;
118 let mut rows = pool.prepare_lossless_rows(row_len, row_len, scratch_bytes)?;
119 let result = self.decode_lossless_color8_rows(
120 sink,
121 &mut pool.lossless_prev_row,
122 &mut pool.lossless_curr_row,
123 Some(&mut rows.top_row),
124 ColorSpace::YCbCr,
125 );
126 pool.restore_sink_rows(rows);
127 result
128 }
129 (ColorSpace::Rgb, 16) => {
130 let predictor_len = checked_scratch_len(&[width, 6])?;
131 let _rows = pool.prepare_lossless_rows(predictor_len, 0, scratch_bytes)?;
132 self.decode_lossless_color16_rows(
133 sink,
134 &mut pool.lossless_prev_row,
135 &mut pool.lossless_curr_row,
136 None,
137 ColorSpace::Rgb,
138 )
139 }
140 (ColorSpace::YCbCr, 16) => {
141 let row_len = checked_scratch_len(&[width, 6])?;
142 let mut rows = pool.prepare_lossless_rows(row_len, row_len, scratch_bytes)?;
143 let result = self.decode_lossless_color16_rows(
144 sink,
145 &mut pool.lossless_prev_row,
146 &mut pool.lossless_curr_row,
147 Some(&mut rows.top_row),
148 ColorSpace::YCbCr,
149 );
150 pool.restore_sink_rows(rows);
151 result
152 }
153 (_, depth) if depth != 8 && depth != 16 => {
154 Err(JpegError::UnsupportedBitDepth { depth })
155 }
156 _ => Err(JpegError::NotImplemented {
157 sof: self.info.sof_kind,
158 }),
159 }
160 }
161
162 pub fn decode_component_rows_with_scratch<W>(
168 &self,
169 pool: &mut ScratchPool,
170 writer: &mut W,
171 ) -> Result<DecodeOutcome, JpegError>
172 where
173 W: ComponentRowWriter,
174 {
175 self.decode_region_component_rows_with_scratch(
176 pool,
177 writer,
178 Rect::full(self.info.dimensions),
179 Downscale::None,
180 )
181 }
182
183 pub fn decode_region_component_rows_with_scratch<W>(
190 &self,
191 pool: &mut ScratchPool,
192 mut writer: &mut W,
193 roi: Rect,
194 scale: Downscale,
195 ) -> Result<DecodeOutcome, JpegError>
196 where
197 W: ComponentRowWriter,
198 {
199 if !roi.is_within(self.info.dimensions) {
200 return Err(JpegError::RectOutOfBounds {
201 rect: roi,
202 width: self.info.dimensions.0,
203 height: self.info.dimensions.1,
204 });
205 }
206
207 let downscale = jpeg_downscale(scale);
208 let scaled_roi = scaled_rect_covering(roi, downscale)?;
209
210 if roi == Rect::full(self.info.dimensions) {
211 self.decode_with_writer(pool, &mut writer, downscale, roi)
212 } else {
213 let (source_x0, source_width) =
214 self.source_window_for_output_rect(downscale, scaled_roi);
215 let mut cropped = CroppedWriter::new(writer, scaled_roi, source_x0, source_width)?;
216 self.decode_with_writer(pool, &mut cropped, downscale, roi)
217 }
218 }
219}