private void ReadAsOldPalleteA(AsepriteReader reader) { // Read the number of packets ushort numberOfPackets = reader.ReadWORD(); List <AsepritePaletteColor> colors = new List <AsepritePaletteColor>(); for (int i = 0; i < numberOfPackets; i++) { // Read the number of palette entries to skip from the last packet // But we're going to ignore the value since we don't need it. _ = reader.ReadByte(); // Read the number of colors in the packet int numberOfColors = reader.ReadByte(); if (numberOfColors == 0) { numberOfColors = 256; } for (int c = 0; c < numberOfColors; c++) { colors.Add(new AsepritePaletteColor(reader, false)); } } Colors = colors.ToArray(); }
/// <summary> /// Creates a new <see cref="AsepritePaletteColor"/> instance. /// </summary> /// <param name="reader"> /// The <see cref="AsepriteReader"/> instance being used to read the /// Aseprite file. /// </param> internal AsepritePaletteColor(AsepriteReader reader, bool isNewPalette) { if (isNewPalette) { // Only read flag if this is the new palette type. _flag = (AsepritePaletteFlags)reader.ReadWORD(); } Red = reader.ReadByte(); Green = reader.ReadByte(); Blue = reader.ReadByte(); if (isNewPalette) { // Only read alpha value if this is the new palette type Alpha = reader.ReadByte(); } else { Alpha = 255; } PackedValue = Utils.BytesToPacked(Red, Green, Blue, Alpha); // If the HasName flag is present, we need to read the string value, however // this seems to always never exist. Not sure what the field is for, but may // just be some compatibility thing with named palette formats like .gpl. if ((_flag & AsepritePaletteFlags.HasName) != 0) { Name = reader.ReadString(); } }
/// <summary> /// Creates a new <see cref="AsepriteLayerChunk"/> instance. /// </summary> /// <param name="reader"> /// The <see cref="AsepriteReader"/> instance being used to read the /// Aseprite file. /// </param> internal AsepriteLayerChunk(AsepriteReader reader) { // Read the flags that are set for this layer. Flags = (AsepriteLayerFlags)reader.ReadWORD(); // Read the type of layer we're dealing with. Type = (AsepriteLayerType)reader.ReadWORD(); // Read the sub level of this layer. If this layer is not a // child layer, this value will be 0. ChildLevel = reader.ReadWORD(); // Per ase file spec, default layer width in pixels is ignored _ = reader.ReadWORD(); // Per ase file spec, default layer height in pixels is ignored _ = reader.ReadWORD(); // Read the blend mode used by this layer. BlendMode = (AsepriteBlendMode)reader.ReadWORD(); // Read the opacity level for this layer. Opacity = reader.ReadByte(); // Per ase file spec, ignroe next 3 bytes, they are reserved for future use reader.Ignore(3); // Read the name of this layer. Name = reader.ReadString(); }
/// <summary> /// Reads the userdata values for this chunk from the provided /// reader. /// </summary> /// <param name="reader"> /// The <see cref="AsepriteReader"/> instance being used to read the /// Aseprite file. /// </param> internal void ReadUserData(AsepriteReader reader) { AsepriteUserDataFlags flags = (AsepriteUserDataFlags)reader.ReadDWORD(); if ((flags & AsepriteUserDataFlags.HasText) != 0) { UserDataText = reader.ReadString(); } if ((flags & AsepriteUserDataFlags.HasColor) != 0) { UserDataColor = new byte[4]; UserDataColor[0] = reader.ReadByte(); UserDataColor[1] = reader.ReadByte(); UserDataColor[2] = reader.ReadByte(); UserDataColor[3] = reader.ReadByte(); } }
/// <summary> /// Creates a new <see cref="AsepriteTagChunk"/> instance. /// </summary> /// <param name="reader"> /// The <see cref="AsepriteReader"/> instance being used to read the /// Aseprite file. /// </param> internal AsepriteTagChunk(AsepriteReader reader) { From = reader.ReadWORD(); To = reader.ReadWORD(); Direction = (AsepriteLoopDirection)reader.ReadByte(); // Per ase file spec, ignore next 8 bytes, they are reserved for future use reader.Ignore(8); ColorR = reader.ReadByte(); ColorG = reader.ReadByte(); ColorB = reader.ReadByte(); // Per ase file spec, ignore next byte, it's just an extra one set to zero reader.Ignore(1); Name = reader.ReadString(); }
/// <summary> /// Creates a new <see cref="AsepriteHeader"/> instance. /// </summary> /// <param name="reader"> /// The <see cref="AsepriteReader"/> instance being used to read the /// Aseprite file. /// </param> internal AsepriteHeader(AsepriteReader reader) { // Get the basestream position of the reader long headerStart = reader.BaseStream.Position; // Header is 128 bytes. Calcualte the base stream position that is // at the end of the header long headerEnd = headerStart + 128; // Read but ignore the file size _ = reader.ReadDWORD(); // Read and validate the magic number if (reader.ReadWORD() != 0xA5E0) { throw new Exception($"File given does not appear to be a valid .ase/.aseprite file!"); } FrameCount = reader.ReadWORD(); Width = reader.ReadWORD(); Height = reader.ReadWORD(); ColorDepth = (AsepriteColorDepth)(reader.ReadWORD() / 8); _flags = (AsepriteHeaderFlags)reader.ReadDWORD(); // Per ase file specs, the speed field is deprecated, so we'll // ignroe it. _ = reader.ReadWORD(); // Per ase file specs, next two DWORDs are ignored. _ = reader.ReadDWORD(); _ = reader.ReadDWORD(); TransparentIndex = reader.ReadByte(); // Per ase file specs, next 3 bytes are ignored reader.Ignore(3); ColorCount = reader.ReadWORD(); // We're going to ignore the rest of the header as we don't need // the information. For documentation though, the following is // what we are skipping // // Pixel Width // Pixel Height // X position of the grid // Y position of the grid // Grid width (zero if there is no grid, grid size is 16x16 on Aseprite default) // Grid height (zero if there is no grid // 84 bytes which are reserved for future use. // // Since we are skipping all this, we'll just set the reader's basestream to // the end of the header position we calculated earlier reader.BaseStream.Position = headerEnd; }
/// <summary> /// Creates a new <see cref="AsepriteCelChunk"/> instance. /// <param name="reader"> /// The <see cref="AsepriteReader"/> instance being used to read the /// Aseprite file. /// </param> /// <param name="frame"> /// The <see cref="AsepriteFrame"/> this cel is contained within. /// </param> /// <param name="dataSize"> /// The total byte size of the data for this cel chunk. /// </param> internal AsepriteCelChunk(AsepriteReader reader, AsepriteFrame frame, int dataSize) { // We need to cache the position of the reader before reading any data so we can // calculate the amount of data to read later for the pixel info. long readerPos = reader.BaseStream.Position; LayerIndex = reader.ReadWORD(); X = reader.ReadSHORT(); Y = reader.ReadSHORT(); Opacity = reader.ReadByte(); CelType = (AsepriteCelType)reader.ReadWORD(); // Per ase file spec, ignore next 7 bytes, they are reserved for future use. reader.Ignore(7); if (CelType == AsepriteCelType.Raw || CelType == AsepriteCelType.Compressed) { Width = reader.ReadWORD(); Height = reader.ReadWORD(); // Calculate the remaning data to read in the cel chunk long bytesToRead = dataSize - (reader.BaseStream.Position - readerPos); // Read the remaning bytes into a buffer byte[] buffer = reader.ReadBytes((int)bytesToRead); if (CelType == AsepriteCelType.Raw) { // For raw cel, the buffer is the raw pixel data PixelData = new byte[buffer.Length]; Buffer.BlockCopy(buffer, 0, PixelData, 0, buffer.Length); } else { // For compressed, we need to deflate the buffer. First, we'll put it in a // memory stream to work with MemoryStream compressedStream = new MemoryStream(buffer); // The first 2 bytes of the compressed stream are the zlib header informaiton, // and we need to ignore them before we attempt to deflate _ = compressedStream.ReadByte(); _ = compressedStream.ReadByte(); // Now we can deflate the compressed stream using (MemoryStream decompressedStream = new MemoryStream()) { using (DeflateStream deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress)) { deflateStream.CopyTo(decompressedStream); PixelData = decompressedStream.ToArray(); } } } Pixels = new uint[Width * Height]; if (frame.File.Header.ColorDepth == AsepriteColorDepth.RGBA) { for (int i = 0, b = 0; i < Pixels.Length; i++, b += 4) { Pixels[i] = Utils.BytesToPacked(PixelData[b], PixelData[b + 1], PixelData[b + 2], PixelData[b + 3]); } } else if (frame.File.Header.ColorDepth == AsepriteColorDepth.Grayscale) { for (int i = 0, b = 0; i < Pixels.Length; i++, b += 2) { Pixels[i] = Utils.BytesToPacked(PixelData[b], PixelData[b], PixelData[b], PixelData[b + 1]); } } else if (frame.File.Header.ColorDepth == AsepriteColorDepth.Indexed) { for (int i = 0; i < Pixels.Length; i++) { int paletteIndex = PixelData[i]; if (paletteIndex == frame.File.Header.TransparentIndex) { Pixels[i] = Utils.BytesToPacked(0, 0, 0, 0); } else { AsepritePaletteColor paletteColor = frame.File.Palette.Colors[paletteIndex]; Microsoft.Xna.Framework.Color color = new Microsoft.Xna.Framework.Color(paletteColor.PackedValue); Pixels[i] = Utils.BytesToPacked(paletteColor.Red, paletteColor.Green, paletteColor.Blue, paletteColor.Alpha); } } } else { throw new Exception($"Unrecognized color depth mode. {frame.File.Header.ColorDepth}"); } } else if (CelType == AsepriteCelType.Linked) { ushort linkedFrame = reader.ReadWORD(); // Get a refrence to the cel this cel is linked to. LinkedCel = frame.File.Frames[linkedFrame].Cels .FirstOrDefault(c => c.LayerIndex == LayerIndex); } }