1
2use crate::meta::attribute::{IntegerBounds};
6
7#[derive(Debug, Clone)]
15pub struct Chunk {
16
17 pub layer_index: usize,
21
22 pub compressed_block: CompressedBlock,
25}
26
27#[derive(Debug, Clone)]
35pub enum CompressedBlock {
36
37 ScanLine(CompressedScanLineBlock),
39
40 Tile(CompressedTileBlock),
42
43 DeepScanLine(CompressedDeepScanLineBlock),
45
46 DeepTile(CompressedDeepTileBlock),
48}
49
50#[derive(Debug, Clone)]
55pub struct CompressedScanLineBlock {
56
57 pub y_coordinate: i32,
60
61 pub compressed_pixels_le: Vec<u8>,
66}
67
68#[derive(Debug, Clone)]
73pub struct CompressedTileBlock {
74
75 pub coordinates: TileCoordinates,
77
78 pub compressed_pixels_le: Vec<u8>,
83}
84
85#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
87pub struct TileCoordinates {
88
89 pub tile_index: Vec2<usize>,
91
92 pub level_index: Vec2<usize>,
94}
95
96#[derive(Debug, Clone)]
101pub struct CompressedDeepScanLineBlock {
102
103 pub y_coordinate: i32,
106
107 pub decompressed_sample_data_size: usize,
109
110 pub compressed_pixel_offset_table: Vec<i8>,
114
115 pub compressed_sample_data_le: Vec<u8>,
119}
120
121#[derive(Debug, Clone)]
126pub struct CompressedDeepTileBlock {
127
128 pub coordinates: TileCoordinates,
130
131 pub decompressed_sample_data_size: usize,
133
134 pub compressed_pixel_offset_table: Vec<i8>,
138
139 pub compressed_sample_data_le: Vec<u8>,
143}
144
145
146use crate::io::*;
147
148impl TileCoordinates {
149
150 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
152 i32::write_le(usize_to_i32(self.tile_index.x(), "tile x")?, write)?;
153 i32::write_le(usize_to_i32(self.tile_index.y(), "tile y")?, write)?;
154 i32::write_le(usize_to_i32(self.level_index.x(), "level x")?, write)?;
155 i32::write_le(usize_to_i32(self.level_index.y(), "level y")?, write)?;
156 Ok(())
157 }
158
159 pub fn read(read: &mut impl Read) -> Result<Self> {
161 let tile_x = i32::read_le(read)?;
162 let tile_y = i32::read_le(read)?;
163
164 let level_x = i32::read_le(read)?;
165 let level_y = i32::read_le(read)?;
166
167 if level_x > 31 || level_y > 31 {
168 return Err(Error::invalid("level index exceeding integer maximum"));
171 }
172
173 Ok(TileCoordinates {
174 tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?,
175 level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")?
176 })
177 }
178
179 pub fn to_data_indices(&self, tile_size: Vec2<usize>, max: Vec2<usize>) -> Result<IntegerBounds> {
183 let x = self.tile_index.x() * tile_size.width();
184 let y = self.tile_index.y() * tile_size.height();
185
186 if x >= max.x() || y >= max.y() {
187 Err(Error::invalid("tile index"))
188 }
189 else {
190 Ok(IntegerBounds {
191 position: Vec2(usize_to_i32(x, "tile x")?, usize_to_i32(y, "tile y")?),
192 size: Vec2(
193 calculate_block_size(max.x(), tile_size.width(), x)?,
194 calculate_block_size(max.y(), tile_size.height(), y)?,
195 ),
196 })
197 }
198 }
199
200 pub fn to_absolute_indices(&self, tile_size: Vec2<usize>, data_window: IntegerBounds) -> Result<IntegerBounds> {
202 let data = self.to_data_indices(tile_size, data_window.size)?;
203 Ok(data.with_origin(data_window.position))
204 }
205
206 pub fn is_largest_resolution_level(&self) -> bool {
208 self.level_index == Vec2(0, 0)
209 }
210}
211
212
213
214use crate::meta::{MetaData, BlockDescription, calculate_block_size};
215
216impl CompressedScanLineBlock {
217
218 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
220 debug_assert_ne!(self.compressed_pixels_le.len(), 0, "empty blocks should not be put in the file bug");
221
222 i32::write_le(self.y_coordinate, write)?;
223 u8::write_i32_sized_slice_le(write, &self.compressed_pixels_le)?;
224 Ok(())
225 }
226
227 pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
229 let y_coordinate = i32::read_le(read)?;
230 let compressed_pixels_le = u8::read_i32_sized_vec_le(read, max_block_byte_size, Some(max_block_byte_size), "scan line block sample count")?;
231 Ok(CompressedScanLineBlock { y_coordinate, compressed_pixels_le })
232 }
233}
234
235impl CompressedTileBlock {
236
237 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
239 debug_assert_ne!(self.compressed_pixels_le.len(), 0, "empty blocks should not be put in the file bug");
240
241 self.coordinates.write(write)?;
242 u8::write_i32_sized_slice_le(write, &self.compressed_pixels_le)?;
243 Ok(())
244 }
245
246 pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
248 let coordinates = TileCoordinates::read(read)?;
249 let compressed_pixels_le = u8::read_i32_sized_vec_le(read, max_block_byte_size, Some(max_block_byte_size), "tile block sample count")?;
250 Ok(CompressedTileBlock { coordinates, compressed_pixels_le })
251 }
252}
253
254impl CompressedDeepScanLineBlock {
255
256 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
258 debug_assert_ne!(self.compressed_sample_data_le.len(), 0, "empty blocks should not be put in the file bug");
259
260 i32::write_le(self.y_coordinate, write)?;
261 u64::write_le(self.compressed_pixel_offset_table.len() as u64, write)?;
262 u64::write_le(self.compressed_sample_data_le.len() as u64, write)?; u64::write_le(self.decompressed_sample_data_size as u64, write)?;
264 i8::write_slice_le(write, &self.compressed_pixel_offset_table)?;
265 u8::write_slice_le(write, &self.compressed_sample_data_le)?;
266 Ok(())
267 }
268
269 pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
271 let y_coordinate = i32::read_le(read)?;
272 let compressed_pixel_offset_table_size = u64_to_usize(u64::read_le(read)?, "deep table size")?;
273 let compressed_sample_data_size = u64_to_usize(u64::read_le(read)?, "deep size")?;
274 let decompressed_sample_data_size = u64_to_usize(u64::read_le(read)?, "raw deep size")?;
275
276 let compressed_pixel_offset_table = i8::read_vec_le(
278 read, compressed_pixel_offset_table_size,
279 6 * u16::MAX as usize, Some(max_block_byte_size),
280 "deep scan line block table size"
281 )?;
282
283 let compressed_sample_data_le = u8::read_vec_le(
284 read, compressed_sample_data_size,
285 6 * u16::MAX as usize, Some(max_block_byte_size),
286 "deep scan line block sample count"
287 )?;
288
289 Ok(CompressedDeepScanLineBlock {
290 y_coordinate,
291 decompressed_sample_data_size,
292 compressed_pixel_offset_table,
293 compressed_sample_data_le,
294 })
295 }
296}
297
298
299impl CompressedDeepTileBlock {
300
301 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
303 debug_assert_ne!(self.compressed_sample_data_le.len(), 0, "empty blocks should not be put in the file bug");
304
305 self.coordinates.write(write)?;
306 u64::write_le(self.compressed_pixel_offset_table.len() as u64, write)?;
307 u64::write_le(self.compressed_sample_data_le.len() as u64, write)?; u64::write_le(self.decompressed_sample_data_size as u64, write)?;
309 i8::write_slice_le(write, &self.compressed_pixel_offset_table)?;
310 u8::write_slice_le(write, &self.compressed_sample_data_le)?;
311 Ok(())
312 }
313
314 pub fn read(read: &mut impl Read, hard_max_block_byte_size: usize) -> Result<Self> {
316 let coordinates = TileCoordinates::read(read)?;
317 let compressed_pixel_offset_table_size = u64_to_usize(u64::read_le(read)?,"deep table size")?;
318 let compressed_sample_data_size = u64_to_usize(u64::read_le(read)?, "deep size")?; let decompressed_sample_data_size = u64_to_usize(u64::read_le(read)?, "raw deep size")?;
320
321 let compressed_pixel_offset_table = i8::read_vec_le(
322 read, compressed_pixel_offset_table_size,
323 6 * u16::MAX as usize, Some(hard_max_block_byte_size),
324 "deep tile block table size"
325 )?;
326
327 let compressed_sample_data_le = u8::read_vec_le(
328 read, compressed_sample_data_size,
329 6 * u16::MAX as usize, Some(hard_max_block_byte_size),
330 "deep tile block sample count"
331 )?;
332
333 Ok(CompressedDeepTileBlock {
334 coordinates,
335 decompressed_sample_data_size,
336 compressed_pixel_offset_table,
337 compressed_sample_data_le,
338 })
339 }
340}
341
342use crate::error::{UnitResult, Result, Error, u64_to_usize, usize_to_i32, i32_to_usize};
343use crate::math::Vec2;
344
345impl Chunk {
347
348 pub fn write(&self, write: &mut impl Write, header_count: usize) -> UnitResult {
350 debug_assert!(self.layer_index < header_count, "layer index bug"); if header_count != 1 { usize_to_i32(self.layer_index, "layer index")?.write_le(write)?; }
353 else { assert_eq!(self.layer_index, 0, "invalid header index for single layer file"); }
354
355 match self.compressed_block {
356 CompressedBlock::ScanLine (ref value) => value.write(write),
357 CompressedBlock::Tile (ref value) => value.write(write),
358 CompressedBlock::DeepScanLine (ref value) => value.write(write),
359 CompressedBlock::DeepTile (ref value) => value.write(write),
360 }
361 }
362
363 pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> {
365 let layer_number = i32_to_usize(
366 if meta_data.requirements.is_multilayer() { i32::read_le(read)? } else { 0_i32 }, "chunk data part number"
369 )?;
370
371 if layer_number >= meta_data.headers.len() {
372 return Err(Error::invalid("chunk data part number"));
373 }
374
375 let header = &meta_data.headers[layer_number];
376 let max_block_byte_size = header.max_block_byte_size();
377
378 let chunk = Chunk {
379 layer_index: layer_number,
380 compressed_block: match header.blocks {
381 BlockDescription::ScanLines if !header.deep => CompressedBlock::ScanLine(CompressedScanLineBlock::read(read, max_block_byte_size)?),
383 BlockDescription::Tiles(_) if !header.deep => CompressedBlock::Tile(CompressedTileBlock::read(read, max_block_byte_size)?),
384
385 BlockDescription::ScanLines => CompressedBlock::DeepScanLine(CompressedDeepScanLineBlock::read(read, max_block_byte_size)?),
387 BlockDescription::Tiles(_) => CompressedBlock::DeepTile(CompressedDeepTileBlock::read(read, max_block_byte_size)?),
388 },
389 };
390
391 Ok(chunk)
392 }
393}
394