Browse Source

Add decoding of 24 bit targa files

pull/1026/head
Brian Popow 6 years ago
parent
commit
4a5e075207
  1. 7
      src/ImageSharp/Configuration.cs
  2. 12
      src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs
  3. 18
      src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs
  4. 20
      src/ImageSharp/Formats/Tga/TgaConstants.cs
  5. 34
      src/ImageSharp/Formats/Tga/TgaDecoder.cs
  6. 125
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  7. 139
      src/ImageSharp/Formats/Tga/TgaFileHeader.cs
  8. 33
      src/ImageSharp/Formats/Tga/TgaFormat.cs
  9. 27
      src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs
  10. 48
      src/ImageSharp/Formats/Tga/TgaImageType.cs
  11. 21
      src/ImageSharp/Formats/Tga/TgaMetadata.cs

7
src/ImageSharp/Configuration.cs

@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Processing;
using SixLabors.Memory;
@ -150,6 +151,7 @@ namespace SixLabors.ImageSharp
/// <see cref="JpegConfigurationModule"/>
/// <see cref="GifConfigurationModule"/>
/// <see cref="BmpConfigurationModule"/>.
/// <see cref="TgaConfigurationModule"/>.
/// </summary>
/// <returns>The default configuration of <see cref="Configuration"/>.</returns>
internal static Configuration CreateDefaultInstance()
@ -158,7 +160,8 @@ namespace SixLabors.ImageSharp
new PngConfigurationModule(),
new JpegConfigurationModule(),
new GifConfigurationModule(),
new BmpConfigurationModule());
new BmpConfigurationModule(),
new TgaConfigurationModule());
}
}
}
}

12
src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs

@ -0,0 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tga
{
/// <summary>
/// The options for decoding tga images. Currently empty, but this may change in the future.
/// </summary>
internal interface ITgaDecoderOptions
{
}
}

18
src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs

@ -0,0 +1,18 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tga
{
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the tga format.
/// </summary>
public sealed class TgaConfigurationModule : IConfigurationModule
{
/// <inheritdoc/>
public void Configure(Configuration configuration)
{
configuration.ImageFormatsManager.SetDecoder(TgaFormat.Instance, new TgaDecoder());
configuration.ImageFormatsManager.AddImageFormatDetector(new TgaImageFormatDetector());
}
}
}

20
src/ImageSharp/Formats/Tga/TgaConstants.cs

@ -0,0 +1,20 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
namespace SixLabors.ImageSharp.Formats.Tga
{
internal static class TgaConstants
{
/// <summary>
/// The list of mimetypes that equate to a targa file.
/// </summary>
public static readonly IEnumerable<string> MimeTypes = new[] { "image/x-tga", "image/x-targa" };
/// <summary>
/// The list of file extensions that equate to a targa file.
/// </summary>
public static readonly IEnumerable<string> FileExtensions = new[] { "tga", "vda", "icb", "vst" };
}
}

34
src/ImageSharp/Formats/Tga/TgaDecoder.cs

@ -0,0 +1,34 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tga
{
/// <summary>
/// Image decoder for Truevision TGA images.
/// </summary>
public sealed class TgaDecoder : IImageDecoder, ITgaDecoderOptions, IImageInfoDetector
{
/// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(stream, nameof(stream));
return new TgaDecoderCore(configuration, this).Decode<TPixel>(stream);
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, nameof(stream));
return new TgaDecoderCore(configuration, this).Identify(stream);
}
}
}

125
src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

