private void WriteFileColor(DataSource df, BitAddress offset, IColor foreignColor, Endian endian) { Span <byte> colorBuffer = stackalloc byte[4]; int writeSize = (foreignColor.Size + 7) / 8; if (writeSize == 1) { colorBuffer[0] = (byte)foreignColor.Color; } else if (writeSize == 2 && endian == Endian.Little) { BinaryPrimitives.WriteUInt16LittleEndian(colorBuffer, (ushort)foreignColor.Color); } else if (writeSize == 2 && endian == Endian.Big) { BinaryPrimitives.WriteUInt16BigEndian(colorBuffer, (ushort)foreignColor.Color); } else if (writeSize == 3) { colorBuffer[0] = (byte)foreignColor.Color; colorBuffer[1] = (byte)(foreignColor.Color >> 8); colorBuffer[2] = (byte)(foreignColor.Color >> 16); } else if (writeSize == 4 && endian == Endian.Little) { BinaryPrimitives.WriteUInt32LittleEndian(colorBuffer, foreignColor.Color); } else if (writeSize == 4 && endian == Endian.Big) { BinaryPrimitives.WriteUInt32BigEndian(colorBuffer, foreignColor.Color); } df.Write(offset, colorBuffer[..writeSize]);
public static ScatteredArranger CreateIndexedArrangerFromImage(string imageFile, ColorModel colorModel, bool zeroIndexTransparent, ICodecFactory factory, IGraphicsCodec codec) { var image = new Bitmap(imageFile); var imagePalette = image.Palette; var palette = new Palette("testPalette", new ColorFactory(), colorModel, zeroIndexTransparent, PaletteStorageSource.Project); var colorSources = imagePalette.Entries .Select(x => new ProjectNativeColorSource(new ColorRgba32(x.R, x.G, x.B, x.A))); palette.SetColorSources(colorSources); var file = new MemoryDataSource("test", image.Width * image.Height); var elemsX = image.Width / codec.Width; var elemsY = image.Height / codec.Height; var arranger = new ScatteredArranger("testArranger", PixelColorType.Indexed, ElementLayout.Tiled, elemsX, elemsY, codec.Width, codec.Height); var address = new BitAddress(0); for (int y = 0; y < elemsY; y++) { for (int x = 0; x < elemsX; x++) { var element = new ArrangerElement(x, y, file, address, factory.CloneCodec(codec), palette); address += codec.StorageSize; arranger.SetElement(element, x, y); } } return(arranger); }
public static async ValueTask <byte[]> ReadUnshiftedAsync(this Stream stream, BitAddress address, int readBits) { var readBuffer = new byte[(readBits + address.BitOffset + 7) / 8]; await stream.ReadUnshiftedAsync(address, readBits, readBuffer); return(readBuffer); }
public void ReadShifted_AsExpected(byte[] data, BitAddress offset, int numBits, byte[] expected) { var stream = new MemoryStream(data); var actual = new byte[(numBits + 7) / 8]; stream.ReadShifted(offset, numBits, actual); CollectionAssert.AreEqual(expected, actual); }
public ArrangerElement(int x1, int y1, DataSource dataFile, BitAddress address, IGraphicsCodec codec, Palette palette) { X1 = x1; Y1 = y1; Source = dataFile; SourceAddress = address; Codec = codec; Palette = palette; Mirror = MirrorOperation.None; Rotation = RotationOperation.None; }
public void WriteShifted_AsExpected(byte[] data, BitAddress offset, int numBits, byte[] writeData, byte[] expected) { using var stream = new MemoryStream(data); stream.WriteShifted(offset, numBits, writeData); stream.Seek(0, SeekOrigin.Begin); var actual = new byte[expected.Length]; stream.Read(actual); CollectionAssert.AreEqual(expected, actual); }
/// <summary> /// /// </summary> /// <param name="df">Source to read color from</param> /// <param name="offset">Offset into the source to read from</param> /// <param name="colorModel">Model to create the color with</param> /// <param name="size">Read size in bits</param> /// <param name="endian">Endianness of the color</param> /// <returns>The ColorModel-mapped color</returns> /// <exception cref="NotSupportedException">Size must be 32 bits or less</exception> private IColor ReadFileColor(DataSource df, BitAddress offset, ColorModel colorModel, int size, Endian endian) { Span <byte> colorBuffer = stackalloc byte[4]; int readSize = (size + 7) / 8; df.Read(offset, size, colorBuffer); uint readColor; if (readSize == 1) { readColor = colorBuffer[0]; } else if (readSize == 2 && endian == Endian.Little) { readColor = BinaryPrimitives.ReadUInt16LittleEndian(colorBuffer); } else if (readSize == 2 && endian == Endian.Big) { readColor = BinaryPrimitives.ReadUInt16BigEndian(colorBuffer); } else if (readSize == 3) { readColor = colorBuffer[0]; readColor |= ((uint)colorBuffer[1]) << 8; readColor |= ((uint)colorBuffer[2]) << 16; } else if (readSize == 4 && endian == Endian.Little) { readColor = BinaryPrimitives.ReadUInt32LittleEndian(colorBuffer); } else if (readSize == 4 && endian == Endian.Big) { readColor = BinaryPrimitives.ReadUInt32BigEndian(colorBuffer); } else { throw new NotSupportedException($"{nameof(LoadColors)}: Palette formats with entry sizes larger than 4 bytes are not supported"); } return(_colorFactory.CreateColor(colorModel, readColor)); }
/// <summary> /// Moves the sequential arranger's top-left element to the specified address with the remaining elements following /// If the arranger will overflow the file, then seek only to the furthest offset /// </summary> /// <param name="absoluteAddress">Specified address to move the arranger to</param> /// <returns></returns> public BitAddress Move(BitAddress absoluteAddress) { if (Mode != ArrangerMode.Sequential) { throw new InvalidOperationException($"{nameof(Move)}: Arranger {Name} is not in sequential mode"); } var testaddress = absoluteAddress + ArrangerBitSize; // Tests the bounds of the arranger vs the file size if (FileSize * 8 < ArrangerBitSize) // Arranger needs more bits than the entire file { Address = new BitAddress(0, 0); } else if (testaddress.Offset > FileSize * 8) // Clamp arranger to edge of viewable file { Address = new BitAddress(FileSize * 8 - ArrangerBitSize); } else { Address = absoluteAddress; } var relativeChange = Address - GetInitialSequentialFileAddress(); for (int posY = 0; posY < ArrangerElementSize.Height; posY++) { for (int posX = 0; posX < ArrangerElementSize.Width; posX++) { var el = GetElement(posX, posY); if (el is ArrangerElement element) { element = element.WithAddress(element.SourceAddress + relativeChange); ElementGrid[posY, posX] = element; } } } return(Address); }
public string SaveToString() { var buffer = new string[16]; buffer[0] = ((short)Address).ToString(CultureInfo.InvariantCulture); buffer[1] = ((int)SizeType).ToString(CultureInfo.InvariantCulture); buffer[2] = Mul.ToString(CultureInfo.InvariantCulture); buffer[3] = Div.ToString(CultureInfo.InvariantCulture); buffer[4] = Offset.ToString(CultureInfo.InvariantCulture); buffer[5] = Precision.ToString(CultureInfo.InvariantCulture); buffer[6] = ((int)ItemType).ToString(CultureInfo.InvariantCulture); buffer[7] = ColCount.ToString(CultureInfo.InvariantCulture); buffer[8] = RowCount.ToString(CultureInfo.InvariantCulture); buffer[9] = BitAddress.ToString(CultureInfo.InvariantCulture); buffer[10] = Reserve1.ToString(CultureInfo.InvariantCulture); buffer[11] = Reserve2.ToString(CultureInfo.InvariantCulture); buffer[12] = ReverseX ? "1" : "0"; buffer[13] = ReverseY ? "1" : "0"; buffer[14] = Min.ToString(CultureInfo.InvariantCulture); buffer[15] = Max.ToString(CultureInfo.InvariantCulture); return(String.Join(" ", buffer)); }
public static async ValueTask WriteUnshiftedAsync(this Stream stream, BitAddress address, int writeBits, ReadOnlyMemory <byte> writeBuffer) { stream.Seek(address.ByteOffset, SeekOrigin.Begin); await stream.WriteUnshiftedAsync(address.BitOffset, writeBits, writeBuffer); }
/// <summary> /// Moves a Sequential Arranger's file position and updates each Element /// Will not move outside of the bounds of the underlying file /// </summary> /// <param name="moveType">Type of move requested</param> /// <returns>Updated address of first element</returns> public static BitAddress Move(this SequentialArranger arranger, ArrangerMoveType moveType) { if (arranger.Mode != ArrangerMode.Sequential) { throw new InvalidOperationException($"{nameof(Move)}: Arranger {arranger.Name} is not in sequential mode"); } var initialAddress = arranger.Address; var newAddress = initialAddress; long bitDelta = 0; var patternWidth = arranger.TileLayout?.Width ?? 1; var patternHeight = arranger.TileLayout?.Height ?? 1; switch (moveType) // Calculate the new address based on the movement command. Negative and post-EOF addresses are handled after the switch { case ArrangerMoveType.ByteDown: newAddress += 8; break; case ArrangerMoveType.ByteUp: newAddress -= 8; break; case ArrangerMoveType.RowDown: if (arranger.Layout == ElementLayout.Tiled) { bitDelta = arranger.ArrangerElementSize.Width * arranger.ActiveCodec.StorageSize * patternHeight; } else if (arranger.Layout == ElementLayout.Single) { bitDelta = arranger.ActiveCodec.StorageSize / arranger.ArrangerPixelSize.Height; } newAddress += bitDelta; break; case ArrangerMoveType.RowUp: if (arranger.Layout == ElementLayout.Tiled) { bitDelta = arranger.ArrangerElementSize.Width * arranger.ActiveCodec.StorageSize * patternHeight; } else if (arranger.Layout == ElementLayout.Single) { bitDelta = arranger.ActiveCodec.StorageSize / arranger.ArrangerPixelSize.Height; } newAddress -= bitDelta; break; case ArrangerMoveType.ColRight: if (arranger.Layout == ElementLayout.Tiled) { bitDelta = arranger.ActiveCodec.StorageSize * patternWidth * patternHeight; } else if (arranger.Layout == ElementLayout.Single) { bitDelta = 16 * arranger.ActiveCodec.StorageSize * arranger.ActiveCodec.Height / arranger.ActiveCodec.Width; } newAddress += bitDelta; break; case ArrangerMoveType.ColLeft: if (arranger.Layout == ElementLayout.Tiled) { bitDelta = arranger.ActiveCodec.StorageSize * patternWidth * patternHeight; } else if (arranger.Layout == ElementLayout.Single) { bitDelta = 16 * arranger.ActiveCodec.StorageSize * arranger.ActiveCodec.Height / arranger.ActiveCodec.Width; } newAddress -= bitDelta; break; case ArrangerMoveType.PageDown: if (arranger.Layout == ElementLayout.Tiled) { bitDelta = arranger.ArrangerElementSize.Width * arranger.ActiveCodec.StorageSize * arranger.ArrangerElementSize.Height / 2; } else if (arranger.Layout == ElementLayout.Single) { bitDelta = arranger.ActiveCodec.StorageSize / 2; } newAddress += bitDelta; break; case ArrangerMoveType.PageUp: if (arranger.Layout == ElementLayout.Tiled) { bitDelta = arranger.ArrangerElementSize.Width * arranger.ActiveCodec.StorageSize * arranger.ArrangerElementSize.Height / 2; } else if (arranger.Layout == ElementLayout.Single) { bitDelta = arranger.ActiveCodec.StorageSize / 2; } newAddress -= bitDelta; break; case ArrangerMoveType.Home: newAddress = BitAddress.Zero; break; case ArrangerMoveType.End: newAddress = new BitAddress(arranger.FileSize * 8 - arranger.ArrangerBitSize); break; } var maxAddress = new BitAddress(arranger.FileSize * 8 - arranger.ArrangerBitSize); if (maxAddress.Offset < 0) { maxAddress = BitAddress.Zero; } newAddress = new BitAddress(Math.Clamp(newAddress.Offset, 0, maxAddress.Offset)); if (initialAddress != newAddress) { newAddress = arranger.Move(newAddress); } return(newAddress); }
public virtual async Task WriteAsync(BitAddress address, int writeBits, ReadOnlyMemory <byte> buffer) => await _stream.Value.WriteUnshiftedAsync(address, writeBits, buffer);
public virtual void Write(BitAddress address, int writeBits, ReadOnlySpan <byte> buffer) => _stream.Value.WriteUnshifted(address, writeBits, buffer);
public virtual async ValueTask ReadAsync(BitAddress address, int readBits, Memory <byte> buffer) => await _stream.Value.ReadUnshiftedAsync(address, readBits, buffer);
public virtual async ValueTask <byte[]> ReadAsync(BitAddress address, int readBits) => await _stream.Value.ReadUnshiftedAsync(address, readBits);
public virtual void Read(BitAddress address, int readBits, Span <byte> buffer) => _stream.Value.ReadUnshifted(address, readBits, buffer);
public static async ValueTask ReadUnshiftedAsync(this Stream stream, BitAddress address, int readBits, Memory <byte> buffer) { stream.Seek(address.ByteOffset, SeekOrigin.Begin); await stream.ReadUnshiftedAsync(address, readBits, buffer); }
public override int GetHashCode() { return((int)Domain * 17 ^ BitAddress.GetHashCode() ^ BitSize.GetHashCode()); }
public void SetAddressStr() { WordAddressStr = WordAddress.ToString().PadLeft(4, '0'); BitAddressStr = BitAddress.ToString().PadLeft(2, '0'); }
public FileColorSourceModel(BitAddress fileAddress, int entries, Endian endian) { FileAddress = fileAddress; Entries = entries; Endian = endian; }
public FileColorSource(BitAddress offset, Endian endian) { Offset = offset; Endian = endian; }
public virtual byte[] Read(BitAddress address, int readBits) => _stream.Value.ReadUnshifted(address, readBits);