diff --git a/.gitattributes b/.gitattributes
index 537d9cef11..435f0bb91b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -93,6 +93,7 @@
 *.gif               binary
 *.jpg               binary
 *.png               binary
+*.tga               binary
 *.ttf               binary
 *.snk               binary
 
diff --git a/Directory.Build.targets b/Directory.Build.targets
index 1dc081782a..01c1f10397 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -24,7 +24,7 @@
   
     
     
-    
+    
     
     
     
diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs
index 7460c9cac1..c51a54a40b 100644
--- a/src/ImageSharp/Common/Helpers/ImageMaths.cs
+++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs
@@ -1,7 +1,8 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
 // Licensed under the Apache License, Version 2.0.
 
 using System;
+using System.Numerics;
 using System.Runtime.CompilerServices;
 
 using SixLabors.ImageSharp.PixelFormats;
@@ -14,6 +15,20 @@ namespace SixLabors.ImageSharp
     /// 
     internal static class ImageMaths
     {
+        /// 
+        /// Vector for converting pixel to gray value as specified by ITU-R Recommendation BT.709.
+        /// 
+        private static readonly Vector4 Bt709 = new Vector4(.2126f, .7152f, .0722f, 0.0f);
+
+        /// 
+        /// Convert a pixel value to grayscale using ITU-R Recommendation BT.709.
+        /// 
+        /// The vector to get the luminance from.
+        /// The number of luminance levels (256 for 8 bit, 65536 for 16 bit grayscale images)
+        [MethodImpl(InliningOptions.ShortMethod)]
+        public static int GetBT709Luminance(ref Vector4 vector, int luminanceLevels)
+            => (int)MathF.Round(Vector4.Dot(vector, Bt709) * (luminanceLevels - 1));
+
         /// 
         /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709.
         /// 
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index ae20490c77..4dba7a7e8e 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -8,6 +8,7 @@
 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 @@ public Configuration Clone()
         /// 
         /// 
         /// .
+        /// .
         /// 
         /// The default configuration of .
         internal static Configuration CreateDefaultInstance()
@@ -158,7 +160,8 @@ internal static Configuration CreateDefaultInstance()
                 new PngConfigurationModule(),
                 new JpegConfigurationModule(),
                 new GifConfigurationModule(),
-                new BmpConfigurationModule());
+                new BmpConfigurationModule(),
+                new TgaConfigurationModule());
         }
     }
 }
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index b7733e0269..03e082cce0 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -387,9 +387,10 @@ private void ReadRle24(Buffer2D pixels, int width, int height, b
                     if (rowHasUndefinedPixels)
                     {
                         // Slow path with undefined pixels.
+                        int rowStartIdx = y * width * 3;
                         for (int x = 0; x < width; x++)
                         {
-                            int idx = (y * width * 3) + (x * 3);
+                            int idx = rowStartIdx + (x * 3);
                             if (undefinedPixels[x, y])
                             {
                                 switch (this.options.RleSkippedPixelHandling)
@@ -418,9 +419,10 @@ private void ReadRle24(Buffer2D pixels, int width, int height, b
                     else
                     {
                         // Fast path without any undefined pixels.
+                        int rowStartIdx = y * width * 3;
                         for (int x = 0; x < width; x++)
                         {
-                            int idx = (y * width * 3) + (x * 3);
+                            int idx = rowStartIdx + (x * 3);
                             color.FromBgr24(Unsafe.As(ref bufferSpan[idx]));
                             pixelRow[x] = color;
                         }
diff --git a/src/ImageSharp/Formats/README.md b/src/ImageSharp/Formats/README.md
new file mode 100644
index 0000000000..4a2b401b1d
--- /dev/null
+++ b/src/ImageSharp/Formats/README.md
@@ -0,0 +1,6 @@
+# Encoder/Decoder for true vision targa files
+
+Useful links for reference:
+
+- [FileFront](https://www.fileformat.info/format/tga/egff.htm)
+- [Tga Specification](http://www.dca.fee.unicamp.br/~martino/disciplinas/ea978/tgaffs.pdf)
diff --git a/src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs b/src/ImageSharp/Formats/Tga/ITgaDecoderOptions.cs
new file mode 100644
index 0000000000..e99e8b0c8d
--- /dev/null
+++ b/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
+{
+    /// 
+    /// The options for decoding tga images. Currently empty, but this may change in the future.
+    /// 
+    internal interface ITgaDecoderOptions
+    {
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/ITgaEncoderOptions.cs b/src/ImageSharp/Formats/Tga/ITgaEncoderOptions.cs
new file mode 100644
index 0000000000..49983d2369
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/ITgaEncoderOptions.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Configuration options for use during tga encoding.
+    /// 
+    internal interface ITgaEncoderOptions
+    {
+        /// 
+        /// Gets the number of bits per pixel.
+        /// 
+        TgaBitsPerPixel? BitsPerPixel { get; }
+
+        /// 
+        /// Gets a value indicating whether run length compression should be used.
+        /// 
+        TgaCompression Compression { get; }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TGA_Specification.pdf b/src/ImageSharp/Formats/Tga/TGA_Specification.pdf
new file mode 100644
index 0000000000..09c9a4ddda
Binary files /dev/null and b/src/ImageSharp/Formats/Tga/TGA_Specification.pdf differ
diff --git a/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs b/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs
new file mode 100644
index 0000000000..a0666fa84d
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaBitsPerPixel.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Enumerates the available bits per pixel the tga encoder supports.
+    /// 
+    public enum TgaBitsPerPixel : byte
+    {
+        /// 
+        /// 8 bits per pixel. Each pixel consists of 1 byte.
+        /// 
+        Pixel8 = 8,
+
+        /// 
+        /// 16 bits per pixel. Each pixel consists of 2 bytes.
+        /// 
+        Pixel16 = 16,
+
+        /// 
+        /// 24 bits per pixel. Each pixel consists of 3 bytes.
+        /// 
+        Pixel24 = 24,
+
+        /// 
+        /// 32 bits per pixel. Each pixel consists of 4 bytes.
+        /// 
+        Pixel32 = 32
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaCompression.cs b/src/ImageSharp/Formats/Tga/TgaCompression.cs
new file mode 100644
index 0000000000..cc6e005eda
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaCompression.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Indicates if compression is used.
+    /// 
+    public enum TgaCompression
+    {
+        /// 
+        /// No compression is used.
+        /// 
+        None,
+
+        /// 
+        /// Run length encoding is used.
+        /// 
+        RunLength,
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs b/src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs
new file mode 100644
index 0000000000..18fbf4acd0
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaConfigurationModule.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Registers the image encoders, decoders and mime type detectors for the tga format.
+    /// 
+    public sealed class TgaConfigurationModule : IConfigurationModule
+    {
+        /// 
+        public void Configure(Configuration configuration)
+        {
+            configuration.ImageFormatsManager.SetEncoder(TgaFormat.Instance, new TgaEncoder());
+            configuration.ImageFormatsManager.SetDecoder(TgaFormat.Instance, new TgaDecoder());
+            configuration.ImageFormatsManager.AddImageFormatDetector(new TgaImageFormatDetector());
+        }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaConstants.cs b/src/ImageSharp/Formats/Tga/TgaConstants.cs
new file mode 100644
index 0000000000..5aabe92a1d
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaConstants.cs
@@ -0,0 +1,25 @@
+// 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
+    {
+        /// 
+        /// The list of mimetypes that equate to a targa file.
+        /// 
+        public static readonly IEnumerable MimeTypes = new[] { "image/x-tga", "image/x-targa" };
+
+        /// 
+        /// The list of file extensions that equate to a targa file.
+        /// 
+        public static readonly IEnumerable FileExtensions = new[] { "tga", "vda", "icb", "vst" };
+
+        /// 
+        /// The file header length of a tga image in bytes.
+        /// 
+        public const int FileHeaderLength = 18;
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaDecoder.cs b/src/ImageSharp/Formats/Tga/TgaDecoder.cs
new file mode 100644
index 0000000000..b97388773a
--- /dev/null
+++ b/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
+{
+    /// 
+    /// Image decoder for Truevision TGA images.
+    /// 
+    public sealed class TgaDecoder : IImageDecoder, ITgaDecoderOptions, IImageInfoDetector
+    {
+        /// 
+        public Image Decode(Configuration configuration, Stream stream)
+            where TPixel : struct, IPixel
+        {
+            Guard.NotNull(stream, nameof(stream));
+
+            return new TgaDecoderCore(configuration, this).Decode(stream);
+        }
+
+        /// 
+        public Image Decode(Configuration configuration, Stream stream) => this.Decode(configuration, stream);
+
+        /// 
+        public IImageInfo Identify(Configuration configuration, Stream stream)
+        {
+            Guard.NotNull(stream, nameof(stream));
+
+            return new TgaDecoderCore(configuration, this).Identify(stream);
+        }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
new file mode 100644
index 0000000000..d861450e04
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
@@ -0,0 +1,588 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Buffers;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.Metadata;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Memory;
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    internal sealed class TgaDecoderCore
+    {
+        /// 
+        /// The metadata.
+        /// 
+        private ImageMetadata metadata;
+
+        /// 
+        /// The tga specific metadata.
+        /// 
+        private TgaMetadata tgaMetadata;
+
+        /// 
+        /// The file header containing general information about the image.
+        /// 
+        private TgaFileHeader fileHeader;
+
+        /// 
+        /// The global configuration.
+        /// 
+        private readonly Configuration configuration;
+
+        /// 
+        /// Used for allocating memory during processing operations.
+        /// 
+        private readonly MemoryAllocator memoryAllocator;
+
+        /// 
+        /// The stream to decode from.
+        /// 
+        private Stream currentStream;
+
+        /// 
+        /// The bitmap decoder options.
+        /// 
+        private readonly ITgaDecoderOptions options;
+
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// The configuration.
+        /// The options.
+        public TgaDecoderCore(Configuration configuration, ITgaDecoderOptions options)
+        {
+            this.configuration = configuration;
+            this.memoryAllocator = configuration.MemoryAllocator;
+            this.options = options;
+        }
+
+        /// 
+        /// Decodes the image from the specified stream.
+        /// 
+        /// The pixel format.
+        /// The stream, where the image should be decoded from. Cannot be null.
+        /// 
+        ///     is null.
+        /// 
+        /// The decoded image.
+        public Image Decode(Stream stream)
+            where TPixel : struct, IPixel
+        {
+            try
+            {
+                bool inverted = this.ReadFileHeader(stream);
+                this.currentStream.Skip(this.fileHeader.IdLength);
+
+                // Parse the color map, if present.
+                if (this.fileHeader.ColorMapType != 0 && this.fileHeader.ColorMapType != 1)
+                {
+                    TgaThrowHelper.ThrowNotSupportedException($"Unknown tga colormap type {this.fileHeader.ColorMapType} found");
+                }
+
+                if (this.fileHeader.Width == 0 || this.fileHeader.Height == 0)
+                {
+                    throw new UnknownImageFormatException("Width or height cannot be 0");
+                }
+
+                var image = new Image(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
+                Buffer2D pixels = image.GetRootFramePixelBuffer();
+
+                if (this.fileHeader.ColorMapType is 1)
+                {
+                    if (this.fileHeader.CMapLength <= 0)
+                    {
+                        TgaThrowHelper.ThrowImageFormatException("Missing tga color map length");
+                    }
+
+                    if (this.fileHeader.CMapDepth <= 0)
+                    {
+                        TgaThrowHelper.ThrowImageFormatException("Missing tga color map depth");
+                    }
+
+                    int colorMapPixelSizeInBytes = this.fileHeader.CMapDepth / 8;
+                    int colorMapSizeInBytes = this.fileHeader.CMapLength * colorMapPixelSizeInBytes;
+                    using (IManagedByteBuffer palette = this.memoryAllocator.AllocateManagedByteBuffer(colorMapSizeInBytes, AllocationOptions.Clean))
+                    {
+                        this.currentStream.Read(palette.Array, this.fileHeader.CMapStart, colorMapSizeInBytes);
+
+                        if (this.fileHeader.ImageType is TgaImageType.RleColorMapped)
+                        {
+                            this.ReadPalettedRle(
+                                this.fileHeader.Width,
+                                this.fileHeader.Height,
+                                pixels,
+                                palette.Array,
+                                colorMapPixelSizeInBytes,
+                                inverted);
+                        }
+                        else
+                        {
+                            this.ReadPaletted(
+                                this.fileHeader.Width,
+                                this.fileHeader.Height,
+                                pixels,
+                                palette.Array,
+                                colorMapPixelSizeInBytes,
+                                inverted);
+                        }
+                    }
+
+                    return image;
+                }
+
+                // Even if the image type indicates it is not a paletted image, it can still contain a palette. Skip those bytes.
+                if (this.fileHeader.CMapLength > 0)
+                {
+                    int colorMapPixelSizeInBytes = this.fileHeader.CMapDepth / 8;
+                    this.currentStream.Skip(this.fileHeader.CMapLength * colorMapPixelSizeInBytes);
+                }
+
+                switch (this.fileHeader.PixelDepth)
+                {
+                    case 8:
+                        if (this.fileHeader.ImageType.IsRunLengthEncoded())
+                        {
+                            this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 1, inverted);
+                        }
+                        else
+                        {
+                            this.ReadMonoChrome(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted);
+                        }
+
+                        break;
+
+                    case 15:
+                    case 16:
+                        if (this.fileHeader.ImageType.IsRunLengthEncoded())
+                        {
+                            this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 2, inverted);
+                        }
+                        else
+                        {
+                            this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted);
+                        }
+
+                        break;
+
+                    case 24:
+                        if (this.fileHeader.ImageType.IsRunLengthEncoded())
+                        {
+                            this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3, inverted);
+                        }
+                        else
+                        {
+                            this.ReadBgr24(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted);
+                        }
+
+                        break;
+
+                    case 32:
+                        if (this.fileHeader.ImageType.IsRunLengthEncoded())
+                        {
+                            this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4, inverted);
+                        }
+                        else
+                        {
+                            this.ReadBgra32(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted);
+                        }
+
+                        break;
+
+                    default:
+                        TgaThrowHelper.ThrowNotSupportedException("Does not support this kind of tga files.");
+                        break;
+                }
+
+                return image;
+            }
+            catch (IndexOutOfRangeException e)
+            {
+                throw new ImageFormatException("TGA image does not have a valid format.", e);
+            }
+        }
+
+        /// 
+        /// Reads a uncompressed TGA image with a palette.
+        /// 
+        /// The pixel type.
+        /// The width of the image.
+        /// The height of the image.
+        /// The  to assign the palette to.
+        /// The color palette.
+        /// Color map size of one entry in bytes.
+        /// Indicates, if the origin of the image is top left rather the bottom left (the default).
+        private void ReadPaletted(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, bool inverted)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(width, AllocationOptions.Clean))
+            {
+                TPixel color = default;
+                Span rowSpan = row.GetSpan();
+
+                for (int y = 0; y < height; y++)
+                {
+                    this.currentStream.Read(row);
+                    int newY = Invert(y, height, inverted);
+                    Span pixelRow = pixels.GetRowSpan(newY);
+                    switch (colorMapPixelSizeInBytes)
+                    {
+                        case 2:
+                            for (int x = 0; x < width; x++)
+                            {
+                                int colorIndex = rowSpan[x];
+
+                                // Set alpha value to 1, to treat it as opaque for Bgra5551.
+                                Bgra5551 bgra = Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes]);
+                                bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
+                                color.FromBgra5551(bgra);
+                                pixelRow[x] = color;
+                            }
+
+                            break;
+
+                        case 3:
+                            for (int x = 0; x < width; x++)
+                            {
+                                int colorIndex = rowSpan[x];
+                                color.FromBgr24(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes]));
+                                pixelRow[x] = color;
+                            }
+
+                            break;
+
+                        case 4:
+                            for (int x = 0; x < width; x++)
+                            {
+                                int colorIndex = rowSpan[x];
+                                color.FromBgra32(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes]));
+                                pixelRow[x] = color;
+                            }
+
+                            break;
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Reads a run length encoded TGA image with a palette.
+        /// 
+        /// The pixel type.
+        /// The width of the image.
+        /// The height of the image.
+        /// The  to assign the palette to.
+        /// The color palette.
+        /// Color map size of one entry in bytes.
+        /// Indicates, if the origin of the image is top left rather the bottom left (the default).
+        private void ReadPalettedRle(int width, int height, Buffer2D pixels, byte[] palette, int colorMapPixelSizeInBytes, bool inverted)
+            where TPixel : struct, IPixel
+        {
+            int bytesPerPixel = 1;
+            using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * bytesPerPixel, AllocationOptions.Clean))
+            {
+                TPixel color = default;
+                Span bufferSpan = buffer.GetSpan();
+                this.UncompressRle(width, height, bufferSpan, bytesPerPixel: 1);
+
+                for (int y = 0; y < height; y++)
+                {
+                    int newY = Invert(y, height, inverted);
+                    Span pixelRow = pixels.GetRowSpan(newY);
+                    int rowStartIdx = y * width * bytesPerPixel;
+                    for (int x = 0; x < width; x++)
+                    {
+                        int idx = rowStartIdx + x;
+                        switch (colorMapPixelSizeInBytes)
+                        {
+                            case 1:
+                                color.FromGray8(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
+                                break;
+                            case 2:
+                                // Set alpha value to 1, to treat it as opaque for Bgra5551.
+                                Bgra5551 bgra = Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]);
+                                bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
+                                color.FromBgra5551(bgra);
+                                break;
+                            case 3:
+                                color.FromBgr24(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
+                                break;
+                            case 4:
+                                color.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
+                                break;
+                        }
+
+                        pixelRow[x] = color;
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Reads a uncompressed monochrome TGA image.
+        /// 
+        /// The pixel type.
+        /// The width of the image.
+        /// The height of the image.
+        /// The  to assign the palette to.
+        /// Indicates, if the origin of the image is top left rather the bottom left (the default).
+        private void ReadMonoChrome(int width, int height, Buffer2D pixels, bool inverted)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0))
+            {
+                for (int y = 0; y < height; y++)
+                {
+                    this.currentStream.Read(row);
+                    int newY = Invert(y, height, inverted);
+                    Span pixelSpan = pixels.GetRowSpan(newY);
+                    PixelOperations.Instance.FromGray8Bytes(
+                        this.configuration,
+                        row.GetSpan(),
+                        pixelSpan,
+                        width);
+                }
+            }
+        }
+
+        /// 
+        /// Reads a uncompressed TGA image where each pixels has 16 bit.
+        /// 
+        /// The pixel type.
+        /// The width of the image.
+        /// The height of the image.
+        /// The  to assign the palette to.
+        /// Indicates, if the origin of the image is top left rather the bottom left (the default).
+        private void ReadBgra16(int width, int height, Buffer2D pixels, bool inverted)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0))
+            {
+                for (int y = 0; y < height; y++)
+                {
+                    this.currentStream.Read(row);
+                    Span rowSpan = row.GetSpan();
+
+                    // We need to set each alpha component value to fully opaque.
+                    for (int x = 1; x < rowSpan.Length; x += 2)
+                    {
+                        rowSpan[x] = (byte)(rowSpan[x] | (1 << 7));
+                    }
+
+                    int newY = Invert(y, height, inverted);
+                    Span pixelSpan = pixels.GetRowSpan(newY);
+                    PixelOperations.Instance.FromBgra5551Bytes(
+                        this.configuration,
+                        rowSpan,
+                        pixelSpan,
+                        width);
+                }
+            }
+        }
+
+        /// 
+        /// Reads a uncompressed TGA image where each pixels has 24 bit.
+        /// 
+        /// The pixel type.
+        /// The width of the image.
+        /// The height of the image.
+        /// The  to assign the palette to.
+        /// Indicates, if the origin of the image is top left rather the bottom left (the default).
+        private void ReadBgr24(int width, int height, Buffer2D pixels, bool inverted)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0))
+            {
+                for (int y = 0; y < height; y++)
+                {
+                    this.currentStream.Read(row);
+                    int newY = Invert(y, height, inverted);
+                    Span pixelSpan = pixels.GetRowSpan(newY);
+                    PixelOperations.Instance.FromBgr24Bytes(
+                        this.configuration,
+                        row.GetSpan(),
+                        pixelSpan,
+                        width);
+                }
+            }
+        }
+
+        /// 
+        /// Reads a uncompressed TGA image where each pixels has 32 bit.
+        /// 
+        /// The pixel type.
+        /// The width of the image.
+        /// The height of the image.
+        /// The  to assign the palette to.
+        /// Indicates, if the origin of the image is top left rather the bottom left (the default).
+        private void ReadBgra32(int width, int height, Buffer2D pixels, bool inverted)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0))
+            {
+                for (int y = 0; y < height; y++)
+                {
+                    this.currentStream.Read(row);
+                    int newY = Invert(y, height, inverted);
+                    Span pixelSpan = pixels.GetRowSpan(newY);
+                    PixelOperations.Instance.FromBgra32Bytes(
+                        this.configuration,
+                        row.GetSpan(),
+                        pixelSpan,
+                        width);
+                }
+            }
+        }
+
+        /// 
+        /// Reads a run length encoded TGA image.
+        /// 
+        /// The pixel type.
+        /// The width of the image.
+        /// The height of the image.
+        /// The  to assign the palette to.
+        /// The bytes per pixel.
+        /// Indicates, if the origin of the image is top left rather the bottom left (the default).
+        private void ReadRle(int width, int height, Buffer2D pixels, int bytesPerPixel, bool inverted)
+            where TPixel : struct, IPixel
+        {
+            TPixel color = default;
+            using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * bytesPerPixel, AllocationOptions.Clean))
+            {
+                Span bufferSpan = buffer.GetSpan();
+                this.UncompressRle(width, height, bufferSpan, bytesPerPixel);
+                for (int y = 0; y < height; y++)
+                {
+                    int newY = Invert(y, height, inverted);
+                    Span pixelRow = pixels.GetRowSpan(newY);
+                    int rowStartIdx = y * width * bytesPerPixel;
+                    for (int x = 0; x < width; x++)
+                    {
+                        int idx = rowStartIdx + (x * bytesPerPixel);
+                        switch (bytesPerPixel)
+                        {
+                            case 1:
+                                color.FromGray8(Unsafe.As(ref bufferSpan[idx]));
+                                break;
+                            case 2:
+                                // Set alpha value to 1, to treat it as opaque for Bgra5551.
+                                bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128);
+                                color.FromBgra5551(Unsafe.As(ref bufferSpan[idx]));
+                                break;
+                            case 3:
+                                color.FromBgr24(Unsafe.As(ref bufferSpan[idx]));
+                                break;
+                            case 4:
+                                color.FromBgra32(Unsafe.As(ref bufferSpan[idx]));
+                                break;
+                        }
+
+                        pixelRow[x] = color;
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Reads the raw image information from the specified stream.
+        /// 
+        /// The  containing image data.
+        public IImageInfo Identify(Stream stream)
+        {
+            this.ReadFileHeader(stream);
+            return new ImageInfo(
+                new PixelTypeInfo(this.fileHeader.PixelDepth),
+                this.fileHeader.Width,
+                this.fileHeader.Height,
+                this.metadata);
+        }
+
+        /// 
+        /// Produce uncompressed tga data from a run length encoded stream.
+        /// 
+        /// The width of the image.
+        /// The height of the image.
+        /// Buffer for uncompressed data.
+        /// The bytes used per pixel.
+        private void UncompressRle(int width, int height, Span buffer, int bytesPerPixel)
+        {
+            int uncompressedPixels = 0;
+            var pixel = new byte[bytesPerPixel];
+            int totalPixels = width * height;
+            while (uncompressedPixels < totalPixels)
+            {
+                byte runLengthByte = (byte)this.currentStream.ReadByte();
+
+                // The high bit of a run length packet is set to 1.
+                int highBit = runLengthByte >> 7;
+                if (highBit == 1)
+                {
+                    int runLength = runLengthByte & 127;
+                    this.currentStream.Read(pixel, 0, bytesPerPixel);
+                    int bufferIdx = uncompressedPixels * bytesPerPixel;
+                    for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
+                    {
+                        pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx));
+                        bufferIdx += bytesPerPixel;
+                    }
+                }
+                else
+                {
+                    // Non-run-length encoded packet.
+                    int runLength = runLengthByte;
+                    int bufferIdx = uncompressedPixels * bytesPerPixel;
+                    for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
+                    {
+                        this.currentStream.Read(pixel, 0, bytesPerPixel);
+                        pixel.AsSpan().CopyTo(buffer.Slice(bufferIdx));
+                        bufferIdx += bytesPerPixel;
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Returns the y- value based on the given height.
+        /// 
+        /// The y- value representing the current row.
+        /// The height of the bitmap.
+        /// Whether the bitmap is inverted.
+        /// The  representing the inverted value.
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static int Invert(int y, int height, bool inverted) => (!inverted) ? height - y - 1 : y;
+
+        /// 
+        /// Reads the tga file header from the stream.
+        /// 
+        /// The  containing image data.
+        /// true, if the image origin is top left.
+        private bool ReadFileHeader(Stream stream)
+        {
+            this.currentStream = stream;
+
+#if NETCOREAPP2_1
+            Span 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);
+            this.metadata = new ImageMetadata();
+            this.tgaMetadata = this.metadata.GetFormatMetadata(TgaFormat.Instance);
+            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;
+        }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaEncoder.cs b/src/ImageSharp/Formats/Tga/TgaEncoder.cs
new file mode 100644
index 0000000000..2fcbb822f5
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaEncoder.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.Advanced;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Image encoder for writing an image to a stream as a targa truevision image.
+    /// 
+    public sealed class TgaEncoder : IImageEncoder, ITgaEncoderOptions
+    {
+        /// 
+        /// Gets or sets the number of bits per pixel.
+        /// 
+        public TgaBitsPerPixel? BitsPerPixel { get; set; }
+
+        /// 
+        /// Gets or sets a value indicating whether no compression or run length compression should be used.
+        /// 
+        public TgaCompression Compression { get; set; } = TgaCompression.RunLength;
+
+        /// 
+        public void Encode(Image image, Stream stream)
+            where TPixel : struct, IPixel
+        {
+            var encoder = new TgaEncoderCore(this, image.GetMemoryAllocator());
+            encoder.Encode(image, stream);
+        }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
new file mode 100644
index 0000000000..28b87e9857
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
@@ -0,0 +1,348 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Buffers.Binary;
+using System.IO;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.Metadata;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Memory;
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Image encoder for writing an image to a stream as a truevision targa image.
+    /// 
+    internal sealed class TgaEncoderCore
+    {
+        /// 
+        /// Used for allocating memory during processing operations.
+        /// 
+        private readonly MemoryAllocator memoryAllocator;
+
+        /// 
+        /// The global configuration.
+        /// 
+        private Configuration configuration;
+
+        /// 
+        /// Reusable buffer for writing data.
+        /// 
+        private readonly byte[] buffer = new byte[2];
+
+        /// 
+        /// The color depth, in number of bits per pixel.
+        /// 
+        private TgaBitsPerPixel? bitsPerPixel;
+
+        /// 
+        /// Indicates if run length compression should be used.
+        /// 
+        private readonly TgaCompression compression;
+
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// The encoder options.
+        /// The memory manager.
+        public TgaEncoderCore(ITgaEncoderOptions options, MemoryAllocator memoryAllocator)
+        {
+            this.memoryAllocator = memoryAllocator;
+            this.bitsPerPixel = options.BitsPerPixel;
+            this.compression = options.Compression;
+        }
+
+        /// 
+        /// Encodes the image to the specified stream from the .
+        /// 
+        /// The pixel format.
+        /// The  to encode from.
+        /// The  to encode the image data to.
+        public void Encode(Image image, Stream stream)
+            where TPixel : struct, IPixel
+        {
+            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 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();
+        }
+
+        /// 
+        /// Writes the pixel data to the binary stream.
+        /// 
+        /// The pixel format.
+        /// The  to write to.
+        /// 
+        /// The  containing pixel data.
+        /// 
+        private void WriteImage(Stream stream, ImageFrame image)
+            where TPixel : struct, IPixel
+        {
+            Buffer2D pixels = image.PixelBuffer;
+            switch (this.bitsPerPixel)
+            {
+                case TgaBitsPerPixel.Pixel8:
+                    this.Write8Bit(stream, pixels);
+                    break;
+
+                case TgaBitsPerPixel.Pixel16:
+                    this.Write16Bit(stream, pixels);
+                    break;
+
+                case TgaBitsPerPixel.Pixel24:
+                    this.Write24Bit(stream, pixels);
+                    break;
+
+                case TgaBitsPerPixel.Pixel32:
+                    this.Write32Bit(stream, pixels);
+                    break;
+            }
+        }
+
+        /// 
+        /// Writes a run length encoded tga image to the stream.
+        /// 
+        /// The pixel type.
+        /// The stream to write the image to.
+        /// The image to encode.
+        private void WriteRunLengthEndcodedImage(Stream stream, ImageFrame image)
+            where TPixel : struct, IPixel
+        {
+            Rgba32 color = default;
+            Buffer2D pixels = image.PixelBuffer;
+            Span 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;
+            }
+        }
+
+        /// 
+        /// Finds consecutive pixels, which have the same value starting from the pixel span offset 0.
+        /// 
+        /// The pixel type.
+        /// The pixel span to search in.
+        /// The number of equal pixels.
+        private byte FindEqualPixels(Span pixelSpan)
+            where TPixel : struct, IPixel
+        {
+            int idx = 0;
+            byte equalPixelCount = 0;
+            while (equalPixelCount < 127 && idx < pixelSpan.Length - 1)
+            {
+                TPixel currentPixel = pixelSpan[idx];
+                TPixel nextPixel = pixelSpan[idx + 1];
+                if (currentPixel.Equals(nextPixel))
+                {
+                    equalPixelCount++;
+                }
+                else
+                {
+                    return equalPixelCount;
+                }
+
+                idx++;
+            }
+
+            return equalPixelCount;
+        }
+
+        private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel) => this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, 0);
+
+        /// 
+        /// Writes the 8bit pixels uncompressed to the stream.
+        /// 
+        /// The pixel format.
+        /// The  to write to.
+        /// The  containing pixel data.
+        private void Write8Bit(Stream stream, Buffer2D pixels)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 1))
+            {
+                for (int y = pixels.Height - 1; y >= 0; y--)
+                {
+                    Span pixelSpan = pixels.GetRowSpan(y);
+                    PixelOperations.Instance.ToGray8Bytes(
+                        this.configuration,
+                        pixelSpan,
+                        row.GetSpan(),
+                        pixelSpan.Length);
+                    stream.Write(row.Array, 0, row.Length());
+                }
+            }
+        }
+
+        /// 
+        /// Writes the 16bit pixels uncompressed to the stream.
+        /// 
+        /// The pixel format.
+        /// The  to write to.
+        /// The  containing pixel data.
+        private void Write16Bit(Stream stream, Buffer2D pixels)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 2))
+            {
+                for (int y = pixels.Height - 1; y >= 0; y--)
+                {
+                    Span pixelSpan = pixels.GetRowSpan(y);
+                    PixelOperations.Instance.ToBgra5551Bytes(
+                        this.configuration,
+                        pixelSpan,
+                        row.GetSpan(),
+                        pixelSpan.Length);
+                    stream.Write(row.Array, 0, row.Length());
+                }
+            }
+        }
+
+        /// 
+        /// Writes the 24bit pixels uncompressed to the stream.
+        /// 
+        /// The pixel format.
+        /// The  to write to.
+        /// The  containing pixel data.
+        private void Write24Bit(Stream stream, Buffer2D pixels)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 3))
+            {
+                for (int y = pixels.Height - 1; y >= 0; y--)
+                {
+                    Span pixelSpan = pixels.GetRowSpan(y);
+                    PixelOperations.Instance.ToBgr24Bytes(
+                        this.configuration,
+                        pixelSpan,
+                        row.GetSpan(),
+                        pixelSpan.Length);
+                    stream.Write(row.Array, 0, row.Length());
+                }
+            }
+        }
+
+        /// 
+        /// Writes the 32bit pixels uncompressed to the stream.
+        /// 
+        /// The pixel format.
+        /// The  to write to.
+        /// The  containing pixel data.
+        private void Write32Bit(Stream stream, Buffer2D pixels)
+            where TPixel : struct, IPixel
+        {
+            using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 4))
+            {
+                for (int y = pixels.Height - 1; y >= 0; y--)
+                {
+                    Span pixelSpan = pixels.GetRowSpan(y);
+                    PixelOperations.Instance.ToBgra32Bytes(
+                        this.configuration,
+                        pixelSpan,
+                        row.GetSpan(),
+                        pixelSpan.Length);
+                    stream.Write(row.Array, 0, row.Length());
+                }
+            }
+        }
+
+        /// 
+        /// Convert the pixel values to grayscale using ITU-R Recommendation BT.709.
+        /// 
+        /// The pixel to get the luminance from.
+        [MethodImpl(InliningOptions.ShortMethod)]
+        public static int GetLuminance(TPixel sourcePixel)
+            where TPixel : struct, IPixel
+        {
+            var vector = sourcePixel.ToVector4();
+            return ImageMaths.GetBT709Luminance(ref vector, 256);
+        }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaFileHeader.cs b/src/ImageSharp/Formats/Tga/TgaFileHeader.cs
new file mode 100644
index 0000000000..e2bbb6fbd2
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaFileHeader.cs
@@ -0,0 +1,147 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// This block of bytes tells the application detailed information about the targa image.
+    /// 
+    /// 
+    [StructLayout(LayoutKind.Sequential, Pack = 1)]
+    internal readonly struct TgaFileHeader
+    {
+        /// 
+        /// Defines the size of the data structure in the targa file.
+        /// 
+        public const int Size = TgaConstants.FileHeaderLength;
+
+        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;
+        }
+
+        /// 
+        /// 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.
+        /// 
+        public byte IdLength { get; }
+
+        /// 
+        /// 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.
+        /// 
+        public byte ColorMapType { get; }
+
+        /// 
+        /// 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.
+        /// 
+        public TgaImageType ImageType { get; }
+
+        /// 
+        /// 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.
+        /// 
+        public short CMapStart { get; }
+
+        /// 
+        /// Gets the total number of color map entries included.
+        /// 
+        public short CMapLength { get; }
+
+        /// 
+        /// Gets the number of bits per entry. Typically 15, 16, 24 or 32-bit values are used.
+        /// 
+        public byte CMapDepth { get; }
+
+        /// 
+        /// 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.
+        /// 
+        public short XOffset { get; }
+
+        /// 
+        /// 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.
+        /// 
+        public short YOffset { get; }
+
+        /// 
+        /// Gets the width of the image in pixels.
+        /// 
+        public short Width { get; }
+
+        /// 
+        /// Gets the height of the image in pixels.
+        /// 
+        public short Height { get; }
+
+        /// 
+        /// 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.
+        /// 
+        public byte PixelDepth { get; }
+
+        /// 
+        /// 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.
+        /// 
+        public byte ImageDescriptor { get; }
+
+        public static TgaFileHeader Parse(Span data)
+        {
+            return MemoryMarshal.Cast(data)[0];
+        }
+
+        public void WriteTo(Span buffer)
+        {
+            ref TgaFileHeader dest = ref Unsafe.As(ref MemoryMarshal.GetReference(buffer));
+
+            dest = this;
+        }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaFormat.cs b/src/ImageSharp/Formats/Tga/TgaFormat.cs
new file mode 100644
index 0000000000..badb1d77a4
--- /dev/null
+++ b/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
+{
+    /// 
+    /// Registers the image encoders, decoders and mime type detectors for the tga format.
+    /// 
+    public sealed class TgaFormat : IImageFormat
+    {
+        /// 
+        /// Gets the current instance.
+        /// 
+        public static TgaFormat Instance { get; } = new TgaFormat();
+
+        /// 
+        public string Name => "TGA";
+
+        /// 
+        public string DefaultMimeType => "image/tga";
+
+        /// 
+        public IEnumerable MimeTypes => TgaConstants.MimeTypes;
+
+        /// 
+        public IEnumerable FileExtensions => TgaConstants.FileExtensions;
+
+        /// 
+        public TgaMetadata CreateDefaultFormatMetadata() => new TgaMetadata();
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs
new file mode 100644
index 0000000000..bd9cfa900c
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Detects tga file headers.
+    /// 
+    public sealed class TgaImageFormatDetector : IImageFormatDetector
+    {
+        /// 
+        public int HeaderSize => TgaConstants.FileHeaderLength;
+
+        /// 
+        public IImageFormat DetectFormat(ReadOnlySpan header)
+        {
+            return this.IsSupportedFileFormat(header) ? TgaFormat.Instance : null;
+        }
+
+        private bool IsSupportedFileFormat(ReadOnlySpan header)
+        {
+            if (header.Length >= this.HeaderSize)
+            {
+                // There is no magick bytes in a tga file, so at least the image type
+                // and the colormap type in the header will be checked for a valid value.
+                if (header[1] != 0 && header[1] != 1)
+                {
+                    return false;
+                }
+
+                var imageType = (TgaImageType)header[2];
+                return imageType.IsValid();
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaImageType.cs b/src/ImageSharp/Formats/Tga/TgaImageType.cs
new file mode 100644
index 0000000000..491fd3ea77
--- /dev/null
+++ b/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
+{
+    /// 
+    /// 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.
+    /// 
+    public enum TgaImageType : byte
+    {
+        /// 
+        /// No image data included.
+        /// 
+        NoImageData = 0,
+
+        /// 
+        /// Uncompressed, color mapped image.
+        /// 
+        ColorMapped = 1,
+
+        /// 
+        /// Uncompressed true color image.
+        /// 
+        TrueColor = 2,
+
+        /// 
+        /// Uncompressed Black and white (grayscale) image.
+        /// 
+        BlackAndWhite = 3,
+
+        /// 
+        /// Run length encoded, color mapped image.
+        /// 
+        RleColorMapped = 9,
+
+        /// 
+        /// Run length encoded, true color image.
+        /// 
+        RleTrueColor = 10,
+
+        /// 
+        /// Run length encoded, black and white (grayscale) image.
+        /// 
+        RleBlackAndWhite = 11,
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaImageTypeExtensions.cs b/src/ImageSharp/Formats/Tga/TgaImageTypeExtensions.cs
new file mode 100644
index 0000000000..6a30cdddd7
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaImageTypeExtensions.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Extension methods for TgaImageType enum.
+    /// 
+    public static class TgaImageTypeExtensions
+    {
+        /// 
+        /// Checks if this tga image type is run length encoded.
+        /// 
+        /// The tga image type.
+        /// True, if this image type is run length encoded, otherwise false.
+        public static bool IsRunLengthEncoded(this TgaImageType imageType)
+        {
+            if (imageType is TgaImageType.RleColorMapped || imageType is TgaImageType.RleBlackAndWhite || imageType is TgaImageType.RleTrueColor)
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        /// 
+        /// Checks, if the image type has valid value.
+        /// 
+        /// The image type.
+        /// true, if its a valid tga image type.
+        public static bool IsValid(this TgaImageType imageType)
+        {
+            switch (imageType)
+            {
+                case TgaImageType.NoImageData:
+                case TgaImageType.ColorMapped:
+                case TgaImageType.TrueColor:
+                case TgaImageType.BlackAndWhite:
+                case TgaImageType.RleColorMapped:
+                case TgaImageType.RleTrueColor:
+                case TgaImageType.RleBlackAndWhite:
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaMetadata.cs b/src/ImageSharp/Formats/Tga/TgaMetadata.cs
new file mode 100644
index 0000000000..4ce61d2e48
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaMetadata.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    /// 
+    /// Provides TGA specific metadata information for the image.
+    /// 
+    public class TgaMetadata : IDeepCloneable
+    {
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        public TgaMetadata()
+        {
+        }
+
+        /// 
+        /// Initializes a new instance of the  class.
+        /// 
+        /// The metadata to create an instance from.
+        private TgaMetadata(TgaMetadata other)
+        {
+            this.BitsPerPixel = other.BitsPerPixel;
+        }
+
+        /// 
+        /// Gets or sets the number of bits per pixel.
+        /// 
+        public TgaBitsPerPixel BitsPerPixel { get; set; } = TgaBitsPerPixel.Pixel24;
+
+        /// 
+        public IDeepCloneable DeepClone() => new TgaMetadata(this);
+    }
+}
diff --git a/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs b/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs
new file mode 100644
index 0000000000..845d009227
--- /dev/null
+++ b/src/ImageSharp/Formats/Tga/TgaThrowHelper.cs
@@ -0,0 +1,31 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace SixLabors.ImageSharp.Formats.Tga
+{
+    internal static class TgaThrowHelper
+    {
+        /// 
+        /// Cold path optimization for throwing -s
+        /// 
+        /// The error message for the exception.
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        public static void ThrowImageFormatException(string errorMessage)
+        {
+            throw new ImageFormatException(errorMessage);
+        }
+
+        /// 
+        /// Cold path optimization for throwing -s
+        /// 
+        /// The error message for the exception.
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        public static void ThrowNotSupportedException(string errorMessage)
+        {
+            throw new NotSupportedException(errorMessage);
+        }
+    }
+}
diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt
index 8603012321..459924c318 100644
--- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt
+++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt
@@ -18,7 +18,7 @@
         /// 
         /// Converts all pixels in 'source` span of  into a span of -s.
         /// 
-        /// A  to configure internal operations
+        /// A  to configure internal operations.
         /// The source  of  data.
         /// The  to the destination pixels.
         internal virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destPixels)
@@ -41,7 +41,7 @@
         /// A helper for  that expects a byte span.
         /// The layout of the data in 'sourceBytes' must be compatible with  layout.
         /// 
-        /// A  to configure internal operations
+        /// A  to configure internal operations.
         /// The  to the source bytes.
         /// The  to the destination pixels.
         /// The number of pixels to convert.
diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs
index f2f11cbfe5..622c133aeb 100644
--- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs
@@ -349,7 +349,7 @@ private void AddPixelsToHistogram(ref Vector4 greyValuesBase, ref int histogramB
         {
             for (int idx = 0; idx < length; idx++)
             {
-                int luminance = GetLuminance(ref Unsafe.Add(ref greyValuesBase, idx), luminanceLevels);
+                int luminance = ImageMaths.GetBT709Luminance(ref Unsafe.Add(ref greyValuesBase, idx), luminanceLevels);
                 Unsafe.Add(ref histogramBase, luminance)++;
             }
         }
@@ -366,7 +366,7 @@ private void RemovePixelsFromHistogram(ref Vector4 greyValuesBase, ref int histo
         {
             for (int idx = 0; idx < length; idx++)
             {
-                int luminance = GetLuminance(ref Unsafe.Add(ref greyValuesBase, idx), luminanceLevels);
+                int luminance = ImageMaths.GetBT709Luminance(ref Unsafe.Add(ref greyValuesBase, idx), luminanceLevels);
                 Unsafe.Add(ref histogramBase, luminance)--;
             }
         }
diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs
index 6e4c16de76..284b9de1f6 100644
--- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs
@@ -143,16 +143,7 @@ public void ClipHistogram(Span histogram, int clipLimit)
         public static int GetLuminance(TPixel sourcePixel, int luminanceLevels)
         {
             var vector = sourcePixel.ToVector4();
-            return GetLuminance(ref vector, luminanceLevels);
+            return ImageMaths.GetBT709Luminance(ref vector, luminanceLevels);
         }
-
-        /// 
-        /// Convert the pixel values to grayscale using ITU-R Recommendation BT.709.
-        /// 
-        /// The vector to get the luminance from
-        /// The number of luminance levels (256 for 8 bit, 65536 for 16 bit grayscale images)
-        [MethodImpl(InliningOptions.ShortMethod)]
-        public static int GetLuminance(ref Vector4 vector, int luminanceLevels)
-            => (int)MathF.Round(((.2126F * vector.X) + (.7152F * vector.Y) + (.0722F * vector.Y)) * (luminanceLevels - 1));
     }
 }
diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs
new file mode 100644
index 0000000000..e3c7216102
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs
@@ -0,0 +1,42 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+
+using BenchmarkDotNet.Attributes;
+
+using ImageMagick;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs
+{
+    [Config(typeof(Config.ShortClr))]
+    public class DecodeTga : BenchmarkBase
+    {
+        private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
+
+        [Params(TestImages.Tga.Bit24)]
+        public string TestImage { get; set; }
+
+        [Benchmark(Baseline = true, Description = "ImageMagick Tga")]
+        public Size TgaImageMagick()
+        {
+            using (var magickImage = new MagickImage(this.TestImageFullPath))
+            {
+                return new Size(magickImage.Width, magickImage.Height);
+            }
+        }
+
+        [Benchmark(Description = "ImageSharp Tga")]
+        public Size TgaCore()
+        {
+            using (var image = Image.Load(this.TestImageFullPath))
+            {
+                return new Size(image.Width, image.Height);
+            }
+        }
+    }
+}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs
new file mode 100644
index 0000000000..ddcbec218e
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeTga.cs
@@ -0,0 +1,54 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+
+using BenchmarkDotNet.Attributes;
+
+using ImageMagick;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests;
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs
+{
+    [Config(typeof(Config.ShortClr))]
+    public class EncodeTga : BenchmarkBase
+    {
+        private MagickImage tgaMagick;
+        private Image tgaCore;
+
+        private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
+
+        [Params(TestImages.Tga.Bit24)]
+        public string TestImage { get; set; }
+
+        [GlobalSetup]
+        public void ReadImages()
+        {
+            if (this.tgaCore == null)
+            {
+                this.tgaCore = Image.Load(TestImageFullPath);
+                this.tgaMagick = new MagickImage(this.TestImageFullPath);
+            }
+        }
+
+        [Benchmark(Baseline = true, Description = "Magick Tga")]
+        public void BmpSystemDrawing()
+        {
+            using (var memoryStream = new MemoryStream())
+            {
+                this.tgaMagick.Write(memoryStream, MagickFormat.Tga);
+            }
+        }
+
+        [Benchmark(Description = "ImageSharp Tga")]
+        public void BmpCore()
+        {
+            using (var memoryStream = new MemoryStream())
+            {
+                this.tgaCore.SaveAsBmp(memoryStream);
+            }
+        }
+    }
+}
diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
index 14ad5635cd..a57d388a95 100644
--- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
+++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
@@ -16,6 +16,7 @@
   
 
   
+    
     
     
     
diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs
index a0e552aebf..6b35bbb972 100644
--- a/tests/ImageSharp.Tests/ConfigurationTests.cs
+++ b/tests/ImageSharp.Tests/ConfigurationTests.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
 // Licensed under the Apache License, Version 2.0.
 
 using System;
@@ -20,6 +20,8 @@ public class ConfigurationTests
         public Configuration ConfigurationEmpty { get; }
         public Configuration DefaultConfiguration { get; }
 
+        private readonly int expectedDefaultConfigurationCount = 5;
+
         public ConfigurationTests()
         {
             // the shallow copy of configuration should behave exactly like the default configuration,
@@ -108,14 +110,13 @@ public void AddFormatCallsConfig()
         [Fact]
         public void ConfigurationCannotAddDuplicates()
         {
-            const int count = 4;
             Configuration config = this.DefaultConfiguration;
 
-            Assert.Equal(count, config.ImageFormats.Count());
+            Assert.Equal(expectedDefaultConfigurationCount, config.ImageFormats.Count());
 
             config.ImageFormatsManager.AddImageFormat(BmpFormat.Instance);
 
-            Assert.Equal(count, config.ImageFormats.Count());
+            Assert.Equal(expectedDefaultConfigurationCount, config.ImageFormats.Count());
         }
 
         [Fact]
@@ -123,7 +124,7 @@ public void DefaultConfigurationHasCorrectFormatCount()
         {
             Configuration config = Configuration.CreateDefaultInstance();
 
-            Assert.Equal(4, config.ImageFormats.Count());
+            Assert.Equal(expectedDefaultConfigurationCount, config.ImageFormats.Count());
         }
 
         [Fact]
diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs
index 25cf29406e..4c3fe31493 100644
--- a/tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpFileHeaderTests.cs
@@ -1,4 +1,11 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
 using System;
+using System.IO;
+using System.Linq;
+
+using SixLabors.ImageSharp.Formats;
 using SixLabors.ImageSharp.Formats.Bmp;
 using Xunit;
 
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
index 2a76310fcd..e064c0fb06 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
@@ -218,7 +218,7 @@ public void Issue1014(TestImageProvider provider)
                     using (Image image = provider.GetImage(new PngDecoder()))
                     {
                         image.DebugSave(provider);
-                        // TODO: compare to expected output
+                        image.CompareToOriginal(provider, ImageComparer.Exact);
                     }
                 });
             Assert.Null(ex);
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
new file mode 100644
index 0000000000..03ad10de40
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs
@@ -0,0 +1,197 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+// ReSharper disable InconsistentNaming
+
+using SixLabors.ImageSharp.Formats.Tga;
+using SixLabors.ImageSharp.PixelFormats;
+
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Tga
+{
+    using static TestImages.Tga;
+
+    public class TgaDecoderTests
+    {
+        [Theory]
+        [WithFile(Grey, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_Uncompressed_MonoChrome(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit15, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_Uncompressed_15Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit15Rle, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_RunLengthEncoded_15Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit16, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_Uncompressed_16Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit16PalRle, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_RunLengthEncoded_WithPalette_16Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit24, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_Uncompressed_24Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit24RleTopLeft, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_RunLengthEncoded_WithTopLeftOrigin_24Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit24TopLeft, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_Palette_WithTopLeftOrigin_24Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_Uncompressed_32Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(GreyRle, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_RunLengthEncoded_MonoChrome(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit16Rle, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_RunLengthEncoded_16Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit24Rle, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_RunLengthEncoded_24Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit32Rle, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_RunLengthEncoded_32Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit16Pal, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_WithPalette_16Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit24Pal, PixelTypes.Rgba32)]
+        public void TgaDecoder_CanDecode_WithPalette_24Bit(TestImageProvider provider)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage(new TgaDecoder()))
+            {
+                image.DebugSave(provider);
+                TgaTestUtils.CompareWithReferenceDecoder(provider, image);
+            }
+        }
+    }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs
new file mode 100644
index 0000000000..e946729a15
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs
@@ -0,0 +1,148 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+// ReSharper disable InconsistentNaming
+
+using System.IO;
+
+using SixLabors.ImageSharp.Formats.Tga;
+using SixLabors.ImageSharp.PixelFormats;
+
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Tga
+{
+    using static TestImages.Tga;
+
+    public class TgaEncoderTests
+    {
+        public static readonly TheoryData BitsPerPixel =
+            new TheoryData
+            {
+                TgaBitsPerPixel.Pixel24,
+                TgaBitsPerPixel.Pixel32
+            };
+
+        public static readonly TheoryData TgaBitsPerPixelFiles =
+            new TheoryData
+            {
+                { Grey, TgaBitsPerPixel.Pixel8 },
+                { Bit32, TgaBitsPerPixel.Pixel32 },
+                { Bit24, TgaBitsPerPixel.Pixel24 },
+                { Bit16, TgaBitsPerPixel.Pixel16 },
+            };
+
+        [Theory]
+        [MemberData(nameof(TgaBitsPerPixelFiles))]
+        public void Encode_PreserveBitsPerPixel(string imagePath, TgaBitsPerPixel bmpBitsPerPixel)
+        {
+            var options = new TgaEncoder();
+
+            TestFile testFile = TestFile.Create(imagePath);
+            using (Image input = testFile.CreateRgba32Image())
+            {
+                using (var memStream = new MemoryStream())
+                {
+                    input.Save(memStream, options);
+                    memStream.Position = 0;
+                    using (Image output = Image.Load(memStream))
+                    {
+                        TgaMetadata meta = output.Metadata.GetFormatMetadata(TgaFormat.Instance);
+                        Assert.Equal(bmpBitsPerPixel, meta.BitsPerPixel);
+                    }
+                }
+            }
+        }
+
+        [Theory]
+        [MemberData(nameof(TgaBitsPerPixelFiles))]
+        public void Encode_WithCompression_PreserveBitsPerPixel(string imagePath, TgaBitsPerPixel bmpBitsPerPixel)
+        {
+            var options = new TgaEncoder()
+                          {
+                              Compression = TgaCompression.RunLength
+                          };
+
+            TestFile testFile = TestFile.Create(imagePath);
+            using (Image input = testFile.CreateRgba32Image())
+            {
+                using (var memStream = new MemoryStream())
+                {
+                    input.Save(memStream, options);
+                    memStream.Position = 0;
+                    using (Image output = Image.Load(memStream))
+                    {
+                        TgaMetadata meta = output.Metadata.GetFormatMetadata(TgaFormat.Instance);
+                        Assert.Equal(bmpBitsPerPixel, meta.BitsPerPixel);
+                    }
+                }
+            }
+        }
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void Encode_Bit8_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8)
+            // using tolerant comparer here. The results from magick differ slightly. Maybe a different ToGrey method is used. The image looks otherwise ok.
+            where TPixel : struct, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None, useExactComparer: false, compareTolerance: 0.03f);
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void Encode_Bit16_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16)
+            where TPixel : struct, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None, useExactComparer: false);
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void Encode_Bit24_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24)
+            where TPixel : struct, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None);
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void Encode_Bit32_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32)
+            where TPixel : struct, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.None);
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void Encode_Bit8_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel8)
+            // using tolerant comparer here. The results from magick differ slightly. Maybe a different ToGrey method is used. The image looks otherwise ok.
+            where TPixel : struct, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength, useExactComparer: false, compareTolerance: 0.03f);
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void Encode_Bit16_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel16)
+            where TPixel : struct, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength, useExactComparer: false);
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void Encode_Bit24_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel24)
+            where TPixel : struct, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength);
+
+        [Theory]
+        [WithFile(Bit32, PixelTypes.Rgba32)]
+        public void Encode_Bit32_WithRunLengthEncoding_Works(TestImageProvider provider, TgaBitsPerPixel bitsPerPixel = TgaBitsPerPixel.Pixel32)
+            where TPixel : struct, IPixel => TestTgaEncoderCore(provider, bitsPerPixel, TgaCompression.RunLength);
+
+        private static void TestTgaEncoderCore(
+            TestImageProvider provider,
+            TgaBitsPerPixel bitsPerPixel,
+            TgaCompression compression = TgaCompression.None,
+            bool useExactComparer = true,
+            float compareTolerance = 0.01f)
+            where TPixel : struct, IPixel
+        {
+            using (Image image = provider.GetImage())
+            {
+                var encoder = new TgaEncoder { BitsPerPixel = bitsPerPixel, Compression = compression};
+
+                using (var memStream = new MemoryStream())
+                {
+                    image.Save(memStream, encoder);
+                    memStream.Position = 0;
+                    using (var encodedImage = (Image)Image.Load(memStream))
+                    {
+                        TgaTestUtils.CompareWithReferenceDecoder(provider, encodedImage, useExactComparer, compareTolerance);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs
new file mode 100644
index 0000000000..c227b79576
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs
@@ -0,0 +1,33 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.IO;
+
+using SixLabors.ImageSharp.Formats;
+
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Tga
+{
+    public class TgaFileHeaderTests
+    {
+        private static readonly byte[] Data = {
+                                                  0,
+                                                  0,
+                                                  15 // invalid tga image type
+                                              };
+
+        private MemoryStream Stream { get; } = new MemoryStream(Data);
+
+        [Fact]
+        public void ImageLoad_WithInvalidImageType_Throws_UnknownImageFormatException()
+        {
+            Assert.Throws(() =>
+            {
+                using (Image.Load(Configuration.Default, this.Stream, out IImageFormat _))
+                {
+                }
+            });
+        }
+    }
+}
diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
new file mode 100644
index 0000000000..a2f2e86d7d
--- /dev/null
+++ b/tests/ImageSharp.Tests/Formats/Tga/TgaTestUtils.cs
@@ -0,0 +1,61 @@
+using System;
+using System.IO;
+
+using ImageMagick;
+
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
+
+namespace SixLabors.ImageSharp.Tests.Formats.Tga
+{
+    public static class TgaTestUtils
+    {
+        public static void CompareWithReferenceDecoder(TestImageProvider provider,
+                                                               Image image,
+                                                               bool useExactComparer = true,
+                                                               float compareTolerance = 0.01f)
+            where TPixel : struct, IPixel
+        {
+            string path = TestImageProvider.GetFilePathOrNull(provider);
+            if (path == null)
+            {
+                throw new InvalidOperationException("CompareToOriginal() works only with file providers!");
+            }
+
+            TestFile testFile = TestFile.Create(path);
+            Image magickImage = DecodeWithMagick(Configuration.Default, new FileInfo(testFile.FullPath));
+            if (useExactComparer)
+            {
+                ImageComparer.Exact.VerifySimilarity(magickImage, image);
+            }
+            else
+            {
+                ImageComparer.Tolerant(compareTolerance).VerifySimilarity(magickImage, image);
+            }
+        }
+
+        public static Image DecodeWithMagick(Configuration configuration, FileInfo fileInfo)
+            where TPixel : struct, IPixel
+        {
+            using (var magickImage = new MagickImage(fileInfo))
+            {
+                var result = new Image(configuration, magickImage.Width, magickImage.Height);
+                Span resultPixels = result.GetPixelSpan();
+
+                using (IPixelCollection pixels = magickImage.GetPixelsUnsafe())
+                {
+                    byte[] data = pixels.ToByteArray(PixelMapping.RGBA);
+
+                    PixelOperations.Instance.FromRgba32Bytes(
+                        configuration,
+                        data,
+                        resultPixels,
+                        resultPixels.Length);
+                }
+
+                return result;
+            }
+        }
+    }
+}
diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs
index 018fabd982..817672f34a 100644
--- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs
+++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs
@@ -2,6 +2,11 @@
 // Licensed under the Apache License, Version 2.0.
 
 using System;
+using System.Numerics;
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Memory;
+
 using Xunit;
 
 namespace SixLabors.ImageSharp.Tests.Helpers
@@ -131,6 +136,23 @@ public void LeastCommonMultiple(int a, int b, int expected)
             Assert.Equal(expected, actual);
         }
 
+        [Theory]
+        [InlineData(0.2f, 0.7f, 0.1f, 256, 140)]
+        [InlineData(0.5f, 0.5f, 0.5f, 256, 128)]
+        [InlineData(0.5f, 0.5f, 0.5f, 65536, 32768)]
+        [InlineData(0.2f, 0.7f, 0.1f, 65536, 36069)]
+        public void GetBT709Luminance_WithVector4(float x, float y, float z, int luminanceLevels, int expected)
+        {
+            // arrange
+            var vector = new Vector4(x, y, z, 0.0f);
+
+            // act
+            int actual = ImageMaths.GetBT709Luminance(ref vector, luminanceLevels);
+
+            // assert
+            Assert.Equal(expected, actual);
+        }
+
         // TODO: We need to test all ImageMaths methods!
     }
-}
\ No newline at end of file
+}
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 146f2efcdb..1777498694 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -365,5 +365,24 @@ public static class Issues
 
             public static readonly string[] All = { Rings, Giphy, Cheers, Trans, Kumin, Leo, Ratio4x1, Ratio1x4 };
         }
