Exemple #1
0
        /// <summary>
        /// Writes an 8 Bit color image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
        /// </summary>
        /// <typeparam name="TPixel">The type of the pixel.</typeparam>
        /// <param name="stream">The <see cref="Stream"/> to write to.</param>
        /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param>
        /// <param name="colorPalette">A byte span of size 1024 for the color palette.</param>
        private void Write8BitColor <TPixel>(Stream stream, ImageFrame <TPixel> image, Span <byte> colorPalette)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            using IQuantizer <TPixel> frameQuantizer   = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration);
            using IndexedImageFrame <TPixel> quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());

            ReadOnlySpan <TPixel> quantizedColors = quantized.Palette.Span;

            PixelOperations <TPixel> .Instance.ToBgra32(this.configuration, quantizedColors, MemoryMarshal.Cast <byte, Bgra32>(colorPalette));

            Span <uint> colorPaletteAsUInt = MemoryMarshal.Cast <byte, uint>(colorPalette);

            for (int i = 0; i < colorPaletteAsUInt.Length; i++)
            {
                colorPaletteAsUInt[i] = colorPaletteAsUInt[i] & 0x00FFFFFF; // Padding byte, always 0.
            }

            stream.Write(colorPalette);

            for (int y = image.Height - 1; y >= 0; y--)
            {
                ReadOnlySpan <byte> pixelSpan = quantized.GetPixelRowSpan(y);
                stream.Write(pixelSpan);

                for (int i = 0; i < this.padding; i++)
                {
                    stream.WriteByte(0);
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Returns a span of bytes in the correct format for the PictEncoder
        /// </summary>
        /// <typeparam name="TPixel"></typeparam>
        /// <param name="image"></param>
        /// <param name="quantized"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private ReadOnlySpan <byte> GetScanLine <TPixel>(Image <TPixel> image, IndexedImageFrame <TPixel> quantized, int y) where TPixel : unmanaged, IPixel <TPixel>
        {
            if (quantized == null && options.IsIndexed)
            {
                throw new Exception("Quantized image expected for indexed images");
            }

            if (quantized != null)
            {
                return(quantized.GetPixelRowSpan(y));
            }

            var pixels     = image.GetPixelRowSpan(y);
            var pixelBytes = (int)options.PictBpp / 8;

            using IMemoryOwner <byte> row = memoryAllocator.Allocate <byte>(pixelBytes * image.Width);
            Span <byte> rowSpan           = row.Memory.Span;

            switch (options.PictBpp)
            {
            case PictBpp.Bit16:
                PixelOperations <TPixel> .Instance.ToBgra5551Bytes(configuration, pixels, rowSpan, pixels.Length);

                break;

            case PictBpp.Bit32:
            default:
                PixelOperations <TPixel> .Instance.ToBgra32Bytes(configuration, pixels, rowSpan, pixels.Length);

                break;
            }
            return(rowSpan);
        }
Exemple #3
0
        /// <summary>
        /// Writes a 1 bit image with a color palette. The color palette has 2 entry's with 4 bytes for each entry.
        /// </summary>
        /// <typeparam name="TPixel">The type of the pixel.</typeparam>
        /// <param name="stream">The <see cref="Stream"/> to write to.</param>
        /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param>
        private void Write1BitColor <TPixel>(Stream stream, ImageFrame <TPixel> image)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            using IQuantizer <TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration, new QuantizerOptions()
            {
                MaxColors = 2
            });
            using IndexedImageFrame <TPixel> quantized   = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());
            using IMemoryOwner <byte> colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize1Bit, AllocationOptions.Clean);

            Span <byte>           colorPalette          = colorPaletteBuffer.GetSpan();
            ReadOnlySpan <TPixel> quantizedColorPalette = quantized.Palette.Span;

            this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);

            ReadOnlySpan <byte> quantizedPixelRow = quantized.GetPixelRowSpan(0);
            int rowPadding = quantizedPixelRow.Length % 8 != 0 ? this.padding - 1 : this.padding;

            for (int y = image.Height - 1; y >= 0; y--)
            {
                quantizedPixelRow = quantized.GetPixelRowSpan(y);

                int endIdx = quantizedPixelRow.Length % 8 == 0 ? quantizedPixelRow.Length : quantizedPixelRow.Length - 8;
                for (int i = 0; i < endIdx; i += 8)
                {
                    Write1BitPalette(stream, i, i + 8, quantizedPixelRow);
                }

                if (quantizedPixelRow.Length % 8 != 0)
                {
                    int startIdx = quantizedPixelRow.Length - 7;
                    endIdx = quantizedPixelRow.Length;
                    Write1BitPalette(stream, startIdx, endIdx, quantizedPixelRow);
                }

                for (int i = 0; i < rowPadding; i++)
                {
                    stream.WriteByte(0);
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Writes an 4 bit color image with a color palette. The color palette has 16 entry's with 4 bytes for each entry.
        /// </summary>
        /// <typeparam name="TPixel">The type of the pixel.</typeparam>
        /// <param name="stream">The <see cref="Stream"/> to write to.</param>
        /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param>
        private void Write4BitColor <TPixel>(Stream stream, ImageFrame <TPixel> image)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            using IQuantizer <TPixel> frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration, new QuantizerOptions()
            {
                MaxColors = 16
            });
            using IndexedImageFrame <TPixel> quantized   = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());
            using IMemoryOwner <byte> colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize4Bit, AllocationOptions.Clean);

            Span <byte>           colorPalette          = colorPaletteBuffer.GetSpan();
            ReadOnlySpan <TPixel> quantizedColorPalette = quantized.Palette.Span;

            this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);

            ReadOnlySpan <byte> pixelRowSpan = quantized.GetPixelRowSpan(0);
            int rowPadding = pixelRowSpan.Length % 2 != 0 ? this.padding - 1 : this.padding;

            for (int y = image.Height - 1; y >= 0; y--)
            {
                pixelRowSpan = quantized.GetPixelRowSpan(y);

                int endIdx = pixelRowSpan.Length % 2 == 0 ? pixelRowSpan.Length : pixelRowSpan.Length - 1;
                for (int i = 0; i < endIdx; i += 2)
                {
                    stream.WriteByte((byte)((pixelRowSpan[i] << 4) | pixelRowSpan[i + 1]));
                }

                if (pixelRowSpan.Length % 2 != 0)
                {
                    stream.WriteByte((byte)((pixelRowSpan[pixelRowSpan.Length - 1] << 4) | 0));
                }

                for (int i = 0; i < rowPadding; i++)
                {
                    stream.WriteByte(0);
                }
            }
        }
