|
|
@ -20,6 +20,11 @@ namespace ImageProcessorCore.Formats |
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
private BmpBitsPerPixel bmpBitsPerPixel; |
|
|
private BmpBitsPerPixel bmpBitsPerPixel; |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The amount to pad each row by.</param>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private int padding; |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Encodes the image to the specified stream from the <see cref="ImageBase{T,TP}"/>.
|
|
|
/// Encodes the image to the specified stream from the <see cref="ImageBase{T,TP}"/>.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
@ -37,39 +42,33 @@ namespace ImageProcessorCore.Formats |
|
|
|
|
|
|
|
|
this.bmpBitsPerPixel = bitsPerPixel; |
|
|
this.bmpBitsPerPixel = bitsPerPixel; |
|
|
|
|
|
|
|
|
int rowWidth = image.Width; |
|
|
// Cast to int will get the bytes per pixel
|
|
|
|
|
|
short bpp = (short)(8 * (int)bitsPerPixel); |
|
|
// TODO: Check this for varying file formats.
|
|
|
int bytesPerLine = 4 * ((image.Width * bpp + 31) / 32); |
|
|
int amount = (image.Width * (int)this.bmpBitsPerPixel) % 4; |
|
|
this.padding = bytesPerLine - (image.Width * (int)bitsPerPixel); |
|
|
if (amount != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
rowWidth += 4 - amount; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Do not use IDisposable pattern here as we want to preserve the stream.
|
|
|
// Do not use IDisposable pattern here as we want to preserve the stream.
|
|
|
EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Little, stream); |
|
|
EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Little, stream); |
|
|
|
|
|
|
|
|
int bpp = (int)this.bmpBitsPerPixel; |
|
|
|
|
|
|
|
|
|
|
|
BmpFileHeader fileHeader = new BmpFileHeader |
|
|
|
|
|
{ |
|
|
|
|
|
Type = 19778, // BM
|
|
|
|
|
|
Offset = 54, |
|
|
|
|
|
FileSize = 54 + (image.Height * rowWidth * bpp) |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
BmpInfoHeader infoHeader = new BmpInfoHeader |
|
|
BmpInfoHeader infoHeader = new BmpInfoHeader |
|
|
{ |
|
|
{ |
|
|
HeaderSize = 40, |
|
|
HeaderSize = BmpInfoHeader.Size, |
|
|
Height = image.Height, |
|
|
Height = image.Height, |
|
|
Width = image.Width, |
|
|
Width = image.Width, |
|
|
BitsPerPixel = (short)(8 * bpp), |
|
|
BitsPerPixel = bpp, |
|
|
Planes = 1, |
|
|
Planes = 1, |
|
|
ImageSize = image.Height * rowWidth * bpp, |
|
|
ImageSize = image.Height * bytesPerLine, |
|
|
ClrUsed = 0, |
|
|
ClrUsed = 0, |
|
|
ClrImportant = 0 |
|
|
ClrImportant = 0 |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
BmpFileHeader fileHeader = new BmpFileHeader |
|
|
|
|
|
{ |
|
|
|
|
|
Type = 19778, // BM
|
|
|
|
|
|
Offset = 54, |
|
|
|
|
|
FileSize = 54 + infoHeader.ImageSize |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
WriteHeader(writer, fileHeader); |
|
|
WriteHeader(writer, fileHeader); |
|
|
this.WriteInfo(writer, infoHeader); |
|
|
this.WriteInfo(writer, infoHeader); |
|
|
this.WriteImage(writer, image); |
|
|
this.WriteImage(writer, image); |
|
|
@ -132,23 +131,16 @@ namespace ImageProcessorCore.Formats |
|
|
where T : IPackedVector<TP> |
|
|
where T : IPackedVector<TP> |
|
|
where TP : struct |
|
|
where TP : struct |
|
|
{ |
|
|
{ |
|
|
// TODO: Add more compression formats.
|
|
|
|
|
|
int amount = (image.Width * (int)this.bmpBitsPerPixel) % 4; |
|
|
|
|
|
if (amount != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
amount = 4 - amount; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
using (IPixelAccessor<T, TP> pixels = image.Lock()) |
|
|
using (IPixelAccessor<T, TP> pixels = image.Lock()) |
|
|
{ |
|
|
{ |
|
|
switch (this.bmpBitsPerPixel) |
|
|
switch (bmpBitsPerPixel) |
|
|
{ |
|
|
{ |
|
|
case BmpBitsPerPixel.Pixel32: |
|
|
case BmpBitsPerPixel.Pixel32: |
|
|
this.Write32bit(writer, pixels, amount); |
|
|
this.Write32bit(writer, pixels); |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case BmpBitsPerPixel.Pixel24: |
|
|
case BmpBitsPerPixel.Pixel24: |
|
|
this.Write24bit(writer, pixels, amount); |
|
|
this.Write24bit(writer, pixels); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
@ -161,8 +153,7 @@ namespace ImageProcessorCore.Formats |
|
|
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|
|
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
|
|
|
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|
|
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|
|
/// <param name="pixels">The <see cref="IPixelAccessor"/> containing pixel data.</param>
|
|
|
/// <param name="pixels">The <see cref="IPixelAccessor"/> containing pixel data.</param>
|
|
|
/// <param name="amount">The amount to pad each row by.</param>
|
|
|
private void Write32bit<T, TP>(EndianBinaryWriter writer, IPixelAccessor<T, TP> pixels) |
|
|
private void Write32bit<T, TP>(EndianBinaryWriter writer, IPixelAccessor<T, TP> pixels, int amount) |
|
|
|
|
|
where T : IPackedVector<TP> |
|
|
where T : IPackedVector<TP> |
|
|
where TP : struct |
|
|
where TP : struct |
|
|
{ |
|
|
{ |
|
|
@ -176,7 +167,7 @@ namespace ImageProcessorCore.Formats |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Pad
|
|
|
// Pad
|
|
|
for (int i = 0; i < amount; i++) |
|
|
for (int i = 0; i < this.padding; i++) |
|
|
{ |
|
|
{ |
|
|
writer.Write((byte)0); |
|
|
writer.Write((byte)0); |
|
|
} |
|
|
} |
|
|
@ -189,8 +180,7 @@ namespace ImageProcessorCore.Formats |
|
|
/// <typeparam name="T">The pixel format.</typeparam>
|
|
|
/// <typeparam name="T">The pixel format.</typeparam>
|
|
|
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|
|
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
|
|
|
/// <param name="pixels">The <see cref="IPixelAccessor"/> containing pixel data.</param>
|
|
|
/// <param name="pixels">The <see cref="IPixelAccessor"/> containing pixel data.</param>
|
|
|
/// <param name="amount">The amount to pad each row by.</param>
|
|
|
private void Write24bit<T, TP>(EndianBinaryWriter writer, IPixelAccessor<T, TP> pixels) |
|
|
private void Write24bit<T, TP>(EndianBinaryWriter writer, IPixelAccessor<T, TP> pixels, int amount) |
|
|
|
|
|
where T : IPackedVector<TP> |
|
|
where T : IPackedVector<TP> |
|
|
where TP : struct |
|
|
where TP : struct |
|
|
{ |
|
|
{ |
|
|
@ -204,7 +194,7 @@ namespace ImageProcessorCore.Formats |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Pad
|
|
|
// Pad
|
|
|
for (int i = 0; i < amount; i++) |
|
|
for (int i = 0; i < this.padding; i++) |
|
|
{ |
|
|
{ |
|
|
writer.Write((byte)0); |
|
|
writer.Write((byte)0); |
|
|
} |
|
|
} |
|
|
|