public static UserDataChunk Read(AsepriteStreamReader reader) { //DWORD Flags // 1 = Has text // 2 = Has color var flag = reader.DWORD(); //+ If flags have bit 1 // STRING Text if (reader.FLAG(flag, 1)) { return(new UserDataChunk(reader.STRING())); } //+If flags have bit 2 // BYTE Color Red(0 - 255) // BYTE Color Green(0 - 255) // BYTE Color Blue(0 - 255) // BYTE Color Alpha(0 - 255) if (reader.FLAG(flag, 2)) { return(new UserDataChunk(reader.BYTE(), reader.BYTE(), reader.BYTE(), reader.BYTE())); } return(new UserDataChunk()); }
public static LayerChunk Read(AsepriteStreamReader reader) { // WORD Flags: // 1 = Visible // 2 = Editable // 4 = Lock movement // 8 = Background // 16 = Prefer linked cels // 32 = The layer group should be displayed collapsed // 64 = The layer is a reference layer var flags = (LayerFlags)reader.WORD(); // WORD Layer type // 0 = Normal(image) layer // 1 = Group var type = (LayerTypes)reader.WORD(); // WORD Layer child level(see NOTE.1) var childLevel = reader.WORD(); // WORD Default layer width in pixels(ignored) reader.WORD(); // WORD Default layer height in pixels(ignored) reader.WORD(); // WORD Blend mode(always 0 for layer set) // Normal = 0 // Multiply = 1 // Screen = 2 // Overlay = 3 // Darken = 4 // Lighten = 5 // Color Dodge = 6 // Color Burn = 7 // Hard Light = 8 // Soft Light = 9 // Difference = 10 // Exclusion = 11 // Hue = 12 // Saturation = 13 // Color = 14 // Luminosity = 15 // Addition = 16 // Subtract = 17 // Divide = 18 var blendMode = (BlendModes)reader.WORD(); // BYTE Opacity var opacity = reader.BYTE(); // Note: valid only if file header flags field has bit 1 set // BYTE[3] For future(set to zero) reader.BYTES(3); // STRING Layer name var name = reader.STRING(); return(new LayerChunk(flags, type, childLevel, blendMode, opacity, name)); }
public static TagsChunk Read(AsepriteStreamReader reader) { //WORD Number of tags var tagCount = reader.WORD(); //BYTE[8] For future(set to zero) reader.BYTES(8); //+For each tag var tags = new Tag[tagCount]; for (int i = 0; i < tagCount; i++) { tags[i] = Tag.Read(reader); } return(new TagsChunk(tags)); }
public static SliceKey Read(AsepriteStreamReader reader, int flag) { // DWORD Frame number(this slice is valid from // this frame to the end of the animation) var frameNumber = reader.DWORD(); // LONG Slice X origin coordinate in the sprite var xOrigin = reader.LONG(); // LONG Slice Y origin coordinate in the sprite var yOrigin = reader.LONG(); // DWORD Slice width(can be 0 if this slice hidden in the // animation from the given frame) var width = reader.DWORD(); // DWORD Slice height var height = reader.DWORD(); long centerX = 0; long centerY = 0; long pivotX = 0; long pivotY = 0; uint centerWidth = 0; uint centerHeight = 0; // + If flags have bit 1 if (reader.FLAG(flag, 1)) { // LONG Center X position(relative to slice bounds) centerX = reader.LONG(); // LONG Center Y position centerY = reader.LONG(); // DWORD Center width centerWidth = reader.DWORD(); // DWORD Center height centerHeight = reader.DWORD(); } // + If flags have bit 2 if (reader.FLAG(flag, 2)) { // LONG Pivot X position(relative to the slice origin) pivotX = reader.LONG(); // LONG Pivot Y position(relative to the slice origin) pivotY = reader.LONG(); } return(new SliceKey(frameNumber, xOrigin, yOrigin, width, height, centerX, centerY, centerWidth, centerHeight, pivotX, pivotY)); }
public static CellExtraChunk Read(AsepriteStreamReader reader) { // DWORD Flags(set to zero) // 1 = Precise bounds are set var preciesBoundsAreSet = reader.DWORD() == 1; // FIXED Precise X position var preciseXPosition = reader.FIXED(); // FIXED Precise Y position var preciseYPosition = reader.FIXED(); // FIXED Width of the cel in the sprite(scaled in real-time) var widthOfTheCellInTheSprite = reader.FIXED(); // FIXED Height of the cel in the sprite var heightOfTheCellInTheSprite = reader.FIXED(); // BYTE[16] For future use(set to zero) reader.BYTES(16); return(new CellExtraChunk(preciesBoundsAreSet, preciseXPosition, preciseYPosition, widthOfTheCellInTheSprite, heightOfTheCellInTheSprite)); }
public static PaletteChunk Read(AsepriteStreamReader reader) { // DWORD New palette size(total number of entries) var entryCount = reader.DWORD(); // DWORD First color index to change var from = reader.DWORD(); // DWORD Last color index to change var to = reader.DWORD(); // BYTE[8] For future(set to zero) reader.BYTES(8); // +For each palette entry in [from, to] range(to - from + 1 entries) var entries = new PaletteEntry[entryCount]; for (int i = 0; i < (to - from) + 1; i++) { entries[i] = PaletteEntry.Read(reader, $"Color {i}"); } return(new PaletteChunk(entries)); }
public static PaletteEntry Read(AsepriteStreamReader reader, string defaultName) { // WORD Entry flags: // 1 = Has name bool hasName = reader.FLAG(reader.WORD(), 1); // BYTE Red(0 - 255) var r = reader.BYTE(); // BYTE Green(0 - 255) var g = reader.BYTE(); // BYTE Blue(0 - 255) var b = reader.BYTE(); // BYTE Alpha(0 - 255) var a = reader.BYTE(); // +If has name bit in entry flags // STRING Color name var name = hasName ? reader.STRING() : defaultName; return(new PaletteEntry(r, g, b, a, name)); }
public static SliceChunk Read(AsepriteStreamReader reader) { // DWORD Number of "slice keys" var keyCount = reader.DWORD(); // DWORD Flags // 1 = It's a 9-patches slice // 2 = Has pivot information var flag = reader.DWORD(); // DWORD Reserved reader.DWORD(); // STRING Name var name = reader.STRING(); // + For each slice key var keys = new SliceKey[keyCount]; for (int i = 0; i < keyCount; i++) { keys[i] = SliceKey.Read(reader, (int)flag); } return(new SliceChunk(name, keys)); }
public static Tag Read(AsepriteStreamReader reader) { //WORD From frame var fromFrame = reader.WORD(); //WORD To frame var toFrame = reader.WORD(); //BYTE Loop animation direction // 0 = Forward // 1 = Reverse // 2 = Ping - pong var loopDirection = (LoopDirections)reader.BYTE(); //BYTE[8] For future(set to zero) reader.BYTES(8); //BYTE[3] RGB values of the tag color var color = reader.BYTES(3); //BYTE Extra byte(zero) reader.BYTE(); //STRING Tag name var name = reader.STRING(); return(new Tag(fromFrame, toFrame, loopDirection, color, name)); }
public static CellChunk Read(AsepriteStreamReader reader, ColorDepth colorDepth) { // WORD Layer index(see NOTE.2) var layerIndex = reader.WORD(); // SHORT X position var xPosition = reader.SHORT(); // SHORT Y position var yPosition = reader.SHORT(); // BYTE Opacity level var opacityLevel = reader.BYTE(); // WORD Cel type var cellType = reader.WORD(); // BYTE[7] For future(set to zero) reader.BYTES(7); // +For cel type = 0(Raw Cel) if (cellType == 0) { // WORD Width in pixels var width = reader.WORD(); // WORD Height in pixels var height = reader.WORD(); // PIXEL[] Raw pixel data: row by row from top to bottom, // for each scanline read pixels from left to right. var depthModifier = 0; if (colorDepth == ColorDepth.RGBA) { depthModifier = 4; } else if (colorDepth == ColorDepth.Grayscale) { depthModifier = 2; } else if (colorDepth == ColorDepth.Indexed) { depthModifier = 1; } var pixels = reader.BYTES(width * height * depthModifier); return(new CellChunk(layerIndex, xPosition, yPosition, opacityLevel, cellType, width, height, pixels)); } // + For cel type = 1(Linked Cel) else if (cellType == 1) { // WORD Frame position to link with var linkedFramePosition = reader.WORD(); return(new CellChunk(layerIndex, xPosition, yPosition, opacityLevel, cellType, linkedFramePosition)); } // + For cel type = 2(Compressed Image) else if (cellType == 2) { // WORD Width in pixels var width = reader.WORD(); // WORD Height in pixels var height = reader.WORD(); // BYTE[] "Raw Cel" data compressed with ZLIB method var depthModifier = 0; if (colorDepth == ColorDepth.RGBA) { depthModifier = 4; } else if (colorDepth == ColorDepth.Grayscale) { depthModifier = 2; } else if (colorDepth == ColorDepth.Indexed) { depthModifier = 1; } var count = width * height * depthModifier; var pixels = new byte[count]; reader.DEFLATE(pixels); return(new CellChunk(layerIndex, xPosition, yPosition, opacityLevel, cellType, width, height, pixels)); } else { return(new CellChunk(layerIndex, xPosition, yPosition, opacityLevel, cellType)); } }
public static FrameData Read(AsepriteStreamReader reader, ColorDepth colorDepth) { // DWORD Bytes in this frame var bytesInFrame = reader.DWORD(); // WORD Magic number(always 0xF1FA) var magicNumber = reader.WORD(); if (magicNumber != 0xF1FA) { throw new System.Exception("Invalid Format"); } // WORD Old field which specifies the number of "chunks" // in this frame.If this value is 0xFFFF, we might // have more chunks to read in this frame // (so we have to use the new field) var oldNumberOfChunks = reader.WORD(); // WORD Frame duration(in milliseconds) var frameDuration = reader.WORD(); // BYTE[2] For future(set to zero) reader.BYTES(2); // DWORD New field which specifies the number of "chunks" // in this frame(if this is 0, use the old field) var newNumberOfChunks = reader.DWORD(); var numberOfChunks = newNumberOfChunks > 0 ? newNumberOfChunks : oldNumberOfChunks; var chunks = new IChunk[numberOfChunks]; for (int i = 0; i < numberOfChunks; i++) { // DWORD Chunk size var startPos = reader.POS; var size = reader.DWORD(); // WORD Chunk type var type = reader.WORD(); // BYTE[] Chunk data Console.WriteLine($"Reading Chunk Type: {type:X}"); switch (type) { case 0x2004: chunks[i] = LayerChunk.Read(reader); break; case 0x2005: chunks[i] = CellChunk.Read(reader, colorDepth); break; case 0x2006: chunks[i] = CellExtraChunk.Read(reader); break; case 0x2018: chunks[i] = TagsChunk.Read(reader); break; case 0x2019: chunks[i] = PaletteChunk.Read(reader); break; case 0x2020: chunks[i] = UserDataChunk.Read(reader); break; case 0x2022: chunks[i] = SliceChunk.Read(reader); break; default: // ingoring data reader.BYTES((int)size); break; } reader.POS = startPos + size; } return(new FrameData(bytesInFrame, frameDuration, chunks)); }
public static Header Read(AsepriteStreamReader reader) { // DWORD File size var fileSize = reader.DWORD(); // WORD Magic number (0xA5E0) var magicNumber = reader.WORD(); if (magicNumber != 0xA5E0) { throw new System.Exception("Invalid Format"); } // WORD Frames var frames = reader.WORD(); // WORD Width in pixels var width = reader.WORD(); // WORD Height in pixels var height = reader.WORD(); // WORD Color depth (bits per pixel) // 32 bpp = RGBA // 16 bpp = Grayscale // 8 bpp = Indexed var colorDepth = (ColorDepth)reader.WORD(); // DWORD Flags: // 1 = Layer opacity has valid value var layerOpacityHasValidValue = reader.FLAG(reader.DWORD(), 1); // WORD Speed (milliseconds between frame, like in FLC files) // DEPRECATED: You should use the frame duration field // from each frame header reader.WORD(); // DWORD Set be 0 reader.DWORD(); // DWORD Set be 0 reader.DWORD(); // BYTE Palette entry (index) which represent transparent color // in all non-background layers (only for Indexed sprites). var transparentIndex = reader.BYTE(); // BYTE[3] Ignore these bytes reader.BYTES(3); // WORD Number of colors (0 means 256 for old sprites) reader.WORD(); // BYTE Pixel width (pixel ratio is "pixel width/pixel height"). // If this or pixel height field is zero, pixel ratio is 1:1 var pixelWidth = reader.BYTE(); // BYTE Pixel height var pixelHeight = reader.BYTE(); byte pixelRatio = 1; if (pixelHeight > 0 && pixelWidth > 0) { pixelRatio = (byte)(pixelWidth / pixelHeight); } // SHORT X position of the grid var xPos = reader.SHORT(); // SHORT Y position of the grid var yPos = reader.SHORT(); // WORD Grid width (zero if there is no grid, grid size // is 16x16 on Aseprite by default) var gridWidth = reader.WORD(); // WORD Grid height (zero if there is no grid) var gridHeight = reader.WORD(); // BYTE[84] For future (set to zero) reader.BYTES(84); return(new Header( fileSize, frames, width, height, colorDepth, layerOpacityHasValidValue, transparentIndex, pixelWidth, pixelHeight, pixelRatio, xPos, yPos, gridWidth, gridHeight)); }