Exemple #5
0
        public void SinglePixelOpaque()
        {
            Configuration config    = Configuration.Default;
            var           quantizer = new WuQuantizer(new QuantizerOptions {
                Dither = null
            });

            using var image = new Image <Rgba32>(config, 1, 1, Color.Black);
            ImageFrame <Rgba32> frame = image.Frames.RootFrame;

            using IFrameQuantizer <Rgba32> frameQuantizer = quantizer.CreateFrameQuantizer <Rgba32>(config);
            using IndexedImageFrame <Rgba32> result       = frameQuantizer.QuantizeFrame(frame, frame.Bounds());

            Assert.Equal(1, result.Palette.Length);
            Assert.Equal(1, result.Width);
            Assert.Equal(1, result.Height);

            Assert.Equal(Color.Black, (Color)result.Palette.Span[0]);
            Assert.Equal(0, result.GetPixelRowSpan(0)[0]);
        }
Exemple #6
0
        /// <summary>
        /// Writes an 8 bit color image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
        /// </summary>
        /// <typeparam name="TPixel">The type of the pixel.</typeparam>
        /// <param name="stream">The <see cref="Stream"/> to write to.</param>
        /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param>
        /// <param name="colorPalette">A byte span of size 1024 for the color palette.</param>
        private void Write8BitColor <TPixel>(Stream stream, ImageFrame <TPixel> image, Span <byte> colorPalette)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            using IQuantizer <TPixel> frameQuantizer   = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration);
            using IndexedImageFrame <TPixel> quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());

            ReadOnlySpan <TPixel> quantizedColorPalette = quantized.Palette.Span;

            this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);

            for (int y = image.Height - 1; y >= 0; y--)
            {
                ReadOnlySpan <byte> pixelSpan = quantized.GetPixelRowSpan(y);
                stream.Write(pixelSpan);

                for (int i = 0; i < this.padding; i++)
                {
                    stream.WriteByte(0);
                }
            }
        }
        /// <summary>
        /// Writes an 8 Bit color image with a color palette. The color palette has 256 entry's with 4 bytes for each entry.
        /// </summary>
        /// <typeparam name="TPixel">The type of the pixel.</typeparam>
        /// <param name="stream">The <see cref="Stream"/> to write to.</param>
        /// <param name="image"> The <see cref="ImageFrame{TPixel}"/> containing pixel data.</param>
        /// <param name="colorPalette">A byte span of size 1024 for the color palette.</param>
        private void Write8BitColor <TPixel>(Stream stream, ImageFrame <TPixel> image, Span <byte> colorPalette)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            using IQuantizer <TPixel> frameQuantizer   = this.quantizer.CreatePixelSpecificQuantizer <TPixel>(this.configuration);
            using IndexedImageFrame <TPixel> quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds());

            ReadOnlySpan <TPixel> quantizedColors = quantized.Palette.Span;
            var color = default(Rgba32);

            // TODO: Use bulk conversion here for better perf
            int idx = 0;

            foreach (TPixel quantizedColor in quantizedColors)
            {
                quantizedColor.ToRgba32(ref color);
                colorPalette[idx]     = color.B;
                colorPalette[idx + 1] = color.G;
                colorPalette[idx + 2] = color.R;

                // Padding byte, always 0.
                colorPalette[idx + 3] = 0;
                idx += 4;
            }

            stream.Write(colorPalette);

            for (int y = image.Height - 1; y >= 0; y--)
            {
                ReadOnlySpan <byte> pixelSpan = quantized.GetPixelRowSpan(y);
                stream.Write(pixelSpan);

                for (int i = 0; i < this.padding; i++)
                {
                    stream.WriteByte(0);
                }
            }
        }