1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! # `goo`
//!
//! [](https://github.com/connorslade/goo/actions/workflows/build.yml) [](https://crates.io/crates/goo) [](https://crates.io/crates/goo)
//!
//! Library for encoding and decoding Elegoo's `.goo` file format.
//! This is a stand alone version of this crate taken from my [mslicer](https://github.com/connorslade/mslicer) project, its an open source slicer for masked stereolithography printers.
//!
//! If you want to learn more about the goo format, make sure you read the [official format spec](https://github.com/elegooofficial/GOO).
//! Some things aren't mentioned in the spec like how everything is big-endian, the checksum is just the negated sum of all bytes in the payload, and the image data encoding specification is hard to follow, so look at [my implementation](https://github.com/connorslade/goo/blob/main/src/encoded_layer.rs).
//! Also, if you use [ImHex](https://imhex.werwolv.net), I have created a pattern file ([goo.hexpat](https://github.com/connorslade/goo/blob/main/goo.hexpat)) that may be helpful.
//!
//! ## Examples
//!
//! For some real world examples, check out the following links to my mslicer project source code:
//!
//! - [Slicing a triangular mesh into a layer](https://github.com/connorslade/mslicer/blob/15d69c7c9f6bd921d8517d81047aa29b18ba4f92/slicer/src/slicer.rs#L72)
//! - [Decoding a sliced file for a layer preview](https://github.com/connorslade/mslicer/blob/15d69c7c9f6bd921d8517d81047aa29b18ba4f92/mslicer/src/windows/slice_operation.rs#L142)
//!
//! ### Encoding an Image
//!
//! Because thousands of very high resolution images take many tens of gigabytes to store, goo files use a run length encoding mechanism as a simple form of compression.
//! In order to encode an image into a goo layer, you therefore must separate it into runs first.
//! In this example ill just add alternating rows of white and black.
//!
//! It is important to note that you must define a value for every pixel.
//! This is because on my printer at least the buffer that each layer is decoded into is uninitialized memory.
//! So if the last run doesn't fill the buffer, the printer will just print whatever was in the buffer before which just makes a huge mess.
//!
//! ```rust
//! use goo::{LayerEncoder, LayerDecoder, Run};
//!
//! let size = (11520, 5102);
//! let mut out = LayerEncoder::new();
//!
//! for y in 0..size.1 {
//! let color = if y % 2 == 0 { 255 } else { 0 };
//! out.add_run(size.0, color);
//! }
//!
//! let (bytes, checksum) = out.finish();
//!
//! let decoder = LayerDecoder::new(&bytes);
//! assert_eq!(checksum, decoder.checksum());
//!
//! for run in decoder {
//! println!("{:?}", run);
//! }
//! ```
//!
//! ### Decoding to Images
//!
//! This example is a simplified version of the included example to inspect sliced goo files.
//! Note that setting each pixel individually is not very fast, but it was enough for a debugging tool.
//!
//! ```rust
//! use std::fs;
//!
//! use goo::{GooFile, LayerDecoder, Run};
//! use image::RgbImage;
//!
//! # fn test() -> anyhow::Result<()> {
//! let raw_goo = fs::read("input.goo")?;
//! let goo = GooFile::deserialize(&raw_goo)?;
//! println!("{:#?}", goo.header);
//!
//! for (i, layer) in goo.layers.iter().enumerate() {
//! let decoder = LayerDecoder::new(&layer.data);
//! let mut pixel = 0;
//!
//! if layer.checksum != decoder.checksum() {
//! eprintln!("WARN: Checksum mismatch for layer {}", i);
//! }
//!
//! let mut image = RgbImage::new(
//! goo.header.x_resolution as u32,
//! goo.header.y_resolution as u32,
//! );
//!
//! for Run { length, value } in decoder {
//! let color = image::Rgb([value, value, value]);
//! for _ in 0..length {
//! let x = pixel % goo.header.x_resolution as u32;
//! let y = pixel / goo.header.x_resolution as u32;
//!
//! image.put_pixel(x, y, color);
//! pixel += 1;
//! }
//! }
//!
//! image.save(format!("layer_{:03}.png", i))?;
//! }
//! # Ok(())
//! # }
//! ```
pub use ;
pub use File as GooFile;
pub use HeaderInfo;
pub use Run;
pub use PreviewImage;
const ENDING_STRING: & = &;
const MAGIC_TAG: & = &;
const DELIMITER: & = &;