+
+        public static class Tga
+        {
+            public const string Bit15 = "Tga/rgb15.tga";
+            public const string Bit15Rle = "Tga/rgb15rle.tga";
+            public const string Bit16 = "Tga/targa_16bit.tga";
+            public const string Bit16PalRle = "Tga/ccm8.tga";
+            public const string Bit24 = "Tga/targa_24bit.tga";
+            public const string Bit24TopLeft = "Tga/targa_24bit_pal_origin_topleft.tga";
+            public const string Bit24RleTopLeft = "Tga/targa_24bit_rle_origin_topleft.tga";
+            public const string Bit32 = "Tga/targa_32bit.tga";
+            public const string Grey = "Tga/targa_8bit.tga";
+            public const string GreyRle = "Tga/targa_8bit_rle.tga";
+            public const string Bit16Rle = "Tga/targa_16bit_rle.tga";
+            public const string Bit24Rle = "Tga/targa_24bit_rle.tga";
+            public const string Bit32Rle = "Tga/targa_32bit_rle.tga";
+            public const string Bit16Pal = "Tga/targa_16bit_pal.tga";
+            public const string Bit24Pal = "Tga/targa_24bit_pal.tga";
+        }
     }
 }
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
index 7d06847223..e09b27c714 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs
@@ -8,6 +8,7 @@
 using SixLabors.ImageSharp.Formats.Gif;
 using SixLabors.ImageSharp.Formats.Jpeg;
 using SixLabors.ImageSharp.Formats.Png;
