mirror of https://github.com/SixLabors/ImageSharp
7 changed files with 228 additions and 1 deletions
@ -0,0 +1,16 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tga |
|||
{ |
|||
/// <summary>
|
|||
/// Configuration options for use during tga encoding.
|
|||
/// </summary>
|
|||
internal interface ITgaEncoderOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the number of bits per pixel.
|
|||
/// </summary>
|
|||
TgaBitsPerPixel? BitsPerPixel { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tga |
|||
{ |
|||
/// <summary>
|
|||
/// Enumerates the available bits per pixel the tga encoder supports.
|
|||
/// </summary>
|
|||
public enum TgaBitsPerPixel : byte |
|||
{ |
|||
/// <summary>
|
|||
/// 8 bits per pixel. Each pixel consists of 1 byte.
|
|||
/// </summary>
|
|||
Pixel8 = 8, |
|||
|
|||
/// <summary>
|
|||
/// 16 bits per pixel. Each pixel consists of 2 bytes.
|
|||
/// </summary>
|
|||
Pixel16 = 16, |
|||
|
|||
/// <summary>
|
|||
/// 24 bits per pixel. Each pixel consists of 3 bytes.
|
|||
/// </summary>
|
|||
Pixel24 = 24, |
|||
|
|||
/// <summary>
|
|||
/// 32 bits per pixel. Each pixel consists of 4 bytes.
|
|||
/// </summary>
|
|||
Pixel32 = 32 |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// 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 |
|||
{ |
|||
public sealed class TgaEncoder : IImageEncoder, ITgaEncoderOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the number of bits per pixel.
|
|||
/// </summary>
|
|||
public TgaBitsPerPixel? BitsPerPixel { get; set; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Encode<TPixel>(Image<TPixel> image, Stream stream) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
var encoder = new TgaEncoderCore(this, image.GetMemoryAllocator()); |
|||
encoder.Encode(image, stream); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,131 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.IO; |
|||
|
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.Metadata; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tga |
|||
{ |
|||
/// <summary>
|
|||
/// Image encoder for writing an image to a stream as a truevision targa image.
|
|||
/// </summary>
|
|||
internal sealed class TgaEncoderCore |
|||
{ |
|||
/// <summary>
|
|||
/// Used for allocating memory during processing operations.
|
|||
/// </summary>
|
|||
private readonly MemoryAllocator memoryAllocator; |
|||
|
|||
/// <summary>
|
|||
/// The global configuration.
|
|||
/// </summary>
|
|||
private Configuration configuration; |
|||
|
|||
/// <summary>
|
|||
/// The color depth, in number of bits per pixel.
|
|||
/// </summary>
|
|||
private TgaBitsPerPixel? bitsPerPixel; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="TgaEncoderCore"/> class.
|
|||
/// </summary>
|
|||
/// <param name="options">The encoder options.</param>
|
|||
/// <param name="memoryAllocator">The memory manager.</param>
|
|||
public TgaEncoderCore(ITgaEncoderOptions options, MemoryAllocator memoryAllocator) |
|||
{ |
|||
this.memoryAllocator = memoryAllocator; |
|||
this.bitsPerPixel = options.BitsPerPixel; |
|||
} |
|||
|
|||
public void Encode<TPixel>(Image<TPixel> image, Stream stream) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(image, nameof(image)); |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
|
|||
this.configuration = image.GetConfiguration(); |
|||
ImageMetadata metadata = image.Metadata; |
|||
TgaMetadata tgaMetadata = metadata.GetFormatMetadata(TgaFormat.Instance); |
|||
this.bitsPerPixel = this.bitsPerPixel ?? tgaMetadata.BitsPerPixel; |
|||
|
|||
var fileHeader = new TgaFileHeader( |
|||
idLength: 0, |
|||
colorMapType: 0, |
|||
imageType: TgaImageType.TrueColor, |
|||
cMapStart: 0, |
|||
cMapLength: 0, |
|||
cMapDepth: 0, |
|||
xOffset: 0, |
|||
yOffset: 0, |
|||
width: (short)image.Width, |
|||
height: (short)image.Height, |
|||
pixelDepth: (byte)this.bitsPerPixel.Value, |
|||
imageDescriptor: 0); |
|||
|
|||
#if NETCOREAPP2_1
|
|||
Span<byte> buffer = stackalloc byte[TgaFileHeader.Size]; |
|||
#else
|
|||
var buffer = new byte[TgaFileHeader.Size]; |
|||
#endif
|
|||
fileHeader.WriteTo(buffer); |
|||
|
|||
stream.Write(buffer, 0, TgaFileHeader.Size); |
|||
|
|||
this.WriteImage(stream, image.Frames.RootFrame); |
|||
|
|||
stream.Flush(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Writes the pixel data to the binary stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
|
|||
/// <param name="image">
|
|||
/// The <see cref="ImageFrame{TPixel}"/> containing pixel data.
|
|||
/// </param>
|
|||
private void WriteImage<TPixel>(Stream stream, ImageFrame<TPixel> image) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
Buffer2D<TPixel> pixels = image.PixelBuffer; |
|||
switch (this.bitsPerPixel) |
|||
{ |
|||
case TgaBitsPerPixel.Pixel24: |
|||
this.Write24Bit(stream, pixels); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel) => this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, 0); |
|||
|
|||
/// <summary>
|
|||
/// Writes the 24bit pixels uncompressed to the stream.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
|
|||
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> containing pixel data.</param>
|
|||
private void Write24Bit<TPixel>(Stream stream, Buffer2D<TPixel> pixels) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
using (IManagedByteBuffer row = this.AllocateRow(pixels.Width, 3)) |
|||
{ |
|||
for (int y = pixels.Height - 1; y >= 0; y--) |
|||
{ |
|||
Span<TPixel> pixelSpan = pixels.GetRowSpan(y); |
|||
PixelOperations<TPixel>.Instance.ToBgr24Bytes( |
|||
this.configuration, |
|||
pixelSpan, |
|||
row.GetSpan(), |
|||
pixelSpan.Length); |
|||
stream.Write(row.Array, 0, row.Length()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue