예제 #1
0
        /// <summary>
        /// Reads the tga file header from the stream.
        /// </summary>
        /// <param name="stream">The <see cref="Stream"/> containing image data.</param>
        /// <returns>The image origin.</returns>
        private TgaImageOrigin ReadFileHeader(Stream stream)
        {
            this.currentStream = stream;

            Span <byte> buffer = stackalloc byte[TgaFileHeader.Size];

            this.currentStream.Read(buffer, 0, TgaFileHeader.Size);
            this.fileHeader  = TgaFileHeader.Parse(buffer);
            this.metadata    = new ImageMetadata();
            this.tgaMetadata = this.metadata.GetTgaMetadata();
            this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth;

            var alphaBits = this.fileHeader.ImageDescriptor & 0xf;

            if (alphaBits != 0 && alphaBits != 1 && alphaBits != 8)
            {
                TgaThrowHelper.ThrowImageFormatException("Invalid alpha channel bits");
            }

            this.tgaMetadata.AlphaChannelBits = (byte)alphaBits;
            this.hasAlpha = alphaBits > 0;

            // Bits 4 and 5 describe the image origin.
            var origin = (TgaImageOrigin)((this.fileHeader.ImageDescriptor & 0x30) >> 4);

            return(origin);
        }
예제 #2
0
        /// <summary>
        /// Reads the tga file header from the stream.
        /// </summary>
        /// <param name="stream">The <see cref="Stream"/> containing image data.</param>
        /// <returns>true, if the image origin is top left.</returns>
        private bool ReadFileHeader(Stream stream)
        {
            this.currentStream = stream;

            Span <byte> buffer = stackalloc byte[TgaFileHeader.Size];

            this.currentStream.Read(buffer, 0, TgaFileHeader.Size);
            this.fileHeader  = TgaFileHeader.Parse(buffer);
            this.metadata    = new ImageMetadata();
            this.tgaMetadata = this.metadata.GetTgaMetadata();
            this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth;

            var alphaBits = this.fileHeader.ImageDescriptor & 0xf;

            if (alphaBits != 0 && alphaBits != 1 && alphaBits != 8)
            {
                TgaThrowHelper.ThrowImageFormatException("Invalid alpha channel bits");
            }

            this.tgaMetadata.AlphaChannelBits = (byte)alphaBits;
            this.hasAlpha = alphaBits > 0;

            // TODO: bits 4 and 5 describe the image origin. See spec page 9. bit 4 is currently ignored.
            // Theoretically the origin could also be top right and bottom right.
            // Bit at position 5 of the descriptor indicates, that the origin is top left instead of bottom left.
            if ((this.fileHeader.ImageDescriptor & (1 << 5)) != 0)
            {
                return(true);
            }

            return(false);
        }
예제 #3
0
        /// <summary>
        /// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
        /// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
        public void Encode <TPixel>(Image <TPixel> image, Stream stream)
            where TPixel : struct, IPixel <TPixel>
        {
            Guard.NotNull(image, nameof(image));
            Guard.NotNull(stream, nameof(stream));

            this.configuration = image.GetConfiguration();
            ImageMetadata metadata    = image.Metadata;
            TgaMetadata   tgaMetadata = metadata.GetFormatMetadata(TgaFormat.Instance);

            this.bitsPerPixel = this.bitsPerPixel ?? tgaMetadata.BitsPerPixel;

            TgaImageType imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleTrueColor : TgaImageType.TrueColor;

            if (this.bitsPerPixel == TgaBitsPerPixel.Pixel8)
            {
                imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleBlackAndWhite : TgaImageType.BlackAndWhite;
            }

            // If compression is used, set bit 5 of the image descriptor to indicate an left top origin.
            byte imageDescriptor = (byte)(this.compression is TgaCompression.RunLength ? 32 : 0);

            var fileHeader = new TgaFileHeader(
                idLength: 0,
                colorMapType: 0,
                imageType: imageType,
                cMapStart: 0,
                cMapLength: 0,
                cMapDepth: 0,
                xOffset: 0,
                yOffset: this.compression is TgaCompression.RunLength ? (short)image.Height : (short)0, // When run length encoding is used, the origin should be top left instead of the default bottom left.
                width: (short)image.Width,
                height: (short)image.Height,
                pixelDepth: (byte)this.bitsPerPixel.Value,
                imageDescriptor: imageDescriptor);

#if NETCOREAPP2_1
            Span <byte> buffer = stackalloc byte[TgaFileHeader.Size];
#else
            byte[] buffer = new byte[TgaFileHeader.Size];
#endif
            fileHeader.WriteTo(buffer);

            stream.Write(buffer, 0, TgaFileHeader.Size);

            if (this.compression is TgaCompression.RunLength)
            {
                this.WriteRunLengthEndcodedImage(stream, image.Frames.RootFrame);
            }
            else
            {
                this.WriteImage(stream, image.Frames.RootFrame);
            }

            stream.Flush();
        }