+using SixLabors.ImageSharp.Formats.Tga;
 using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs;
 
 namespace SixLabors.ImageSharp.Tests
@@ -53,7 +54,8 @@ private static Configuration CreateDefaultConfiguration()
         {
             var cfg = new Configuration(
                 new JpegConfigurationModule(),
-                new GifConfigurationModule()
+                new GifConfigurationModule(),
+                new TgaConfigurationModule()
             );
 
             // Magick codecs should work on all platforms
@@ -75,4 +77,4 @@ private static Configuration CreateDefaultConfiguration()
             return cfg;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/Images/External b/tests/Images/External
index f0c4033667..ca4cf8318f 160000
--- a/tests/Images/External
+++ b/tests/Images/External
@@ -1 +1 @@
-Subproject commit f0c4033667bd23ad9dde82ccb625c232d402ee05
+Subproject commit ca4cf8318fe4d09f0fc825686dcd477ebfb5e3e5
diff --git a/tests/Images/Input/Tga/ccm8.tga b/tests/Images/Input/Tga/ccm8.tga
new file mode 100644
index 0000000000..7a21efef7b
Binary files /dev/null and b/tests/Images/Input/Tga/ccm8.tga differ
diff --git a/tests/Images/Input/Tga/rgb15.tga b/tests/Images/Input/Tga/rgb15.tga
new file mode 100644
index 0000000000..9506b418ae
Binary files /dev/null and b/tests/Images/Input/Tga/rgb15.tga differ
diff --git a/tests/Images/Input/Tga/rgb15rle.tga b/tests/Images/Input/Tga/rgb15rle.tga
new file mode 100644
index 0000000000..5d4672c9cf
Binary files /dev/null and b/tests/Images/Input/Tga/rgb15rle.tga differ
diff --git a/tests/Images/Input/Tga/targa.png b/tests/Images/Input/Tga/targa.png
new file mode 100644
index 0000000000..c18cf7e23d
Binary files /dev/null and b/tests/Images/Input/Tga/targa.png differ
diff --git a/tests/Images/Input/Tga/targa_16bit.tga b/tests/Images/Input/Tga/targa_16bit.tga
new file mode 100644
index 0000000000..eeaf33d592
Binary files /dev/null and b/tests/Images/Input/Tga/targa_16bit.tga differ
diff --git a/tests/Images/Input/Tga/targa_16bit_pal.tga b/tests/Images/Input/Tga/targa_16bit_pal.tga
new file mode 100644
index 0000000000..8074ad78f5
Binary files /dev/null and b/tests/Images/Input/Tga/targa_16bit_pal.tga differ
diff --git a/tests/Images/Input/Tga/targa_16bit_rle.tga b/tests/Images/Input/Tga/targa_16bit_rle.tga
new file mode 100644
index 0000000000..968f4de320
Binary files /dev/null and b/tests/Images/Input/Tga/targa_16bit_rle.tga differ
diff --git a/tests/Images/Input/Tga/targa_24bit.tga b/tests/Images/Input/Tga/targa_24bit.tga
new file mode 100644
index 0000000000..ebe78aea5f
Binary files /dev/null and b/tests/Images/Input/Tga/targa_24bit.tga differ
diff --git a/tests/Images/Input/Tga/targa_24bit_pal.tga b/tests/Images/Input/Tga/targa_24bit_pal.tga
new file mode 100644
index 0000000000..d97c646748
Binary files /dev/null and b/tests/Images/Input/Tga/targa_24bit_pal.tga differ
diff --git a/tests/Images/Input/Tga/targa_24bit_pal_origin_topleft.tga b/tests/Images/Input/Tga/targa_24bit_pal_origin_topleft.tga
new file mode 100644
index 0000000000..0c3ad641d1
Binary files /dev/null and b/tests/Images/Input/Tga/targa_24bit_pal_origin_topleft.tga differ
diff --git a/tests/Images/Input/Tga/targa_24bit_rle.tga b/tests/Images/Input/Tga/targa_24bit_rle.tga
new file mode 100644
index 0000000000..e887af750b
Binary files /dev/null and b/tests/Images/Input/Tga/targa_24bit_rle.tga differ
diff --git a/tests/Images/Input/Tga/targa_24bit_rle_origin_topleft.tga b/tests/Images/Input/Tga/targa_24bit_rle_origin_topleft.tga
new file mode 100644
index 0000000000..53e08c5e2c
Binary files /dev/null and b/tests/Images/Input/Tga/targa_24bit_rle_origin_topleft.tga differ
diff --git a/tests/Images/Input/Tga/targa_32bit.tga b/tests/Images/Input/Tga/targa_32bit.tga
new file mode 100644
index 0000000000..7f29e022fd
Binary files /dev/null and b/tests/Images/Input/Tga/targa_32bit.tga differ
diff --git a/tests/Images/Input/Tga/targa_32bit_rle.tga b/tests/Images/Input/Tga/targa_32bit_rle.tga
new file mode 100644
index 0000000000..c5af174b1f
Binary files /dev/null and b/tests/Images/Input/Tga/targa_32bit_rle.tga differ
diff --git a/tests/Images/Input/Tga/targa_8bit.tga b/tests/Images/Input/Tga/targa_8bit.tga
new file mode 100644
index 0000000000..0b69052ec2
Binary files /dev/null and b/tests/Images/Input/Tga/targa_8bit.tga differ
diff --git a/tests/Images/Input/Tga/targa_8bit_rle.tga b/tests/Images/Input/Tga/targa_8bit_rle.tga
new file mode 100644
index 0000000000..21e9dfa3dd
Binary files /dev/null and b/tests/Images/Input/Tga/targa_8bit_rle.tga differ