Beispiel #1
0
        /// <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;
                    }
                }
            }
        }
Beispiel #2
0
        /// <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);
                    }
                }
            });
Beispiel #3
0
        /// <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;
                    }
                }
            }
        }
Beispiel #4
0
        /// <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());
                }
        }
Beispiel #6
0
        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);