/// <summary> /// Looks up color values and builds the image from de-compressed RLE8 or RLE4 data. /// Compressed RLE8 stream is uncompressed by <see cref="UncompressRle8(int, Span{byte})"/> /// Compressed RLE4 stream is uncompressed by <see cref="UncompressRle4(int, Span{byte})"/> /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="compression">The compression type. Either RLE4 or RLE8.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param> /// <param name="width">The width of the bitmap.</param> /// <param name="height">The height of the bitmap.</param> /// <param name="inverted">Whether the bitmap is inverted.</param> private void ReadRle <TPixel>(BmpCompression compression, Buffer2D <TPixel> pixels, byte[] colors, int width, int height, bool inverted) where TPixel : struct, IPixel <TPixel> { TPixel color = default; using (Buffer2D <byte> buffer = this.memoryAllocator.Allocate2D <byte>(width, height, AllocationOptions.Clean)) { if (compression == BmpCompression.RLE8) { this.UncompressRle8(width, buffer.GetSpan()); } else { this.UncompressRle4(width, buffer.GetSpan()); } for (int y = 0; y < height; y++) { int newY = Invert(y, height, inverted); Span <byte> bufferRow = buffer.GetRowSpan(y); Span <TPixel> pixelRow = pixels.GetRowSpan(newY); for (int x = 0; x < width; x++) { color.FromBgr24(Unsafe.As <byte, Bgr24>(ref colors[bufferRow[x] * 4])); pixelRow[x] = color; } } } }
/// <summary> /// TODO: This should be a common processing method! The image.Opacity(val) multiplies the alpha channel! /// </summary> /// <typeparam name="TPixel"></typeparam> /// <param name="ctx"></param> public static void MakeOpaque <TPixel>(this IImageProcessingContext <TPixel> ctx) where TPixel : struct, IPixel <TPixel> { MemoryAllocator memoryAllocator = ctx.MemoryAllocator; ctx.Apply(img => { using (Buffer2D <Vector4> temp = memoryAllocator.Allocate2D <Vector4>(img.Width, img.Height)) { Span <Vector4> tempSpan = temp.GetSpan(); foreach (ImageFrame <TPixel> frame in img.Frames) { Span <TPixel> pixelSpan = frame.GetPixelSpan(); PixelOperations <TPixel> .Instance.ToScaledVector4(pixelSpan, tempSpan, pixelSpan.Length); for (int i = 0; i < tempSpan.Length; i++) { ref Vector4 v = ref tempSpan[i]; v.W = 1F; } PixelOperations <TPixel> .Instance.PackFromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); } } });
/// <summary> /// Looks up color values and builds the image from de-compressed RLE8 data. /// Compresssed RLE8 stream is uncompressed by <see cref="UncompressRle8(int, Span{byte})"/> /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="colors">The <see cref="T:byte[]"/> containing the colors.</param> /// <param name="width">The width of the bitmap.</param> /// <param name="height">The height of the bitmap.</param> /// <param name="inverted">Whether the bitmap is inverted.</param> private void ReadRle8 <TPixel>(Buffer2D <TPixel> pixels, byte[] colors, int width, int height, bool inverted) where TPixel : struct, IPixel <TPixel> { var color = default(TPixel); var rgba = new Rgba32(0, 0, 0, 255); using (Buffer2D <byte> buffer = this.memoryAllocator.AllocateClean2D <byte>(width, height)) { this.UncompressRle8(width, buffer.GetSpan()); for (int y = 0; y < height; y++) { int newY = Invert(y, height, inverted); Span <byte> bufferRow = buffer.GetRowSpan(y); Span <TPixel> pixelRow = pixels.GetRowSpan(newY); for (int x = 0; x < width; x++) { rgba.Bgr = Unsafe.As <byte, Bgr24>(ref colors[bufferRow[x] * 4]); color.PackFromRgba32(rgba); pixelRow[x] = color; } } } }
/// <summary> /// Copies the pixels to a <see cref="Buffer2D{TPixel}"/> of the same size. /// </summary> /// <param name="target">The target pixel buffer accessor.</param> internal void CopyTo(Buffer2D <TPixel> target) { if (this.Size() != target.Size()) { throw new ArgumentException("ImageFrame<TPixel>.CopyTo(): target must be of the same size!", nameof(target)); } this.GetPixelSpan().CopyTo(target.GetSpan()); }
public void IterateRectangularBuffer( int maxDegreeOfParallelism, int bufferWidth, int bufferHeight, int rectX, int rectY, int rectWidth, int rectHeight) { MemoryAllocator memoryAllocator = Configuration.Default.MemoryAllocator; using (Buffer2D <Point> expected = memoryAllocator.Allocate2D <Point>(bufferWidth, bufferHeight, AllocationOptions.Clean)) using (Buffer2D <Point> actual = memoryAllocator.Allocate2D <Point>(bufferWidth, bufferHeight, AllocationOptions.Clean)) { var rect = new Rectangle(rectX, rectY, rectWidth, rectHeight); void FillRow(int y, Buffer2D <Point> buffer) { for (int x = rect.Left; x < rect.Right; x++) { buffer[x, y] = new Point(x, y); } } // Fill Expected data: for (int y = rectY; y < rect.Bottom; y++) { FillRow(y, expected); } // Fill actual data using IterateRows: var settings = new ParallelExecutionSettings(maxDegreeOfParallelism, memoryAllocator); void RowAction(RowInterval rows) { this.output.WriteLine(rows.ToString()); for (int y = rows.Min; y < rows.Max; y++) { FillRow(y, actual); } } var operation = new TestRowIntervalOperation(RowAction); ParallelRowIterator.IterateRows( rect, settings, in operation); // Assert: TestImageExtensions.CompareBuffers(expected.GetSpan(), actual.GetSpan()); } }
public void GetMultiRowSpan(int width, int height, int min, int max) { using (Buffer2D <int> buffer = Configuration.Default.MemoryAllocator.Allocate2D <int>(width, height)) { var rows = new RowInterval(min, max); Span <int> span = buffer.GetMultiRowSpan(rows); ref int expected0 = ref buffer.GetSpan()[min * width]; int expectedLength = (max - min) * width; ref int actual0 = ref span[0];
/// <summary> /// Writes a run length encoded tga image to the stream. /// </summary> /// <typeparam name="TPixel">The pixel type.</typeparam> /// <param name="stream">The stream to write the image to.</param> /// <param name="image">The image to encode.</param> private void WriteRunLengthEndcodedImage <TPixel>(Stream stream, ImageFrame <TPixel> image) where TPixel : struct, IPixel <TPixel> { Rgba32 color = default; Buffer2D <TPixel> pixels = image.PixelBuffer; Span <TPixel> pixelSpan = pixels.GetSpan(); int totalPixels = image.Width * image.Height; int encodedPixels = 0; while (encodedPixels < totalPixels) { TPixel currentPixel = pixelSpan[encodedPixels]; currentPixel.ToRgba32(ref color); byte equalPixelCount = this.FindEqualPixels(pixelSpan.Slice(encodedPixels)); // Write the number of equal pixels, with the high bit set, indicating ist a compressed pixel run. stream.WriteByte((byte)(equalPixelCount | 128)); switch (this.bitsPerPixel) { case TgaBitsPerPixel.Pixel8: int luminance = GetLuminance(currentPixel); stream.WriteByte((byte)luminance); break; case TgaBitsPerPixel.Pixel16: var bgra5551 = new Bgra5551(color.ToVector4()); BinaryPrimitives.TryWriteInt16LittleEndian(this.buffer, (short)bgra5551.PackedValue); stream.WriteByte(this.buffer[0]); stream.WriteByte(this.buffer[1]); break; case TgaBitsPerPixel.Pixel24: stream.WriteByte(color.B); stream.WriteByte(color.G); stream.WriteByte(color.R); break; case TgaBitsPerPixel.Pixel32: stream.WriteByte(color.B); stream.WriteByte(color.G); stream.WriteByte(color.R); stream.WriteByte(color.A); break; } encodedPixels += equalPixelCount + 1; } }
internal static Image <Rgba32> ToGrayscaleImage(this Buffer2D <float> buffer, float scale) { var image = new Image <Rgba32>(buffer.Width, buffer.Height); Span <Rgba32> pixels = image.Frames.RootFrame.GetPixelSpan(); Span <float> bufferSpan = buffer.GetSpan(); for (int i = 0; i < bufferSpan.Length; i++) { float value = bufferSpan[i] * scale; var v = new Vector4(value, value, value, 1f); pixels[i].FromVector4(v); } return(image); }
/// <summary> /// Gets the span to the backing buffer at the given row. /// </summary> /// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <param name="source">The source.</param> /// <param name="row">The row.</param> /// <returns> /// The span returned from Pixel source. /// </returns> private static Span <TPixel> GetSpan <TPixel>(Buffer2D <TPixel> source, int row) where TPixel : struct, IPixel <TPixel> => source.GetSpan().Slice(row * source.Width, source.Width);