// -------------------------------------------------------------------------------------------------------------------- // // Copyright © James South and contributors. // Licensed under the Apache License, Version 2.0. // // // Image encoder for writing an image to a stream as a Windows bitmap. // // -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Formats { using System; using System.IO; /// /// Image encoder for writing an image to a stream as a Windows bitmap. /// /// The encoder can currently only write 24-bit rgb images to streams. public class BmpEncoder : IImageEncoder { /// /// Gets or sets the quality of output for images. /// /// Png is a lossless format so this is not used in this encoder. public int Quality { get; set; } /// /// Gets the default file extension for this encoder. /// public string Extension { get { return "BMP"; } } /// /// Returns a value indicating whether the supports the specified /// file header. /// /// The containing the file extension. /// /// True if the decoder supports the file extension; otherwise, false. /// public bool IsSupportedFileExtension(string extension) { Guard.NotNullOrEmpty(extension, "extension"); extension = extension.StartsWith(".") ? extension.Substring(1) : extension; return extension.Equals("BMP", StringComparison.OrdinalIgnoreCase) || extension.Equals("DIP", StringComparison.OrdinalIgnoreCase); } /// /// Encodes the image to the specified stream from the . /// /// The to encode from. /// The to encode the image data to. public void Encode(ImageBase image, Stream stream) { Guard.NotNull(image, "image"); Guard.NotNull(stream, "stream"); int rowWidth = image.Width; int amount = (image.Width * 3) % 4; if (amount != 0) { rowWidth += 4 - amount; } BinaryWriter writer = new BinaryWriter(stream); BmpFileHeader fileHeader = new BmpFileHeader { Type = 19778, Offset = 54, FileSize = 54 + (image.Height * rowWidth * 3) }; WriteHeader(writer, fileHeader); BmpInfoHeader infoHeader = new BmpInfoHeader { HeaderSize = 40, Height = image.Height, Width = image.Width, BitsPerPixel = 24, Planes = 1, Compression = BmpCompression.RGB, ImageSize = image.Height * rowWidth * 3, ClrUsed = 0, ClrImportant = 0 }; WriteInfo(writer, infoHeader); WriteImage(writer, image); writer.Flush(); } /// /// Writes the pixel data to the binary stream. /// /// /// The containing the stream to write to. /// /// /// The containing pixel data. /// private static void WriteImage(BinaryWriter writer, ImageBase image) { int amount = (image.Width * 3) % 4; if (amount != 0) { amount = 4 - amount; } byte[] data = image.Pixels; for (int y = image.Height - 1; y >= 0; y--) { for (int x = 0; x < image.Width; x++) { int offset = ((y * image.Width) + x) * 4; writer.Write(data[offset + 0]); writer.Write(data[offset + 1]); writer.Write(data[offset + 2]); } for (int i = 0; i < amount; i++) { writer.Write((byte)0); } } } /// /// Writes the bitmap header data to the binary stream. /// /// /// The containing the stream to write to. /// /// /// The containing the header data. /// private static void WriteHeader(BinaryWriter writer, BmpFileHeader fileHeader) { writer.Write(fileHeader.Type); writer.Write(fileHeader.FileSize); writer.Write(fileHeader.Reserved); writer.Write(fileHeader.Offset); } /// /// Writes the bitmap information to the binary stream. /// /// /// The containing the stream to write to. /// /// /// The containing the detailed information about the image. /// private static void WriteInfo(BinaryWriter writer, BmpInfoHeader infoHeader) { writer.Write(infoHeader.HeaderSize); writer.Write(infoHeader.Width); writer.Write(infoHeader.Height); writer.Write(infoHeader.Planes); writer.Write(infoHeader.BitsPerPixel); writer.Write((int)infoHeader.Compression); writer.Write(infoHeader.ImageSize); writer.Write(infoHeader.XPelsPerMeter); writer.Write(infoHeader.YPelsPerMeter); writer.Write(infoHeader.ClrUsed); writer.Write(infoHeader.ClrImportant); } } }