@ -0,0 +1,125 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Tga
{
internal sealed class TgaDecoderCore
{
/// <summary>
/// The metadata.
/// </summary>
private ImageMetadata metadata;
/// <summary>
/// The file header containing general information about the image.
/// </summary>
private TgaFileHeader fileHeader;
/// <summary>
/// The global configuration.
/// </summary>
private readonly Configuration configuration;
/// <summary>
/// Used for allocating memory during processing operations.
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// The stream to decode from.
/// </summary>
private Stream currentStream;
/// <summary>
/// The bitmap decoder options.
/// </summary>
private readonly ITgaDecoderOptions options;
public TgaDecoderCore(Configuration configuration, ITgaDecoderOptions options)
{
this.configuration = configuration;
this.memoryAllocator = configuration.MemoryAllocator;
this.options = options;
}
/// <summary>
/// Decodes the image from the specified stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream, where the image should be decoded from. Cannot be null.</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="stream"/> is null.</para>
/// </exception>
/// <returns>The decoded image.</returns>
public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : struct, IPixel<TPixel>
{
try
{
this.ReadFileHeader(stream);
var image = new Image<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(this.fileHeader.Width, 3, 0))
{
for (int y = 0; y < this.fileHeader.Height; y++)
{
this.currentStream.Read(row);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(
this.configuration,
row.GetSpan(),
pixelSpan,
this.fileHeader.Width);
}
}
return image;
}
catch (Exception e)
{
throw new ImageFormatException("TGA image does not have a valid format.", e);
}
}
/// <summary>
/// Reads the raw image information from the specified stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
public IImageInfo Identify(Stream stream)
{
this.ReadFileHeader(stream);
return new ImageInfo(
new PixelTypeInfo(this.fileHeader.PixelDepth),
this.fileHeader.Width,
this.fileHeader.Height,
this.metadata);
}
/// <summary>
/// Reads the tga file header from the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
private void ReadFileHeader(Stream stream)
{
this.currentStream = stream;
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[TgaFileHeader.Size];
#else
var buffer = new byte[TgaFileHeader.Size];
#endif
this.currentStream.Read(buffer, 0, TgaFileHeader.Size);
this.fileHeader = TgaFileHeader.Parse(buffer);
}
}
}

139
src/ImageSharp/Formats/Tga/TgaFileHeader.cs

@ -0,0 +1,139 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Tga
{
/// <summary>
/// This block of bytes tells the application detailed information about the targa image.
/// <see href="https://www.fileformat.info/format/tga/egff.htm"/>
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct TgaFileHeader
{
/// <summary>
/// Defines the size of the data structure in the targa file.
/// </summary>
public const int Size = 18;
public TgaFileHeader(
byte idLength,
byte colorMapType,
TgaImageType imageType,
short cMapStart,
short cMapLength,
byte cMapDepth,
short xOffset,
short yOffset,
short width,
short height,
byte pixelDepth,
byte imageDescriptor)
{
this.IdLength = idLength;
this.ColorMapType = colorMapType;
this.ImageType = imageType;
this.CMapStart = cMapStart;
this.CMapLength = cMapLength;
this.CMapDepth = cMapDepth;
this.XOffset = xOffset;
this.YOffset = yOffset;
this.Width = width;
this.Height = height;
this.PixelDepth = pixelDepth;
this.ImageDescriptor = imageDescriptor;
}
/// <summary>
/// Gets the id length.
/// This field identifies the number of bytes contained in Field 6, the Image ID Field. The maximum number
/// of characters is 255. A value of zero indicates that no Image ID field is included with the image.
/// </summary>
public byte IdLength { get; }
/// <summary>
/// Gets the color map type.
/// This field indicates the type of color map (if any) included with the image. There are currently 2 defined
/// values for this field:
/// 0 - indicates that no color-map data is included with this image.
/// 1 - indicates that a color-map is included with this image.
/// </summary>
public byte ColorMapType { get; }
/// <summary>
/// Gets the image type.
/// The TGA File Format can be used to store Pseudo-Color, True-Color and Direct-Color images of various
/// pixel depths.
/// </summary>
public TgaImageType ImageType { get; }
/// <summary>
/// Gets the start of the color map.
/// This field and its sub-fields describe the color map (if any) used for the image. If the Color Map Type field
/// is set to zero, indicating that no color map exists, then these 5 bytes should be set to zero.
/// </summary>
public short CMapStart { get; }
/// <summary>
/// Gets the total number of color map entries included.
/// </summary>
public short CMapLength { get; }
/// <summary>
/// Gets the number of bits per entry. Typically 15, 16, 24 or 32-bit values are used.
/// </summary>
public byte CMapDepth { get; }
/// <summary>
/// Gets the XOffset.
/// These bytes specify the absolute horizontal coordinate for the lower left
/// corner of the image as it is positioned on a display device having an
/// origin at the lower left of the screen.
/// </summary>
public short XOffset { get; }
/// <summary>
/// Gets the YOffset.
/// These bytes specify the absolute vertical coordinate for the lower left
/// corner of the image as it is positioned on a display device having an
/// origin at the lower left of the screen.
/// </summary>
public short YOffset { get; }
/// <summary>
/// Gets the width of the image in pixels.
/// </summary>
public short Width { get; }
/// <summary>
/// Gets the height of the image in pixels.
/// </summary>
public short Height { get; }
/// <summary>
/// Gets the number of bits per pixel. This number includes
/// the Attribute or Alpha channel bits. Common values are 8, 16, 24 and
/// 32 but other pixel depths could be used.
/// </summary>
public byte PixelDepth { get; }
/// <summary>
/// Gets the ImageDescriptor.
/// ImageDescriptor contains two pieces of information.
/// Bits 0 through 3 contain the number of attribute bits per pixel.
/// Attribute bits are found only in pixels for the 16- and 32-bit flavors of the TGA format and are called alpha channel,
/// overlay, or interrupt bits. Bits 4 and 5 contain the image origin location (coordinate 0,0) of the image.
/// This position may be any of the four corners of the display screen.
/// When both of these bits are set to zero, the image origin is the lower-left corner of the screen.
/// Bits 6 and 7 of the ImageDescriptor field are unused and should be set to 0.
/// </summary>
public byte ImageDescriptor { get; }
public static TgaFileHeader Parse(Span<byte> data)
{
return MemoryMarshal.Cast<byte, TgaFileHeader>(data)[0];
}
}
}

