1use std::convert::TryInto;
2
3use crate::{
4 error::{AseParseResult, AseResult, AsepriteError, AsepriteInvalidError, AsepriteParseError},
5 AsepritePalette,
6};
7
8use flate2::Decompress;
9use nom::{
10 bytes::complete::{tag, take},
11 combinator::{all_consuming, cond},
12 multi::{count, length_data, many1},
13 number::complete::{le_i16, le_i32, le_u16, le_u32, le_u8},
14 Finish,
15};
16use tracing::{debug_span, error, info};
17
18#[derive(Debug, PartialEq)]
22#[allow(missing_docs)]
23pub enum AsepriteColorDepth {
24 RGBA,
25 Grayscale,
26 Indexed,
27}
28
29impl AsepriteColorDepth {
30 fn bytes_per_pixel(&self) -> usize {
31 match self {
32 AsepriteColorDepth::RGBA => 4,
33 AsepriteColorDepth::Grayscale => 2,
34 AsepriteColorDepth::Indexed => 1,
35 }
36 }
37}
38
39#[derive(Debug, PartialEq)]
41pub struct RawAsepriteHeader {
42 pub file_size: u32,
44 pub magic_number: u16,
46 pub frames: u16,
48 pub width: u16,
50 pub height: u16,
52 pub color_depth: AsepriteColorDepth,
54 pub flags: u32,
58 #[deprecated = "You should use the duration in each frame"]
60 pub speed: u16,
61 pub transparent_palette: u8,
65 pub color_count: u16,
67 pub pixel_width: u8,
69 pub pixel_height: u8,
71 pub grid_x: i16,
73 pub grid_y: i16,
75 pub grid_width: u16,
77 pub grid_height: u16,
79}
80
81fn color_depth(input: &[u8]) -> AseParseResult<AsepriteColorDepth> {
82 let (input, depth) = le_u16(input)?;
83 Ok((
84 input,
85 match depth {
86 32 => AsepriteColorDepth::RGBA,
87 16 => AsepriteColorDepth::Grayscale,
88 8 => AsepriteColorDepth::Indexed,
89 depth => {
90 return Err(nom::Err::Failure(AsepriteParseError::InvalidColorDepth(
91 depth,
92 )))
93 }
94 },
95 ))
96}
97
98const ASEPRITE_MAGIC_NUMBER: u16 = 0xA5E0;
99
100fn aseprite_header(input: &[u8]) -> AseParseResult<RawAsepriteHeader> {
101 let input_len = input.len();
102 let (input, file_size) = le_u32(input)?;
103
104 let (input, magic_number) = tag(&ASEPRITE_MAGIC_NUMBER.to_le_bytes())(input)?;
105 let (input, frames) = le_u16(input)?;
106 let (input, width) = le_u16(input)?;
107 let (input, height) = le_u16(input)?;
108 let (input, color_depth) = color_depth(input)?;
109 let (input, flags) = le_u32(input)?;
110 let (input, speed) = le_u16(input)?;
111 let (input, _) = le_u32(input)?;
112 let (input, _) = le_u32(input)?;
113 let (input, transparent_palette) = le_u8(input)?;
114 let (input, _) = take(3usize)(input)?;
115 let (input, color_count) = le_u16(input)?;
116 let (input, pixel_width) = le_u8(input)?;
117 let (input, pixel_height) = le_u8(input)?;
118 let (input, grid_x) = le_i16(input)?;
119 let (input, grid_y) = le_i16(input)?;
120 let (input, grid_width) = le_u16(input)?;
121 let (input, grid_height) = le_u16(input)?;
122 let (input, _) = take(84usize)(input)?;
123
124 assert_eq!(input_len - input.len(), 128);
125
126 Ok((
127 input,
128 #[allow(deprecated)]
129 RawAsepriteHeader {
130 file_size,
131 magic_number: u16::from_le_bytes(
132 magic_number
133 .try_into()
134 .expect("Invalid ASEPRITE_MAGIC_NUMBER matched. This is a bug."),
135 ),
136 frames,
137 width,
138 height,
139 color_depth,
140 flags,
141 speed,
142 transparent_palette,
143 color_count,
144 pixel_width,
145 pixel_height,
146 grid_x,
147 grid_y,
148 grid_width,
149 grid_height,
150 },
151 ))
152}
153
154fn aseprite_string(input: &[u8]) -> AseParseResult<String> {
155 let (input, name_len) = le_u16(input)?;
156 let (input, name_bytes) = take(name_len as usize)(input)?;
157
158 Ok((
159 input,
160 String::from_utf8(name_bytes.to_vec())
161 .map_err(|err| nom::Err::Failure(AsepriteParseError::InvalidUtf8(err)))?,
162 ))
163}
164
165pub struct RawAsepriteFrame {
167 pub magic_number: u16,
169 pub duration_ms: u16,
171 pub chunks: Vec<RawAsepriteChunk>,
173}
174
175#[allow(missing_docs)]
177#[derive(Debug, Clone, Copy)]
178pub struct AsepriteColor {
179 pub red: u8,
180 pub green: u8,
181 pub blue: u8,
182 pub alpha: u8,
183}
184
185fn aseprite_color(input: &[u8]) -> AseParseResult<AsepriteColor> {
186 let (input, colors) = take(4usize)(input)?;
187
188 Ok((
189 input,
190 AsepriteColor {
191 red: colors[0],
192 green: colors[1],
193 blue: colors[2],
194 alpha: colors[3],
195 },
196 ))
197}
198
199pub struct RawAsepriteUserData {
201 pub text: Option<String>,
203 pub color: Option<AsepriteColor>,
205}
206
207fn aseprite_user_data(input: &[u8]) -> AseParseResult<RawAsepriteUserData> {
208 let (input, kind) = le_u32(input)?;
209
210 let (input, text) = cond(kind & 0x1 != 0, aseprite_string)(input)?;
211 let (input, color) = cond(kind & 0x2 != 0, aseprite_color)(input)?;
212
213 Ok((input, RawAsepriteUserData { text, color }))
214}
215
216pub enum AsepriteLayerType {
218 Normal,
220 Group,
222}
223
224fn aseprite_layer_type(input: &[u8]) -> AseParseResult<AsepriteLayerType> {
225 let (input, layer_type) = le_u16(input)?;
226
227 Ok((
228 input,
229 match layer_type {
230 0 => AsepriteLayerType::Normal,
231 1 => AsepriteLayerType::Group,
232 unknown => {
233 return Err(nom::Err::Failure(AsepriteParseError::InvalidLayerType(
234 unknown,
235 )));
236 }
237 },
238 ))
239}
240
241#[derive(Debug, Clone, Copy)]
242#[allow(missing_docs)]
244pub enum AsepriteBlendMode {
245 Normal,
246 Multiply,
247 Screen,
248 Overlay,
249 Darken,
250 Lighten,
251 ColorDodge,
252 ColorBurn,
253 HardLight,
254 SoftLight,
255 Difference,
256 Exclusion,
257 Hue,
258 Saturation,
259 Color,
260 Luminosity,
261 Addition,
262 Subtract,
263 Divide,
264}
265
266fn aseprite_blend_mode(input: &[u8]) -> AseParseResult<AsepriteBlendMode> {
267 let (input, blend_mode) = le_u16(input)?;
268
269 Ok((
270 input,
271 match blend_mode {
272 0 => AsepriteBlendMode::Normal,
273 1 => AsepriteBlendMode::Multiply,
274 2 => AsepriteBlendMode::Screen,
275 3 => AsepriteBlendMode::Overlay,
276 4 => AsepriteBlendMode::Darken,
277 5 => AsepriteBlendMode::Lighten,
278 6 => AsepriteBlendMode::ColorDodge,
279 7 => AsepriteBlendMode::ColorBurn,
280 8 => AsepriteBlendMode::HardLight,
281 9 => AsepriteBlendMode::SoftLight,
282 10 => AsepriteBlendMode::Difference,
283 11 => AsepriteBlendMode::Exclusion,
284 12 => AsepriteBlendMode::Hue,
285 13 => AsepriteBlendMode::Saturation,
286 14 => AsepriteBlendMode::Color,
287 15 => AsepriteBlendMode::Luminosity,
288 16 => AsepriteBlendMode::Addition,
289 17 => AsepriteBlendMode::Subtract,
290 18 => AsepriteBlendMode::Divide,
291 unknown => {
292 return Err(nom::Err::Failure(AsepriteParseError::InvalidBlendMode(
293 unknown,
294 )));
295 }
296 },
297 ))
298}
299
300#[derive(Debug, Clone)]
301pub enum AsepritePixel {
303 RGBA(AsepriteColor),
305 Grayscale {
307 intensity: u16,
309 alpha: u16,
311 },
312 Indexed(u8),
314}
315
316impl AsepritePixel {
317 pub fn get_rgba(
319 &self,
320 palette: Option<&AsepritePalette>,
321 transparent_palette: Option<u8>,
322 ) -> AseResult<[u8; 4]> {
323 match self {
324 AsepritePixel::RGBA(color) => Ok([color.red, color.green, color.blue, color.alpha]),
325 AsepritePixel::Grayscale { intensity, alpha } => Ok([
326 (*intensity / 2) as u8,
327 (*intensity / 2) as u8,
328 (*intensity / 2) as u8,
329 (*alpha / 2) as u8,
330 ]),
331 AsepritePixel::Indexed(idx) => {
332 if transparent_palette != Some(*idx) {
333 palette
334 .and_then(|palette| palette.entries.get(*idx as usize))
335 .map(|color| [color.red, color.green, color.blue, color.alpha])
336 .ok_or(AsepriteError::InvalidConfiguration(
337 AsepriteInvalidError::InvalidPaletteIndex(*idx as usize),
338 ))
339 } else {
340 Ok([0; 4])
341 }
342 }
343 }
344 }
345}
346
347fn aseprite_pixel<'a>(
348 input: &'a [u8],
349 header: &'_ RawAsepriteHeader,
350) -> AseParseResult<'a, AsepritePixel> {
351 match header.color_depth {
352 AsepriteColorDepth::RGBA => {
353 let (input, color) = aseprite_color(input)?;
354
355 Ok((input, AsepritePixel::RGBA(color)))
356 }
357 AsepriteColorDepth::Grayscale => {
358 let (input, intensity) = le_u16(input)?;
359 let (input, alpha) = le_u16(input)?;
360
361 Ok((input, AsepritePixel::Grayscale { intensity, alpha }))
362 }
363 AsepriteColorDepth::Indexed => {
364 let (input, index) = le_u8(input)?;
365
366 Ok((input, AsepritePixel::Indexed(index)))
367 }
368 }
369}
370
371fn aseprite_pixels<'a>(
372 input: &'a [u8],
373 header: &'_ RawAsepriteHeader,
374 amt: usize,
375) -> AseParseResult<'a, Vec<AsepritePixel>> {
376 count(|input: &'a [u8]| aseprite_pixel(input, header), amt)(input)
377}
378
379#[derive(Clone)]
380pub enum RawAsepriteCel {
382 Raw {
384 width: u16,
386 height: u16,
388 pixels: Vec<AsepritePixel>,
390 },
391 Linked {
393 frame_position: u16,
395 },
396 Compressed {
398 width: u16,
400 height: u16,
402 pixels: Vec<AsepritePixel>,
404 },
405}
406
407impl std::fmt::Debug for RawAsepriteCel {
408 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409 match self {
410 Self::Raw { .. } => write!(f, "Raw"),
411 Self::Linked { .. } => write!(f, "Linked"),
412 Self::Compressed { .. } => write!(f, "Compressed"),
413 }
414 }
415}
416
417fn aseprite_cel<'a>(
418 input: &'a [u8],
419 header: &'_ RawAsepriteHeader,
420 cel_type: u16,
421) -> AseParseResult<'a, RawAsepriteCel> {
422 match cel_type {
423 0 => {
424 let (input, width) = le_u16(input)?;
425 let (input, height) = le_u16(input)?;
426 let (input, pixels) = aseprite_pixels(input, header, width as usize * height as usize)?;
427
428 Ok((
429 input,
430 RawAsepriteCel::Raw {
431 width,
432 height,
433 pixels,
434 },
435 ))
436 }
437 1 => {
438 let (input, frame_position) = le_u16(input)?;
439
440 Ok((input, RawAsepriteCel::Linked { frame_position }))
441 }
442 2 => {
443 let (input, width) = le_u16(input)?;
444 let (input, height) = le_u16(input)?;
445
446 let mut pixel_data =
453 vec![0; width as usize * height as usize * header.color_depth.bytes_per_pixel()];
454
455 let mut zlib_decompressor = Decompress::new(true);
456 let status = zlib_decompressor
457 .decompress(input, &mut pixel_data, flate2::FlushDecompress::Finish)
458 .map_err(|flate_err| {
459 nom::Err::Failure(AsepriteParseError::InvalidCompressedData(flate_err))
460 })?;
461
462 match status {
463 flate2::Status::Ok | flate2::Status::BufError => {
464 return Err(nom::Err::Failure(
465 AsepriteParseError::NotEnoughCompressedData,
466 ));
467 }
468 flate2::Status::StreamEnd => (),
469 }
470
471 let (_, pixels) =
472 aseprite_pixels(&pixel_data, header, width as usize * height as usize)
473 .map_err(|_| nom::Err::Failure(AsepriteParseError::InvalidCel))?;
474
475 Ok((
476 &input[input.len()..],
477 RawAsepriteCel::Compressed {
478 width,
479 height,
480 pixels,
481 },
482 ))
483 }
484 unknown => Err(nom::Err::Failure(AsepriteParseError::InvalidCelType(
485 unknown,
486 ))),
487 }
488}
489
490#[derive(Debug, Clone, Copy)]
491pub enum AsepriteAnimationDirection {
493 Forward,
497 Reverse,
501 PingPong,
505}
506
507fn aseprite_anim_direction(input: &[u8]) -> AseParseResult<AsepriteAnimationDirection> {
508 let (input, dir) = le_u8(input)?;
509
510 Ok((
511 input,
512 match dir {
513 0 => AsepriteAnimationDirection::Forward,
514 1 => AsepriteAnimationDirection::Reverse,
515 2 => AsepriteAnimationDirection::PingPong,
516 unknown => {
517 return Err(nom::Err::Failure(
518 AsepriteParseError::InvalidAnimationDirection(unknown),
519 ));
520 }
521 },
522 ))
523}
524
525pub struct RawAsepriteTag {
527 pub from: u16,
529 pub to: u16,
531 pub anim_direction: AsepriteAnimationDirection,
533 pub name: String,
535}
536
537fn aseprite_tag(input: &[u8]) -> AseParseResult<RawAsepriteTag> {
538 let (input, from) = le_u16(input)?;
539 let (input, to) = le_u16(input)?;
540 let (input, anim_direction) = aseprite_anim_direction(input)?;
541 let (input, _) = take(8usize)(input)?;
542 let (input, _) = take(3usize)(input)?;
543 let (input, _) = take(1usize)(input)?;
544 let (input, name) = aseprite_string(input)?;
545
546 Ok((
547 input,
548 RawAsepriteTag {
549 from,
550 to,
551 anim_direction,
552 name,
553 },
554 ))
555}
556
557pub enum RawAsepriteChunk {
559 Layer {
563 flags: u16,
573 layer_type: AsepriteLayerType,
575 layer_child: u16,
579 width: u16,
583 height: u16,
587 blend_mode: AsepriteBlendMode,
589 opacity: u8,
591 name: String,
593 },
594 Cel {
596 layer_index: u16,
598 x: i16,
600 y: i16,
602 opacity: u8,
604 cel: RawAsepriteCel,
606 },
607 CelExtra {
609 flags: u32,
613 x: f64,
615 y: f64,
617 width: f64,
619 height: f64,
621 },
622 Tags {
624 tags: Vec<RawAsepriteTag>,
626 },
627 Palette {
629 palette_size: u32,
631 from_color: u32,
633 to_color: u32,
635 entries: Vec<RawAsepritePaletteEntry>,
637 },
638 UserData {
640 data: RawAsepriteUserData,
642 },
643 Slice {
645 flags: u32,
647 name: String,
649 slices: Vec<RawAsepriteSlice>,
651 },
652 ColorProfile {
654 profile_type: u16,
656 flags: u16,
660 gamma: f64,
662 icc_profile: Option<RawAsepriteIccProfile>,
664 },
665}
666
667pub struct RawAsepriteIccProfile {
669 pub icc_profile: Vec<u8>,
671}
672
673fn aseprite_icc_profile(input: &[u8]) -> AseParseResult<RawAsepriteIccProfile> {
674 let (input, icc_profile) = length_data(le_u32)(input)?;
675
676 Ok((
677 input,
678 RawAsepriteIccProfile {
679 icc_profile: icc_profile.to_vec(),
680 },
681 ))
682}
683
684fn color_profile_chunk(input: &[u8]) -> AseParseResult<RawAsepriteChunk> {
685 let (input, profile_type) = le_u16(input)?;
686 let (input, flags) = le_u16(input)?;
687 let (input, gamma) = aseprite_fixed(input)?;
688 let (input, _) = take(8usize)(input)?;
689
690 let (input, icc_profile) = cond(profile_type & 0x2 != 0, aseprite_icc_profile)(input)?;
691
692 Ok((
693 input,
694 RawAsepriteChunk::ColorProfile {
695 profile_type,
696 flags,
697 gamma,
698 icc_profile,
699 },
700 ))
701}
702
703pub struct RawAsepriteSlice {
705 pub frame: u32,
707 pub x_origin: i32,
709 pub y_origin: i32,
711 pub width: u32,
715 pub height: u32,
717 pub nine_patch_info: Option<AsepriteNinePatchInfo>,
719 pub pivot: Option<AsepritePivot>,
721}
722
723#[derive(Debug, Clone)]
724pub struct AsepriteNinePatchInfo {
726 pub x_center: i32,
728 pub y_center: i32,
730 pub width: u32,
732 pub height: u32,
734}
735
736fn aseprite_nine_patch_info(input: &[u8]) -> AseParseResult<AsepriteNinePatchInfo> {
737 let (input, x_center) = le_i32(input)?;
738 let (input, y_center) = le_i32(input)?;
739 let (input, width) = le_u32(input)?;
740 let (input, height) = le_u32(input)?;
741
742 Ok((
743 input,
744 AsepriteNinePatchInfo {
745 x_center,
746 y_center,
747 width,
748 height,
749 },
750 ))
751}
752
753pub struct AsepritePivot {
755 pub x_pivot: i32,
757 pub y_pivot: i32,
759}
760
761fn aseprite_pivot(input: &[u8]) -> AseParseResult<AsepritePivot> {
762 let (input, x_pivot) = le_i32(input)?;
763 let (input, y_pivot) = le_i32(input)?;
764
765 Ok((input, AsepritePivot { x_pivot, y_pivot }))
766}
767
768fn aseprite_slice(input: &[u8], flags: u32) -> AseParseResult<RawAsepriteSlice> {
769 let (input, frame) = le_u32(input)?;
770 let (input, x_origin) = le_i32(input)?;
771 let (input, y_origin) = le_i32(input)?;
772 let (input, width) = le_u32(input)?;
773 let (input, height) = le_u32(input)?;
774 let (input, nine_patch_info) = cond(flags & 0x1 != 0, aseprite_nine_patch_info)(input)?;
775 let (input, pivot) = cond(flags & 0x2 != 0, aseprite_pivot)(input)?;
776
777 Ok((
778 input,
779 RawAsepriteSlice {
780 frame,
781 x_origin,
782 y_origin,
783 width,
784 height,
785 nine_patch_info,
786 pivot,
787 },
788 ))
789}
790
791fn aseprite_slices(
792 input: &[u8],
793 slice_count: usize,
794 flags: u32,
795) -> AseParseResult<Vec<RawAsepriteSlice>> {
796 count(|input| aseprite_slice(input, flags), slice_count)(input)
797}
798
799fn slice_chunk(input: &[u8]) -> AseParseResult<RawAsepriteChunk> {
800 let (input, slice_count) = le_u32(input)?;
801 let (input, flags) = le_u32(input)?;
802 let (input, _) = le_u32(input)?;
803 let (input, name) = aseprite_string(input)?;
804 let (input, slices) = aseprite_slices(input, slice_count as usize, flags)?;
805
806 Ok((
807 input,
808 RawAsepriteChunk::Slice {
809 flags,
810 name,
811 slices,
812 },
813 ))
814}
815
816fn user_data_chunk(input: &[u8]) -> AseParseResult<RawAsepriteChunk> {
817 let (input, data) = aseprite_user_data(input)?;
818
819 Ok((input, RawAsepriteChunk::UserData { data }))
820}
821
822pub struct RawAsepritePaletteEntry {
824 pub color: AsepriteColor,
826 pub name: Option<String>,
828}
829
830fn aseprite_palette(input: &[u8]) -> AseParseResult<RawAsepritePaletteEntry> {
831 let (input, flags) = le_u16(input)?;
832 let (input, color) = aseprite_color(input)?;
833
834 let (input, name) = cond(flags & 0x1 == 0x1, aseprite_string)(input)?;
835
836 Ok((input, RawAsepritePaletteEntry { color, name }))
837}
838
839fn aseprite_palettes(
840 input: &[u8],
841 palette_count: usize,
842) -> AseParseResult<Vec<RawAsepritePaletteEntry>> {
843 count(aseprite_palette, palette_count)(input)
844}
845
846fn palette_chunk(input: &[u8]) -> AseParseResult<RawAsepriteChunk> {
847 let (input, palette_size) = le_u32(input)?;
848 let (input, from_color) = le_u32(input)?;
849 let (input, to_color) = le_u32(input)?;
850 let (input, _) = take(8usize)(input)?;
851
852 let (input, entries) = aseprite_palettes(input, (to_color - from_color + 1) as usize)?;
853
854 Ok((
855 input,
856 RawAsepriteChunk::Palette {
857 palette_size,
858 from_color,
859 to_color,
860 entries,
861 },
862 ))
863}
864
865fn tags(input: &[u8], tag_count: u16) -> AseParseResult<Vec<RawAsepriteTag>> {
866 count(aseprite_tag, tag_count as usize)(input)
867}
868
869fn tags_chunk(input: &[u8]) -> AseParseResult<RawAsepriteChunk> {
870 let (input, tag_count) = le_u16(input)?;
871 let (input, _) = take(8usize)(input)?;
872 let (input, tags) = tags(input, tag_count)?;
873
874 Ok((input, RawAsepriteChunk::Tags { tags }))
875}
876
877fn aseprite_fixed(input: &[u8]) -> AseParseResult<f64> {
878 let (input, whole) = le_u32(input)?;
879
880 Ok((input, whole as f64 / 0x10000 as f64))
881}
882
883fn cel_extra_chunk(input: &[u8]) -> AseParseResult<RawAsepriteChunk> {
884 let (input, flags) = le_u32(input)?;
885 let (input, x) = aseprite_fixed(input)?;
886 let (input, y) = aseprite_fixed(input)?;
887 let (input, width) = aseprite_fixed(input)?;
888 let (input, height) = aseprite_fixed(input)?;
889
890 Ok((
891 input,
892 RawAsepriteChunk::CelExtra {
893 flags,
894 x,
895 y,
896 width,
897 height,
898 },
899 ))
900}
901
902fn cel_chunk<'a>(
903 input: &'a [u8],
904 header: &'_ RawAsepriteHeader,
905) -> AseParseResult<'a, RawAsepriteChunk> {
906 let (input, layer_index) = le_u16(input)?;
907 let (input, x) = le_i16(input)?;
908 let (input, y) = le_i16(input)?;
909 let (input, opacity) = le_u8(input)?;
910 let (input, cel_type) = le_u16(input)?;
911 let (input, _) = take(7usize)(input)?;
912 let (input, cel) = aseprite_cel(input, header, cel_type)?;
914
915 Ok((
916 input,
917 RawAsepriteChunk::Cel {
918 layer_index,
919 x,
920 y,
921 opacity,
922 cel,
923 },
924 ))
925}
926
927fn layer_chunk(input: &[u8]) -> AseParseResult<RawAsepriteChunk> {
928 let (input, flags) = le_u16(input)?;
929 let (input, layer_type) = aseprite_layer_type(input)?;
930 let (input, layer_child) = le_u16(input)?;
931 let (input, width) = le_u16(input)?;
932 let (input, height) = le_u16(input)?;
933 let (input, blend_mode) = aseprite_blend_mode(input)?;
934 let (input, opacity) = le_u8(input)?;
935 let (input, _) = take(3usize)(input)?;
936 let (input, name) = aseprite_string(input)?;
937
938 Ok((
939 input,
940 RawAsepriteChunk::Layer {
941 flags,
942 layer_type,
943 layer_child,
944 width,
945 height,
946 blend_mode,
947 opacity,
948 name,
949 },
950 ))
951}
952
953fn aseprite_chunk<'a>(
954 input: &'a [u8],
955 header: &'_ RawAsepriteHeader,
956) -> AseParseResult<'a, Option<RawAsepriteChunk>> {
957 let input_len = input.len();
958 let (input, chunk_size) = le_u32(input)?;
959 let (input, chunk_type) = le_u16(input)?;
960 let (input, chunk_data) = take(chunk_size as usize - (input_len - input.len()))(input)?;
962
963 let _span = debug_span!("chunk", chunk_type);
964
965 let res =
966 match chunk_type {
967 0x0004 => {
968 info!("Ignoring chunk of kind {} (Old palette chunk)", chunk_type);
969 None
970 }
971 0x0011 => {
972 info!("Ignoring chunk of kind {} (Old palette chunk)", chunk_type);
973 None
974 }
975 0x2004 => Some(all_consuming(layer_chunk)(chunk_data).map_err(|err| {
976 err.map(|err| AsepriteParseError::InvalidLayerChunk(Box::new(err)))
977 })?),
978 0x2005 => Some(
979 all_consuming(|input: &'a [u8]| cel_chunk(input, header))(chunk_data).map_err(
980 |err| err.map(|err| AsepriteParseError::InvalidCelChunk(Box::new(err))),
981 )?,
982 ),
983 0x2006 => Some(all_consuming(cel_extra_chunk)(chunk_data).map_err(|err| {
984 err.map(|err| AsepriteParseError::InvalidCelExtraChunk(Box::new(err)))
985 })?),
986 0x2007 => Some(color_profile_chunk(chunk_data).map_err(|err| {
987 err.map(|err| AsepriteParseError::InvalidColorProfileChunk(Box::new(err)))
988 })?),
989 0x2016 => {
990 info!("Got a deprecated profile chunk");
991 None
992 }
993 0x2018 => Some(all_consuming(tags_chunk)(chunk_data).map_err(|err| {
994 err.map(|err| AsepriteParseError::InvalidTagsChunk(Box::new(err)))
995 })?),
996 0x2019 => Some(all_consuming(palette_chunk)(chunk_data).map_err(|err| {
997 err.map(|err| AsepriteParseError::InvalidPaletteChunk(Box::new(err)))
998 })?),
999 0x2020 => Some(all_consuming(user_data_chunk)(chunk_data).map_err(|err| {
1000 err.map(|err| AsepriteParseError::InvalidUserDataChunk(Box::new(err)))
1001 })?),
1002 0x2022 => Some(all_consuming(slice_chunk)(chunk_data).map_err(|err| {
1003 err.map(|err| AsepriteParseError::InvalidSliceChunk(Box::new(err)))
1004 })?),
1005 chunk_type => {
1006 error!("Got unknown chunk type: {:?}", chunk_type);
1007 None
1008 }
1009 };
1010
1011 Ok((input, res.map(|(_, chunk)| chunk)))
1012}
1013
1014const ASEPRITE_FRAME_MAGIC_NUMBER: u16 = 0xF1FA;
1015
1016fn aseprite_frame<'a>(
1017 input: &'a [u8],
1018 header: &'_ RawAsepriteHeader,
1019) -> AseParseResult<'a, RawAsepriteFrame> {
1020 let (input, magic_number) = tag(&ASEPRITE_FRAME_MAGIC_NUMBER.to_le_bytes())(input)?;
1021 let (input, small_chunk_count) = le_u16(input)?;
1022 let (input, duration_ms) = le_u16(input)?;
1023 let (input, _) = take(2usize)(input)?;
1024 let (input, chunk_count) = le_u32(input)?;
1025
1026 let actual_count = if chunk_count == 0 {
1028 small_chunk_count as usize
1029 } else {
1030 chunk_count as usize
1031 };
1032
1033 let (input, chunks) = count(
1034 |input: &'a [u8]| aseprite_chunk(input, header),
1035 actual_count,
1036 )(input)?;
1037
1038 let chunks = chunks.into_iter().flatten().collect();
1039
1040 Ok((
1041 input,
1042 RawAsepriteFrame {
1043 magic_number: u16::from_le_bytes(
1044 magic_number
1045 .try_into()
1046 .expect("Invalid ASEPRITE_FRAME_MAGIC_NUMBER matched. This is a bug."),
1047 ),
1048 duration_ms,
1049 chunks,
1050 },
1051 ))
1052}
1053
1054fn aseprite_frames<'a>(
1055 input: &'a [u8],
1056 header: &'_ RawAsepriteHeader,
1057) -> AseParseResult<'a, Vec<RawAsepriteFrame>> {
1058 all_consuming(many1(
1059 |input: &'a [u8]| -> AseParseResult<RawAsepriteFrame> {
1060 let (input, _length) = le_u32(input)?;
1061 aseprite_frame(input, header)
1062 },
1063 ))(input)
1064}
1065
1066pub struct RawAseprite {
1068 pub header: RawAsepriteHeader,
1070 pub frames: Vec<RawAsepriteFrame>,
1072}
1073
1074fn aseprite(input: &[u8]) -> AseParseResult<RawAseprite> {
1075 let (input, header) = aseprite_header(input)?;
1076 let (input, frames) = aseprite_frames(input, &header)?;
1077
1078 Ok((input, RawAseprite { header, frames }))
1079}
1080
1081pub fn read_aseprite(input: &[u8]) -> Result<RawAseprite, AsepriteError> {
1083 let (_, ase) = aseprite(input).finish()?;
1084
1085 Ok(ase)
1086}
1087
1088#[cfg(test)]
1089#[allow(deprecated)]
1090mod test {
1091 use super::{aseprite_frames, aseprite_header, RawAsepriteHeader, ASEPRITE_MAGIC_NUMBER};
1092
1093 #[test]
1094 fn check_valid_file_header() {
1095 let ase_file = std::fs::read("./tests/test_cases/simple.aseprite").unwrap();
1096
1097 let (_rest, raw_header) = aseprite_header(&ase_file).unwrap();
1098
1099 let expected = RawAsepriteHeader {
1100 file_size: 787,
1101 magic_number: ASEPRITE_MAGIC_NUMBER,
1102 frames: 1,
1103 width: 123,
1104 height: 456,
1105 color_depth: super::AsepriteColorDepth::RGBA,
1106 flags: 1,
1107 speed: 125,
1108 transparent_palette: 0,
1109 color_count: 32,
1110 pixel_width: 1,
1111 pixel_height: 1,
1112 grid_x: 0,
1113 grid_y: 0,
1114 grid_width: 16,
1115 grid_height: 16,
1116 };
1117
1118 assert_eq!(raw_header, expected);
1119 }
1120
1121 #[test]
1122 fn check_valid_file() {
1123 let ase_file = std::fs::read("./tests/test_cases/simple.aseprite").unwrap();
1124
1125 let (body, raw_header) = aseprite_header(&ase_file).unwrap();
1126
1127 let (rest, raw_body) = aseprite_frames(body, &raw_header).unwrap();
1128
1129 assert_eq!(rest.len(), 0);
1130 assert_eq!(raw_body.len(), 1);
1131 let frame = &raw_body[0];
1132
1133 assert_eq!(frame.duration_ms, 125);
1134 }
1135}