public static byte[] Save(Bitmap bmp, ImageSettings settings, List <Color> pal) { settings.Width = bmp.Width; settings.Height = bmp.Height; var points = GetPointSequence(settings); var ms = new MemoryStream(); using (var bw = new BinaryWriterX(ms)) { foreach (var point in points) { var color = bmp.GetPixel(point.X, point.Y); switch (settings.BitPerIndex) { case BitLength.Bit4: bw.WriteNibble(pal.FindIndex(c => c == color)); break; case BitLength.Bit8: bw.Write((byte)pal.FindIndex(c => c == color)); break; default: throw new NotSupportedException(); } } } return(ms.ToArray()); }
public static Bitmap Load(byte[] indeces, ImageSettings settings, IEnumerable <Color> palette) { int width = settings.Width, height = settings.Height; var colors = GetColorsFromIndeces(indeces, palette, settings).ToList(); var points = GetPointSequence(settings); // Now we just need to merge the points with the colors var bmp = new Bitmap(width, height); var data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); unsafe { var ptr = (int *)data.Scan0; foreach (var pair in points.Zip(colors, Tuple.Create)) { int x = pair.Item1.X, y = pair.Item1.Y; if (0 <= x && x < width && 0 <= y && y < height) { ptr[data.Stride * y / 4 + x] = (pair.Item2.Equals(settings.TransparentColor)) ? Color.Transparent.ToArgb() : pair.Item2.ToArgb(); } } } bmp.UnlockBits(data); return(bmp); }
static IEnumerable <Point> GetPointSequence(ImageSettings settings) { int tileSize = settings.TileSize; if ((int)settings.Orientation < 4) { if (tileSize > settings.Width) { tileSize = settings.Width; } } else { if (tileSize > settings.Height) { tileSize = settings.Height; } } int strideWidth = (settings.Width + 7) & ~7; int strideHeight = (settings.Height + 7) & ~7; if (settings.PadToPowerOf2) { strideWidth = 2 << (int)Math.Log(strideWidth - 1, 2); strideHeight = 2 << (int)Math.Log(strideHeight - 1, 2); } int stride = (int)settings.Orientation < 4 ? strideWidth : strideHeight; for (int i = 0; i < strideWidth * strideHeight; i++) { int x_out = (i / (int)Math.Pow(tileSize, 2) % (stride / tileSize)) * tileSize; int y_out = (i / (int)Math.Pow(tileSize, 2) / (stride / tileSize)) * tileSize; int x_in = i % tileSize; int y_in = i / tileSize % tileSize; switch (settings.Orientation) { case Orientation.Default: yield return(new Point(x_out + x_in, y_out + y_in)); break; case Orientation.TransposeTile: yield return(new Point(x_out + y_in, y_out + x_in)); break; case Orientation.Rotate90: yield return(new Point(y_out + y_in, stride - 1 - (x_out + x_in))); break; case Orientation.Transpose: yield return(new Point(y_out + y_in, x_out + x_in)); break; default: throw new NotSupportedException($"Unknown orientation format {settings.Orientation}"); } } }
static IEnumerable <Color> GetColorsFromIndeces(byte[] indeces, IEnumerable <Color> palette, ImageSettings settings) { using (var br = new BinaryReaderX(new MemoryStream(indeces))) { var count = 0; while (br.BaseStream.Position < br.BaseStream.Length) { switch (settings.BitPerIndex) { case BitLength.Bit4: if (count < settings.Width) { yield return(palette.ToList()[br.ReadNibble()]); yield return(palette.ToList()[br.ReadNibble()]); } else { br.ReadByte(); } count += 2; if (count % settings.TileSize == 0) { count = 0; } break; case BitLength.Bit8: if (count < settings.Width) { yield return(palette.ToList()[br.ReadByte()]); } else { br.ReadByte(); } count++; if (count % settings.TileSize == 0) { count = 0; } break; default: throw new NotSupportedException($"Unknown bitLength format {settings.BitPerIndex}"); } } } }