33
src/ImageSharp/Formats/Tga/TgaFormat.cs

@ -0,0 +1,33 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
namespace SixLabors.ImageSharp.Formats.Tga
{
/// <summary>
/// Registers the image encoders, decoders and mime type detectors for the tga format.
/// </summary>
public sealed class TgaFormat : IImageFormat<TgaMetadata>
{
/// <summary>
/// Gets the current instance.
/// </summary>
public static TgaFormat Instance { get; } = new TgaFormat();
/// <inheritdoc/>
public string Name => "TGA";
/// <inheritdoc/>
public string DefaultMimeType => "image/tga";
/// <inheritdoc/>
public IEnumerable<string> MimeTypes => TgaConstants.MimeTypes;
/// <inheritdoc/>
public IEnumerable<string> FileExtensions => TgaConstants.FileExtensions;
/// <inheritdoc/>
public TgaMetadata CreateDefaultFormatMetadata() => new TgaMetadata();
}
}

27
src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs

@ -0,0 +1,27 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.Tga
{
/// <summary>
/// Detects tga file headers.
/// </summary>
public sealed class TgaImageFormatDetector : IImageFormatDetector
{
/// <inheritdoc/>
public int HeaderSize => 18;
/// <inheritdoc/>
public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{
return this.IsSupportedFileFormat(header) ? TgaFormat.Instance : null;
}
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{
return header.Length >= this.HeaderSize;
}
}
}

48
src/ImageSharp/Formats/Tga/TgaImageType.cs

@ -0,0 +1,48 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tga
{
/// <summary>
/// Defines the tga image type. The TGA File Format can be used to store Pseudo-Color,
/// True-Color and Direct-Color images of various pixel depths.
/// </summary>
public enum TgaImageType : byte
{
/// <summary>
/// No image data included.
/// Not sure what this is used for.
/// </summary>
NoImageData = 0,
/// <summary>
/// Uncompressed, color mapped image.
/// </summary>
ColorMapped = 1,
/// <summary>
/// Uncompressed true color image.
/// </summary>
TrueColor = 2,
/// <summary>
/// Uncompressed Black and white (grayscale) image.
/// </summary>
BlackAndWhite = 3,
/// <summary>
/// Run length encoded, color mapped image.
/// </summary>
RleColorMapped = 9,
/// <summary>
/// Run length encoded, true color image.
/// </summary>
RleTrueColor = 10,
/// <summary>
/// Run length encoded, black and white (grayscale) image.
/// </summary>
RleBlackAndWhite = 11,
}
}

21
src/ImageSharp/Formats/Tga/TgaMetadata.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tga
{
/// <summary>
/// Provides TGA specific metadata information for the image.
/// </summary>
public class TgaMetadata : IDeepCloneable
{
/// <summary>
/// Initializes a new instance of the <see cref="TgaMetadata"/> class.
/// </summary>
public TgaMetadata()
{
}
/// <inheritdoc/>
public IDeepCloneable DeepClone() => throw new System.NotImplementedException();
}
}
Loading…
Cancel
Save