aseprite_reader2/
raw.rs

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// As specified in https://github.com/aseprite/aseprite/blob/fc79146c56f941f834f28809f0d2c4d7fd60076c/docs/ase-file-specs.md
19
20/// Color depth in a single .aseprite file
21#[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/// The raw Aseprite Header
40#[derive(Debug, PartialEq)]
41pub struct RawAsepriteHeader {
42    /// File size of the .aseprite file
43    pub file_size: u32,
44    /// Magic number in the file, always `0xA5E0`
45    pub magic_number: u16,
46    /// Amount of frames in the body of the file
47    pub frames: u16,
48    /// Base width
49    pub width: u16,
50    /// Base height
51    pub height: u16,
52    /// The color depth used
53    pub color_depth: AsepriteColorDepth,
54    /// Flags for this file
55    ///
56    /// - 1 = Layer opacity has a valid value
57    pub flags: u32,
58    /// Milliseconds between frames (DEPRECATED)
59    #[deprecated = "You should use the duration in each frame"]
60    pub speed: u16,
61    /// Palette entry which should be considered transparent
62    ///
63    /// This is only useful for indexed colors
64    pub transparent_palette: u8,
65    /// The amount of colors in the palette
66    pub color_count: u16,
67    /// Width of one pixel
68    pub pixel_width: u8,
69    /// Height of one pixel
70    pub pixel_height: u8,
71    /// Grid x start position
72    pub grid_x: i16,
73    /// Grid y start position
74    pub grid_y: i16,
75    /// Grid width
76    pub grid_width: u16,
77    /// Grid height
78    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
165/// A raw frame
166pub struct RawAsepriteFrame {
167    /// The magic frame number, always `0xF1FA`
168    pub magic_number: u16,
169    /// Duration of this frame, in ms
170    pub duration_ms: u16,
171    /// The chunks in this frame
172    pub chunks: Vec<RawAsepriteChunk>,
173}
174
175/// A full RGBA color
176#[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
199/// Raw user data
200pub struct RawAsepriteUserData {
201    /// Text, if any
202    pub text: Option<String>,
203    /// Color, if any
204    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
216/// Layer type
217pub enum AsepriteLayerType {
218    /// A normal layer
219    Normal,
220    /// A layer group
221    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/// The different blend modes
243#[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)]
301/// A single pixel
302pub enum AsepritePixel {
303    /// Pixel in RGBA format
304    RGBA(AsepriteColor),
305    /// A grayscale pixel
306    Grayscale {
307        /// Gray intensity
308        intensity: u16,
309        /// Alpha value (opacity)
310        alpha: u16,
311    },
312    /// Indexed pixel
313    Indexed(u8),
314}
315
316impl AsepritePixel {
317    /// Get the pixel as an array of RGBA values
318    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)]
380/// Raw Cel
381pub enum RawAsepriteCel {
382    /// Raw Cel Data
383    Raw {
384        /// Width in pixels
385        width: u16,
386        /// Height in pixels
387        height: u16,
388        /// The pixels themselves
389        pixels: Vec<AsepritePixel>,
390    },
391    /// Linked Cel Data
392    Linked {
393        /// Frame position to link with
394        frame_position: u16,
395    },
396    /// Compressed Cel Data
397    Compressed {
398        /// Width in pixels
399        width: u16,
400        /// Height in pixels
401        height: u16,
402        /// The decompressed pixels
403        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 (input, width) = le_u16(input)?;
447            // let (input, height) = le_u16(input)?;
448
449            // assert_eq!(outer_width, width);
450            // assert_eq!(outer_height, height);
451
452            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)]
491/// Animation Direction
492pub enum AsepriteAnimationDirection {
493    /// Forward animation direction
494    ///
495    /// When encountering the end, starts from the beginning
496    Forward,
497    /// Reverse animation direction
498    ///
499    /// When encountering the start, starts from the end
500    Reverse,
501    /// Ping-Pong animation direction
502    ///
503    /// Starts at beginning and reverses direction whenever it hits either end or beginning
504    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
525/// A raw Tag
526pub struct RawAsepriteTag {
527    /// Starting frame
528    pub from: u16,
529    /// End frame
530    pub to: u16,
531    /// animation direction
532    pub anim_direction: AsepriteAnimationDirection,
533    /// name of the tag
534    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
557/// Raw Chunk
558pub enum RawAsepriteChunk {
559    /// Layer Chunk
560    ///
561    /// All the layer chunks determine the general layer layout
562    Layer {
563        /// The flags set for this layer
564        ///
565        /// 1 = Visible
566        /// 2 = Editable
567        /// 4 = Lock Movement
568        /// 8 = Background
569        /// 16 = Prefer linked cels
570        /// 32 = The layer group should be displayed collapsed
571        /// 64 = The layer is a reference layer
572        flags: u16,
573        /// Type of the layer
574        layer_type: AsepriteLayerType,
575        /// How deep the child is in the hierarchy
576        ///
577        /// The higher, the deeper in the previous chunk
578        layer_child: u16,
579        /// layer width
580        ///
581        /// This is ignored
582        width: u16,
583        /// layer height
584        ///
585        /// This is ignored
586        height: u16,
587        /// The blend mode of the layer
588        blend_mode: AsepriteBlendMode,
589        /// Opacity of this layer
590        opacity: u8,
591        /// The name of the layer
592        name: String,
593    },
594    /// A Cel is a container of pixel
595    Cel {
596        /// Which layer this cel corresponds to (0 based)
597        layer_index: u16,
598        /// x position
599        x: i16,
600        /// y position
601        y: i16,
602        /// Opacity of the cel
603        opacity: u8,
604        /// The cel content
605        cel: RawAsepriteCel,
606    },
607    /// Extra data for the previous cel
608    CelExtra {
609        /// Flags for the extra cel
610        ///
611        /// - 1 = Precise bounds are set
612        flags: u32,
613        /// Precise x position
614        x: f64,
615        /// Precise y position
616        y: f64,
617        /// precise width of the cel
618        width: f64,
619        /// precise height of the cel
620        height: f64,
621    },
622    /// Tags for this image
623    Tags {
624        /// the different tags
625        tags: Vec<RawAsepriteTag>,
626    },
627    /// A color palette
628    Palette {
629        /// The total count of entries in the palette
630        palette_size: u32,
631        /// First color index to change
632        from_color: u32,
633        /// Last color index to change
634        to_color: u32,
635        /// The individual palette entries
636        entries: Vec<RawAsepritePaletteEntry>,
637    },
638    /// User Data for the last chunk
639    UserData {
640        /// the data itself
641        data: RawAsepriteUserData,
642    },
643    /// A slice in the image
644    Slice {
645        /// the flags for this slice
646        flags: u32,
647        /// the name of the slices
648        name: String,
649        /// the individual slices
650        slices: Vec<RawAsepriteSlice>,
651    },
652    /// An embedded color profile
653    ColorProfile {
654        /// The type of color profile
655        profile_type: u16,
656        /// The flags for this color profile
657        ///
658        /// 1 = use the fixed gamma
659        flags: u16,
660        /// Fixed gamma
661        gamma: f64,
662        /// An embedded ICC Profile
663        icc_profile: Option<RawAsepriteIccProfile>,
664    },
665}
666
667/// A raw Icc Profile
668pub struct RawAsepriteIccProfile {
669    /// The bytes of the icc profile
670    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
703/// Raw Slice
704pub struct RawAsepriteSlice {
705    /// For which frame this slice is valid from (to the end of the animation)
706    pub frame: u32,
707    /// x origin, relative to the sprite
708    pub x_origin: i32,
709    /// y origin, relative to the sprite
710    pub y_origin: i32,
711    /// slice width
712    ///
713    /// this may be 0 if hidden from the given frame
714    pub width: u32,
715    /// slice height
716    pub height: u32,
717    /// 9-Patch info, if any
718    pub nine_patch_info: Option<AsepriteNinePatchInfo>,
719    /// A pivot, if any
720    pub pivot: Option<AsepritePivot>,
721}
722
723#[derive(Debug, Clone)]
724/// 9-Patch slice info
725pub struct AsepriteNinePatchInfo {
726    /// x center, relative to slice bounds
727    pub x_center: i32,
728    /// y center, relative to slice bounds
729    pub y_center: i32,
730    /// width of center
731    pub width: u32,
732    /// height of center
733    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
753/// A raw pivot inside a slice
754pub struct AsepritePivot {
755    /// x position, relative to origin
756    pub x_pivot: i32,
757    /// y position, relative to origin
758    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
822/// A raw palette entry
823pub struct RawAsepritePaletteEntry {
824    /// color of this entry
825    pub color: AsepriteColor,
826    /// name of this entry
827    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    // We do not immediately try to load the cel, as the reserved bytes are decoupled from the type itself
913    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    // Get the remaining data of this chunk and parse it as the corresponding type
961    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    // As per spec, if an older file is being read, it might not set chunk_count yet, so we use small_chunk_count
1027    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
1066/// A raw .aseprite file
1067pub struct RawAseprite {
1068    /// The header describes how the rest of the file is to be interpreted
1069    pub header: RawAsepriteHeader,
1070    /// A vector of frames inside the file
1071    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
1081/// Read a [`RawAseprite`] from memory
1082pub 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}