Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions src/ImageSharp/Formats/Tga/TgaImageFormatDetector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
public sealed class TgaImageFormatDetector : IImageFormatDetector
{
/// <inheritdoc/>
public int HeaderSize => TgaConstants.FileHeaderLength;
public int HeaderSize => 16;

/// <inheritdoc/>
public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
Expand All @@ -23,15 +23,38 @@ private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{
if (header.Length >= this.HeaderSize)
{
// There are no magic 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.
// There are no magic bytes in the first few bytes of a tga file,
// so we try to figure out if its a valid tga by checking for valid tga header bytes.

// The color map type should be either 0 or 1, other values are not valid.
if (header[1] != 0 && header[1] != 1)
{
return false;
}

// The third byte is the image type.
var imageType = (TgaImageType)header[2];
return imageType.IsValid();
if (!imageType.IsValid())
{
return false;
}

// If the color map typ is zero, all bytes of the color map specification should also be zeros.
if (header[1] == 0)
{
if (header[3] != 0 || header[4] != 0 || header[5] != 0 || header[6] != 0 || header[7] != 0)
{
return false;
}
}

// The height or the width of the image should not be zero.
if ((header[12] == 0 && header[13] == 0) || (header[14] == 0 && header[15] == 0))
{
return false;
}

return true;
}

return false;
Expand Down
44 changes: 32 additions & 12 deletions tests/ImageSharp.Tests/Formats/Tga/TgaFileHeaderTests.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,54 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.

using System.Collections.Generic;
using System.IO;

using SixLabors.ImageSharp.Formats;

using SixLabors.ImageSharp.Formats.Tga;
using Xunit;

namespace SixLabors.ImageSharp.Tests.Formats.Tga
{
public class TgaFileHeaderTests
{
private static readonly byte[] Data =
[Theory]
[InlineData(new byte[] { 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // invalid tga image type.
[InlineData(new byte[] { 0, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // invalid colormap type.
[InlineData(new byte[] { 0, 0, 1, 5, 5, 5, 5, 5, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero.
[InlineData(new byte[] { 0, 0, 1, 0, 0, 0, 0, 8, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero.
[InlineData(new byte[] { 0, 0, 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero.
[InlineData(new byte[] { 0, 0, 1, 0, 0, 6, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero.
[InlineData(new byte[] { 0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 })] // valid colormap type (0), but colomap spec bytes should all be zero.
[InlineData(new byte[] { 0, 0, 0, 12, 106, 80, 32, 32, 13, 10, 135, 10, 0, 0, 0, 20, 102, 116 })] // jp2 image header
[InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 195, 0, 32, 8 })] // invalid width
[InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 32, 8 })] // invalid height
public void ImageLoad_WithNoValidTgaHeaderBytes_Throws_UnknownImageFormatException(byte[] data)
{
0,
0,
15 // invalid tga image type
};

private MemoryStream Stream { get; } = new MemoryStream(Data);
using var stream = new MemoryStream(data);

[Fact]
public void ImageLoad_WithInvalidImageType_Throws_UnknownImageFormatException()
{
Assert.Throws<UnknownImageFormatException>(() =>
{
using (Image.Load(Configuration.Default, this.Stream, out IImageFormat _))
using (Image.Load(Configuration.Default, stream, out IImageFormat _))
{
}
});
}

[Theory]
[InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 195, 0, 32, 8 }, 250, 195, TgaBitsPerPixel.Pixel32)]
[InlineData(new byte[] { 26, 1, 9, 0, 0, 0, 1, 16, 0, 0, 0, 0, 128, 0, 128, 0, 8, 0 }, 128, 128, TgaBitsPerPixel.Pixel8)]
[InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 16, 0 }, 220, 220, TgaBitsPerPixel.Pixel16)]
[InlineData(new byte[] { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 124, 0, 124, 0, 24, 32 }, 124, 124, TgaBitsPerPixel.Pixel24)]
public void Identify_WithValidData_Works(byte[] data, int width, int height, TgaBitsPerPixel bitsPerPixel)
{
using var stream = new MemoryStream(data);

IImageInfo info = Image.Identify(stream);
TgaMetadata tgaData = info.Metadata.GetTgaMetadata();
Assert.Equal(bitsPerPixel, tgaData.BitsPerPixel);
Assert.Equal(width, info.Width);
Assert.Equal(height, info.Height);
}
}
}