Skip to content

Commit 1f4605e

Browse files
Implement TgaMetadata
1 parent b9994b6 commit 1f4605e

3 files changed

Lines changed: 81 additions & 28 deletions

File tree

src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
using System.Buffers;
55
using System.Buffers.Binary;
6-
using System.Numerics;
7-
using System.Runtime.CompilerServices;
86
using SixLabors.ImageSharp.Memory;
97
using SixLabors.ImageSharp.Metadata;
108
using SixLabors.ImageSharp.PixelFormats;
@@ -160,32 +158,40 @@ private void WriteRunLengthEncodedImage<TPixel>(Stream stream, ImageFrame<TPixel
160158
where TPixel : unmanaged, IPixel<TPixel>
161159
{
162160
Buffer2D<TPixel> pixels = image.PixelBuffer;
161+
162+
using IMemoryOwner<Rgba32> rgbaOwner = this.memoryAllocator.Allocate<Rgba32>(image.Width);
163+
Span<Rgba32> rgbaRow = rgbaOwner.GetSpan();
164+
163165
for (int y = 0; y < image.Height; y++)
164166
{
165167
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y);
168+
PixelOperations<TPixel>.Instance.ToRgba32(image.Configuration, pixelRow, rgbaRow);
169+
166170
for (int x = 0; x < image.Width;)
167171
{
168172
TPixel currentPixel = pixelRow[x];
173+
Rgba32 rgba = rgbaRow[x];
169174
byte equalPixelCount = FindEqualPixels(pixelRow, x);
170175

171176
if (equalPixelCount > 0)
172177
{
173-
// Write the number of equal pixels, with the high bit set, indicating ist a compressed pixel run.
178+
// Write the number of equal pixels, with the high bit set, indicating it's a compressed pixel run.
174179
stream.WriteByte((byte)(equalPixelCount | 128));
175-
this.WritePixel(stream, currentPixel, currentPixel.ToRgba32());
180+
this.WritePixel(stream, rgba);
176181
x += equalPixelCount + 1;
177182
}
178183
else
179184
{
180185
// Write Raw Packet (i.e., Non-Run-Length Encoded):
181186
byte unEqualPixelCount = FindUnEqualPixels(pixelRow, x);
182187
stream.WriteByte(unEqualPixelCount);
183-
this.WritePixel(stream, currentPixel, currentPixel.ToRgba32());
188+
this.WritePixel(stream, rgba);
184189
x++;
185190
for (int i = 0; i < unEqualPixelCount; i++)
186191
{
187192
currentPixel = pixelRow[x];
188-
this.WritePixel(stream, currentPixel, currentPixel.ToRgba32());
193+
rgba = rgbaRow[x];
194+
this.WritePixel(stream, rgba);
189195
x++;
190196
}
191197
}
@@ -196,22 +202,19 @@ private void WriteRunLengthEncodedImage<TPixel>(Stream stream, ImageFrame<TPixel
196202
/// <summary>
197203
/// Writes a the pixel to the stream.
198204
/// </summary>
199-
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
200205
/// <param name="stream">The stream to write to.</param>
201-
/// <param name="currentPixel">The current pixel.</param>
202206
/// <param name="color">The color of the pixel to write.</param>
203-
private void WritePixel<TPixel>(Stream stream, TPixel currentPixel, Rgba32 color)
204-
where TPixel : unmanaged, IPixel<TPixel>
207+
private void WritePixel(Stream stream, Rgba32 color)
205208
{
206209
switch (this.bitsPerPixel)
207210
{
208211
case TgaBitsPerPixel.Pixel8:
209-
int luminance = GetLuminance(currentPixel);
210-
stream.WriteByte((byte)luminance);
212+
L8 l8 = L8.FromRgba32(color);
213+
stream.WriteByte(l8.PackedValue);
211214
break;
212215

213216
case TgaBitsPerPixel.Pixel16:
214-
Bgra5551 bgra5551 = new(color.ToVector4());
217+
Bgra5551 bgra5551 = Bgra5551.FromRgba32(color);
215218
Span<byte> buffer = stackalloc byte[2];
216219
BinaryPrimitives.WriteInt16LittleEndian(buffer, (short)bgra5551.PackedValue);
217220
stream.WriteByte(buffer[0]);
@@ -402,17 +405,4 @@ private void Write32Bit<TPixel>(Configuration configuration, Stream stream, Buff
402405
stream.Write(rowSpan);
403406
}
404407
}
405-
406-
/// <summary>
407-
/// Convert the pixel values to grayscale using ITU-R Recommendation BT.709.
408-
/// </summary>
409-
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
410-
/// <param name="sourcePixel">The pixel to get the luminance from.</param>
411-
[MethodImpl(InliningOptions.ShortMethod)]
412-
public static int GetLuminance<TPixel>(TPixel sourcePixel)
413-
where TPixel : unmanaged, IPixel<TPixel>
414-
{
415-
Vector4 vector = sourcePixel.ToVector4();
416-
return ColorNumerics.GetBT709Luminance(ref vector, 256);
417-
}
418408
}

src/ImageSharp/Formats/Tga/TgaMetadata.cs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4+
using SixLabors.ImageSharp.PixelFormats;
5+
46
namespace SixLabors.ImageSharp.Formats.Tga;
57

68
/// <summary>
79
/// Provides TGA specific metadata information for the image.
810
/// </summary>
9-
public class TgaMetadata : IDeepCloneable
11+
public class TgaMetadata : IFormatMetadata<TgaMetadata>
1012
{
1113
/// <summary>
1214
/// Initializes a new instance of the <see cref="TgaMetadata"/> class.
@@ -33,5 +35,65 @@ private TgaMetadata(TgaMetadata other)
3335
public byte AlphaChannelBits { get; set; }
3436

3537
/// <inheritdoc/>
36-
public IDeepCloneable DeepClone() => new TgaMetadata(this);
38+
public static TgaMetadata FromFormatConnectingMetadata(FormatConnectingMetadata metadata)
39+
{
40+
// TODO: AlphaChannelBits is not used during encoding.
41+
int bpp = metadata.PixelTypeInfo.BitsPerPixel;
42+
return bpp switch
43+
{
44+
<= 8 => new TgaMetadata { BitsPerPixel = TgaBitsPerPixel.Pixel8 },
45+
<= 16 => new TgaMetadata { BitsPerPixel = TgaBitsPerPixel.Pixel16 },
46+
<= 24 => new TgaMetadata { BitsPerPixel = TgaBitsPerPixel.Pixel24 },
47+
_ => new TgaMetadata { BitsPerPixel = TgaBitsPerPixel.Pixel32 }
48+
};
49+
}
50+
51+
/// <inheritdoc/>
52+
public FormatConnectingMetadata ToFormatConnectingMetadata()
53+
{
54+
int bpp = (int)this.BitsPerPixel;
55+
56+
PixelComponentInfo info;
57+
PixelColorType color;
58+
PixelAlphaRepresentation alpha;
59+
switch (this.BitsPerPixel)
60+
{
61+
case TgaBitsPerPixel.Pixel8:
62+
info = PixelComponentInfo.Create(1, bpp, 8);
63+
color = PixelColorType.Luminance;
64+
alpha = PixelAlphaRepresentation.None;
65+
break;
66+
case TgaBitsPerPixel.Pixel16:
67+
info = PixelComponentInfo.Create(1, bpp, 5, 5, 5, 1);
68+
color = PixelColorType.BGR | PixelColorType.Alpha;
69+
alpha = PixelAlphaRepresentation.Unassociated;
70+
break;
71+
case TgaBitsPerPixel.Pixel24:
72+
info = PixelComponentInfo.Create(3, bpp, 8, 8, 8);
73+
color = PixelColorType.RGB;
74+
alpha = PixelAlphaRepresentation.None;
75+
break;
76+
case TgaBitsPerPixel.Pixel32 or _:
77+
info = PixelComponentInfo.Create(4, bpp, 8, 8, 8, 8);
78+
color = PixelColorType.RGB | PixelColorType.Alpha;
79+
alpha = PixelAlphaRepresentation.Unassociated;
80+
break;
81+
}
82+
83+
return new()
84+
{
85+
PixelTypeInfo = new PixelTypeInfo(bpp)
86+
{
87+
AlphaRepresentation = alpha,
88+
ComponentInfo = info,
89+
ColorType = color
90+
}
91+
};
92+
}
93+
94+
/// <inheritdoc/>
95+
IDeepCloneable IDeepCloneable.DeepClone() => this.DeepClone();
96+
97+
/// <inheritdoc/>
98+
public TgaMetadata DeepClone() => new(this);
3799
}

tests/ImageSharp.Tests/Formats/Tga/TgaEncoderTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ private static void TestTgaEncoderCore<TPixel>(
175175

176176
using (var memStream = new MemoryStream())
177177
{
178+
image.DebugSave(provider, encoder);
178179
image.Save(memStream, encoder);
179180
memStream.Position = 0;
180181
using (var encodedImage = (Image<TPixel>)Image.Load(memStream))

0 commit comments

Comments
 (0)