예제 #1
0
        /// <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);
            }
        }