/// <summary> /// Converts a given bitmap, modified by given settings, in binary data. /// </summary> /// <param name="bmp">The bitmap, which will be converted.</param> /// <param name="palette">The list containing all colors of the palette to use.</param> /// <param name="settings">The settings determining the final binary data output.</param> /// <returns><see cref="Tuple"/> containing 2 byte arrays.</returns> public static (byte[] indexData, byte[] paletteData) Save(Bitmap bmp, IndexedImageSettings settings) { // Create swizzle point list var points = GetPointSequence(settings.Swizzle, settings.Width, settings.Height, settings.PadWidth, settings.PadHeight); // Get swizzled collection of colors var colors = new List <Color>(); var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); unsafe { var imagePtr = (int *)data.Scan0; if (imagePtr == null) { throw new ArgumentNullException(nameof(imagePtr)); } foreach (var point in points) { var x = Clamp(point.X, 0, bmp.Width); var y = Clamp(point.Y, 0, bmp.Height); colors.Add(Color.FromArgb(imagePtr[y * bmp.Width + x])); } } bmp.UnlockBits(data); // Decompose/Quantize colors var(indices, palette) = settings.QuantizationSettings != null? settings.IndexEncoding.Quantize(colors, settings.QuantizationSettings) : settings.IndexEncoding.Decompose(colors); return(settings.IndexEncoding.Save(indices), settings.Encoding.Save(palette)); }
protected override (Bitmap Image, IList <Color> Palette) Transcode(BitmapInfo bitmapInfo, EncodingInfo imageEncoding, EncodingInfo paletteEncoding, IProgress <ProgressReport> progress) { var img = bitmapInfo.Image; var indexEncoding = BTX.IndexEncodings[imageEncoding.EncodingIndex]; var palEncoding = BTX.PaletteEncodings[paletteEncoding.EncodingIndex]; var settings = new IndexedImageSettings(indexEncoding, palEncoding, img.Width, img.Height) { QuantizationSettings = new QuantizationSettings(new WuColorQuantizer(6, 3), img.Width, img.Height) { ParallelCount = 8 } }; var data = Kanvas.Kolors.Save(img, settings); (_format.Texture, _format.Palette) = Kanvas.Kolors.Load(data.indexData, data.paletteData, settings); return(_format.Texture, _format.Palette); }
/// <summary> /// /// </summary> /// <param name="input"></param> public BTX(Stream input) { using (var br = new BinaryReaderX(input, true)) { // Header Header = br.ReadType <FileHeader>(); br.SeekAlignment(); FileName = br.ReadCStringASCII(); // Setup var dataLength = Header.Width * Header.Height; var paletteDataLength = Header.ColorCount * 4; // Image br.BaseStream.Position = Header.ImageOffset; var texture = br.ReadBytes(dataLength); // Palette if (Header.Format == ImageFormat.Palette_8) { br.BaseStream.Position = Header.PaletteOffset; var palette = br.ReadBytes(paletteDataLength); var settings = new IndexedImageSettings(IndexEncodings[(int)Header.Format], PaletteEncodings[(int)Header.Format], Header.Width, Header.Height); var data = Kolors.Load(texture, palette, settings); Texture = data.image; Palette = data.palette; FormatName = IndexEncodings[(int)Header.Format].FormatName; PaletteFormatName = PaletteEncodings[(int)Header.Format].FormatName; HasPalette = true; } else { var settings = new ImageSettings(Encodings[(int)Header.Format], Header.Width, Header.Height); Texture = Kolors.Load(texture, settings); FormatName = Encodings[(int)Header.Format].FormatName; } } }
/// <summary> /// /// </summary> /// <param name="output"></param> public void Save(Stream output) { using (var bw = new BinaryWriterX(output, true)) { // Updates Header.Width = (short)Texture.Width; Header.Height = (short)Texture.Height; // Header bw.WriteType(Header); bw.WriteAlignment(); bw.WriteString(FileName, Encoding.ASCII, false); bw.WriteAlignment(); // Setup if (Header.Format == ImageFormat.Palette_8) { var settings = new IndexedImageSettings(IndexEncodings[(int)Header.Format], PaletteEncodings[(int)Header.Format], Header.Width, Header.Height) { QuantizationSettings = new QuantizationSettings(new WuColorQuantizer(6, 3), Header.Width, Header.Height) { ColorCount = 256, ParallelCount = 8 } }; var data = Kolors.Save(Texture, settings); bw.Write(data.indexData); bw.Write(data.paletteData); } else { var settings = new ImageSettings(Encodings[(int)Header.Format], Header.Width, Header.Height); var data = Kolors.Save(Texture, settings); bw.Write(data); } } }
/// <summary> /// Loads the binary data with given settings as an image. /// </summary> /// <param name="bytes">Byte array containing the binary image data.</param> /// <param name="paletteBytes">Byte array containing the binary palette data.</param> /// <param name="settings">The settings determining the final image output.</param> /// <returns>Loaded bitmap, indices and colors.</returns> public static (Bitmap image, IList <Color> palette) Load(byte[] bytes, byte[] paletteBytes, IndexedImageSettings settings) { int width = settings.Width, height = settings.Height; var points = GetPointSequence(settings.Swizzle, settings.Width, settings.Height, settings.PadWidth, settings.PadHeight); var indices = settings.IndexEncoding.Load(bytes); var palette = settings.Encoding.Load(paletteBytes).ToList(); var bmp = new Bitmap(width, height); var data = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); unsafe { var imagePtr = (int *)data.Scan0; if (imagePtr == null) { throw new ArgumentNullException(nameof(imagePtr)); } var colors = settings.IndexEncoding.Compose(indices, palette); foreach (var(point, color) in points.Zip(colors, Tuple.Create)) { int x = point.X, y = point.Y; if (0 > x || x >= width || 0 > y || y >= height) { continue; } imagePtr[data.Stride * y / 4 + x] = color.ToArgb(); } } bmp.UnlockBits(data); return(bmp, palette); }