예제 #4
0
        /// <summary>
        /// Reads the tga file header from the stream.
        /// </summary>
        /// <param name="stream">The <see cref="Stream"/> containing image data.</param>
        /// <returns>true, if the image origin is top left.</returns>
        private bool ReadFileHeader(Stream stream)
        {
            this.currentStream = stream;

            Span <byte> buffer = stackalloc byte[TgaFileHeader.Size];

            this.currentStream.Read(buffer, 0, TgaFileHeader.Size);
            this.fileHeader  = TgaFileHeader.Parse(buffer);
            this.metadata    = new ImageMetadata();
            this.tgaMetadata = this.metadata.GetTgaMetadata();
            this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth;

            // Bit at position 5 of the descriptor indicates, that the origin is top left instead of bottom right.
            if ((this.fileHeader.ImageDescriptor & (1 << 5)) != 0)
            {
                return(true);
            }

            return(false);
        }
예제 #5
0
        /// <summary>
        /// Encodes the image to the specified stream from the <see cref="ImageFrame{TPixel}"/>.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode from.</param>
        /// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
        public void Encode <TPixel>(Image <TPixel> image, Stream stream)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            Guard.NotNull(image, nameof(image));
            Guard.NotNull(stream, nameof(stream));

            this.configuration = image.GetConfiguration();
            ImageMetadata metadata    = image.Metadata;
            TgaMetadata   tgaMetadata = metadata.GetTgaMetadata();

            this.bitsPerPixel = this.bitsPerPixel ?? tgaMetadata.BitsPerPixel;

            TgaImageType imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleTrueColor : TgaImageType.TrueColor;

            if (this.bitsPerPixel == TgaBitsPerPixel.Pixel8)
            {
                imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleBlackAndWhite : TgaImageType.BlackAndWhite;
            }

            byte imageDescriptor = 0;

            if (this.compression is TgaCompression.RunLength)
            {
                // If compression is used, set bit 5 of the image descriptor to indicate a left top origin.
                imageDescriptor |= 0x20;
            }

            if (this.bitsPerPixel is TgaBitsPerPixel.Pixel32)
            {
                // Indicate, that 8 bit are used for the alpha channel.
                imageDescriptor |= 0x8;
            }

            if (this.bitsPerPixel is TgaBitsPerPixel.Pixel16)
            {
                // Indicate, that 1 bit is used for the alpha channel.
                imageDescriptor |= 0x1;
            }

            var fileHeader = new TgaFileHeader(
                idLength: 0,
                colorMapType: 0,
                imageType: imageType,
                cMapStart: 0,
                cMapLength: 0,
                cMapDepth: 0,
                xOffset: 0,
                yOffset: this.compression is TgaCompression.RunLength ? (short)image.Height : (short)0, // When run length encoding is used, the origin should be top left instead of the default bottom left.
                width: (short)image.Width,
                height: (short)image.Height,
                pixelDepth: (byte)this.bitsPerPixel.Value,
                imageDescriptor: imageDescriptor);

            Span <byte> buffer = stackalloc byte[TgaFileHeader.Size];

            fileHeader.WriteTo(buffer);

            stream.Write(buffer, 0, TgaFileHeader.Size);

            if (this.compression is TgaCompression.RunLength)
            {
                this.WriteRunLengthEncodedImage(stream, image.Frames.RootFrame);
            }
            else
            {
                this.WriteImage(stream, image.Frames.RootFrame);
            }

            stream.Flush();
        }