1
2use crate::meta::attribute::{IntegerBounds};
6
7#[derive(Debug, Clone)]
13pub struct Chunk {
14
15 pub layer_index: usize,
19
20 pub compressed_block: CompressedBlock,
22}
23
24#[derive(Debug, Clone)]
30pub enum CompressedBlock {
31
32 ScanLine(CompressedScanLineBlock),
34
35 Tile(CompressedTileBlock),
37
38 DeepScanLine(CompressedDeepScanLineBlock),
40
41 DeepTile(CompressedDeepTileBlock),
43}
44
45#[derive(Debug, Clone)]
48pub struct CompressedScanLineBlock {
49
50 pub y_coordinate: i32,
53
54 pub compressed_pixels: Vec<u8>,
58}
59
60#[derive(Debug, Clone)]
63pub struct CompressedTileBlock {
64
65 pub coordinates: TileCoordinates,
67
68 pub compressed_pixels: Vec<u8>,
72}
73
74#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
76pub struct TileCoordinates {
77
78 pub tile_index: Vec2<usize>,
80
81 pub level_index: Vec2<usize>,
83}
84
85#[derive(Debug, Clone)]
88pub struct CompressedDeepScanLineBlock {
89
90 pub y_coordinate: i32,
93
94 pub decompressed_sample_data_size: usize,
96
97 pub compressed_pixel_offset_table: Vec<i8>,
101
102 pub compressed_sample_data: Vec<u8>,
106}
107
108#[derive(Debug, Clone)]
111pub struct CompressedDeepTileBlock {
112
113 pub coordinates: TileCoordinates,
115
116 pub decompressed_sample_data_size: usize,
118
119 pub compressed_pixel_offset_table: Vec<i8>,
123
124 pub compressed_sample_data: Vec<u8>,
128}
129
130
131use crate::io::*;
132
133impl TileCoordinates {
134
135 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
137 i32::write(usize_to_i32(self.tile_index.x()), write)?;
138 i32::write(usize_to_i32(self.tile_index.y()), write)?;
139 i32::write(usize_to_i32(self.level_index.x()), write)?;
140 i32::write(usize_to_i32(self.level_index.y()), write)?;
141 Ok(())
142 }
143
144 pub fn read(read: &mut impl Read) -> Result<Self> {
146 let tile_x = i32::read(read)?;
147 let tile_y = i32::read(read)?;
148
149 let level_x = i32::read(read)?;
150 let level_y = i32::read(read)?;
151
152 if level_x > 31 || level_y > 31 {
153 return Err(Error::invalid("level index exceeding integer maximum"));
156 }
157
158 Ok(TileCoordinates {
159 tile_index: Vec2(tile_x, tile_y).to_usize("tile coordinate index")?,
160 level_index: Vec2(level_x, level_y).to_usize("tile coordinate level")?
161 })
162 }
163
164 pub fn to_data_indices(&self, tile_size: Vec2<usize>, max: Vec2<usize>) -> Result<IntegerBounds> {
168 let x = self.tile_index.x() * tile_size.width();
169 let y = self.tile_index.y() * tile_size.height();
170
171 if x >= max.x() || y >= max.y() {
172 Err(Error::invalid("tile index"))
173 }
174 else {
175 Ok(IntegerBounds {
176 position: Vec2(usize_to_i32(x), usize_to_i32(y)),
177 size: Vec2(
178 calculate_block_size(max.x(), tile_size.width(), x)?,
179 calculate_block_size(max.y(), tile_size.height(), y)?,
180 ),
181 })
182 }
183 }
184
185 pub fn to_absolute_indices(&self, tile_size: Vec2<usize>, data_window: IntegerBounds) -> Result<IntegerBounds> {
187 let data = self.to_data_indices(tile_size, data_window.size)?;
188 Ok(data.with_origin(data_window.position))
189 }
190
191 pub fn is_largest_resolution_level(&self) -> bool {
193 self.level_index == Vec2(0, 0)
194 }
195}
196
197
198
199use crate::meta::{MetaData, BlockDescription, calculate_block_size};
200
201impl CompressedScanLineBlock {
202
203 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
205 debug_assert_ne!(self.compressed_pixels.len(), 0, "empty blocks should not be put in the file bug");
206
207 i32::write(self.y_coordinate, write)?;
208 u8::write_i32_sized_slice(write, &self.compressed_pixels)?;
209 Ok(())
210 }
211
212 pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
214 let y_coordinate = i32::read(read)?;
215 let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size), "scan line block sample count")?;
216 Ok(CompressedScanLineBlock { y_coordinate, compressed_pixels })
217 }
218}
219
220impl CompressedTileBlock {
221
222 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
224 debug_assert_ne!(self.compressed_pixels.len(), 0, "empty blocks should not be put in the file bug");
225
226 self.coordinates.write(write)?;
227 u8::write_i32_sized_slice(write, &self.compressed_pixels)?;
228 Ok(())
229 }
230
231 pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
233 let coordinates = TileCoordinates::read(read)?;
234 let compressed_pixels = u8::read_i32_sized_vec(read, max_block_byte_size, Some(max_block_byte_size), "tile block sample count")?;
235 Ok(CompressedTileBlock { coordinates, compressed_pixels })
236 }
237}
238
239impl CompressedDeepScanLineBlock {
240
241 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
243 debug_assert_ne!(self.compressed_sample_data.len(), 0, "empty blocks should not be put in the file bug");
244
245 i32::write(self.y_coordinate, write)?;
246 u64::write(self.compressed_pixel_offset_table.len() as u64, write)?;
247 u64::write(self.compressed_sample_data.len() as u64, write)?; u64::write(self.decompressed_sample_data_size as u64, write)?;
249 i8::write_slice(write, &self.compressed_pixel_offset_table)?;
250 u8::write_slice(write, &self.compressed_sample_data)?;
251 Ok(())
252 }
253
254 pub fn read(read: &mut impl Read, max_block_byte_size: usize) -> Result<Self> {
256 let y_coordinate = i32::read(read)?;
257 let compressed_pixel_offset_table_size = u64_to_usize(u64::read(read)?);
258 let compressed_sample_data_size = u64_to_usize(u64::read(read)?);
259 let decompressed_sample_data_size = u64_to_usize(u64::read(read)?);
260
261 let compressed_pixel_offset_table = i8::read_vec(
263 read, compressed_pixel_offset_table_size,
264 6 * u16::MAX as usize, Some(max_block_byte_size),
265 "deep scan line block table size"
266 )?;
267
268 let compressed_sample_data = u8::read_vec(
269 read, compressed_sample_data_size,
270 6 * u16::MAX as usize, Some(max_block_byte_size),
271 "deep scan line block sample count"
272 )?;
273
274 Ok(CompressedDeepScanLineBlock {
275 y_coordinate,
276 decompressed_sample_data_size,
277 compressed_pixel_offset_table,
278 compressed_sample_data,
279 })
280 }
281}
282
283
284impl CompressedDeepTileBlock {
285
286 pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
288 debug_assert_ne!(self.compressed_sample_data.len(), 0, "empty blocks should not be put in the file bug");
289
290 self.coordinates.write(write)?;
291 u64::write(self.compressed_pixel_offset_table.len() as u64, write)?;
292 u64::write(self.compressed_sample_data.len() as u64, write)?; u64::write(self.decompressed_sample_data_size as u64, write)?;
294 i8::write_slice(write, &self.compressed_pixel_offset_table)?;
295 u8::write_slice(write, &self.compressed_sample_data)?;
296 Ok(())
297 }
298
299 pub fn read(read: &mut impl Read, hard_max_block_byte_size: usize) -> Result<Self> {
301 let coordinates = TileCoordinates::read(read)?;
302 let compressed_pixel_offset_table_size = u64_to_usize(u64::read(read)?);
303 let compressed_sample_data_size = u64_to_usize(u64::read(read)?); let decompressed_sample_data_size = u64_to_usize(u64::read(read)?);
305
306 let compressed_pixel_offset_table = i8::read_vec(
307 read, compressed_pixel_offset_table_size,
308 6 * u16::MAX as usize, Some(hard_max_block_byte_size),
309 "deep tile block table size"
310 )?;
311
312 let compressed_sample_data = u8::read_vec(
313 read, compressed_sample_data_size,
314 6 * u16::MAX as usize, Some(hard_max_block_byte_size),
315 "deep tile block sample count"
316 )?;
317
318 Ok(CompressedDeepTileBlock {
319 coordinates,
320 decompressed_sample_data_size,
321 compressed_pixel_offset_table,
322 compressed_sample_data,
323 })
324 }
325}
326
327use crate::error::{UnitResult, Result, Error, u64_to_usize, usize_to_i32, i32_to_usize};
328use crate::math::Vec2;
329
330impl Chunk {
332
333 pub fn write(&self, write: &mut impl Write, header_count: usize) -> UnitResult {
335 debug_assert!(self.layer_index < header_count, "layer index bug"); if header_count != 1 { usize_to_i32(self.layer_index).write(write)?; }
338 else { assert_eq!(self.layer_index, 0, "invalid header index for single layer file"); }
339
340 match self.compressed_block {
341 CompressedBlock::ScanLine (ref value) => value.write(write),
342 CompressedBlock::Tile (ref value) => value.write(write),
343 CompressedBlock::DeepScanLine (ref value) => value.write(write),
344 CompressedBlock::DeepTile (ref value) => value.write(write),
345 }
346 }
347
348 pub fn read(read: &mut impl Read, meta_data: &MetaData) -> Result<Self> {
350 let layer_number = i32_to_usize(
351 if meta_data.requirements.is_multilayer() { i32::read(read)? } else { 0_i32 }, "chunk data part number"
354 )?;
355
356 if layer_number >= meta_data.headers.len() {
357 return Err(Error::invalid("chunk data part number"));
358 }
359
360 let header = &meta_data.headers[layer_number];
361 let max_block_byte_size = header.max_block_byte_size();
362
363 let chunk = Chunk {
364 layer_index: layer_number,
365 compressed_block: match header.blocks {
366 BlockDescription::ScanLines if !header.deep => CompressedBlock::ScanLine(CompressedScanLineBlock::read(read, max_block_byte_size)?),
368 BlockDescription::Tiles(_) if !header.deep => CompressedBlock::Tile(CompressedTileBlock::read(read, max_block_byte_size)?),
369
370 BlockDescription::ScanLines => CompressedBlock::DeepScanLine(CompressedDeepScanLineBlock::read(read, max_block_byte_size)?),
372 BlockDescription::Tiles(_) => CompressedBlock::DeepTile(CompressedDeepTileBlock::read(read, max_block_byte_size)?),
373 },
374 };
375
376 Ok(chunk)
377 }
378}
379