diff --git a/src/ImageProcessor/Formats/Bmp/BmpCompression.cs b/src/ImageProcessor/Formats/Bmp/BmpCompression.cs
new file mode 100644
index 000000000..2db5e7534
--- /dev/null
+++ b/src/ImageProcessor/Formats/Bmp/BmpCompression.cs
@@ -0,0 +1,69 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// Defines how the compression type of the image data
+// in the bitmap file.
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Formats
+{
+ ///
+ /// Defines how the compression type of the image data
+ /// in the bitmap file.
+ ///
+ internal enum BmpCompression
+ {
+ ///
+ /// Each image row has a multiple of four elements. If the
+ /// row has less elements, zeros will be added at the right side.
+ /// The format depends on the number of bits, stored in the info header.
+ /// If the number of bits are one, four or eight each pixel data is
+ /// a index to the palette. If the number of bits are sixteen,
+ /// twenty-four or thirty-two each pixel contains a color.
+ ///
+ RGB = 0,
+
+ ///
+ /// Two bytes are one data record. If the first byte is not zero, the
+ /// next two half bytes will be repeated as much as the value of the first byte.
+ /// If the first byte is zero, the record has different meanings, depending
+ /// on the second byte. If the second byte is zero, it is the end of the row,
+ /// if it is one, it is the end of the image.
+ /// Not supported at the moment.
+ ///
+ RLE8 = 1,
+
+ ///
+ /// Two bytes are one data record. If the first byte is not zero, the
+ /// next byte will be repeated as much as the value of the first byte.
+ /// If the first byte is zero, the record has different meanings, depending
+ /// on the second byte. If the second byte is zero, it is the end of the row,
+ /// if it is one, it is the end of the image.
+ /// Not supported at the moment.
+ ///
+ RLE4 = 2,
+
+ ///
+ /// Each image row has a multiple of four elements. If the
+ /// row has less elements, zeros will be added at the right side.
+ /// Not supported at the moment.
+ ///
+ BitFields = 3,
+
+ ///
+ /// The bitmap contains a JPG image.
+ /// Not supported at the moment.
+ ///
+ JPEG = 4,
+
+ ///
+ /// The bitmap contains a PNG image.
+ /// Not supported at the moment.
+ ///
+ PNG = 5
+ }
+}
diff --git a/src/ImageProcessor/Formats/Bmp/BmpDecoder.cs b/src/ImageProcessor/Formats/Bmp/BmpDecoder.cs
new file mode 100644
index 000000000..01f5ba5c3
--- /dev/null
+++ b/src/ImageProcessor/Formats/Bmp/BmpDecoder.cs
@@ -0,0 +1,94 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// Image decoder for generating an image out of a Windows bitmap stream.
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Formats
+{
+ using System;
+ using System.IO;
+
+ ///
+ /// Image decoder for generating an image out of a Windows bitmap stream.
+ ///
+ ///
+ /// Does not support the following formats at the moment:
+ ///
+ /// - JPG
+ /// - PNG
+ /// - RLE4
+ /// - RLE8
+ /// - BitFields
+ ///
+ /// Formats will be supported in a later releases. We advise always
+ /// to use only 24 Bit Windows bitmaps.
+ ///
+ public class BmpDecoder : IImageDecoder
+ {
+ ///
+ /// Gets the size of the header for this image type.
+ ///
+ /// The size of the header.
+ public int HeaderSize
+ {
+ get
+ {
+ return 2;
+ }
+ }
+
+ ///
+ /// 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);
+ }
+
+ ///
+ /// Returns a value indicating whether the supports the specified
+ /// file header.
+ ///
+ /// The containing the file header.
+ ///
+ /// True if the decoder supports the file header; otherwise, false.
+ ///
+ public bool IsSupportedFileFormat(byte[] header)
+ {
+ bool isBmp = false;
+ if (header.Length >= 2)
+ {
+ isBmp =
+ header[0] == 0x42 && // B
+ header[1] == 0x4D; // M
+ }
+
+ return isBmp;
+ }
+
+ ///
+ /// Decodes the image from the specified stream to the .
+ ///
+ /// The to decode to.
+ /// The containing image data.
+ public void Decode(Image image, Stream stream)
+ {
+ new BmpDecoderCore().Decode(image, stream);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs b/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs
new file mode 100644
index 000000000..4e45c92e8
--- /dev/null
+++ b/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs
@@ -0,0 +1,422 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// Performs the bmp decoding operation.
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Formats
+{
+ using System;
+ using System.IO;
+
+ ///
+ /// Performs the bmp decoding operation.
+ ///
+ internal class BmpDecoderCore
+ {
+ ///
+ /// The mask for the red part of the color for 16 bit rgb bitmaps.
+ ///
+ private const int Rgb16RMask = 0x00007C00;
+
+ ///
+ /// The mask for the green part of the color for 16 bit rgb bitmaps.
+ ///
+ private const int Rgb16GMask = 0x000003E0;
+
+ ///
+ /// The mask for the blue part of the color for 16 bit rgb bitmaps.
+ ///
+ private const int Rgb16BMask = 0x0000001F;
+
+ #region Fields
+
+ ///
+ /// The stream to decode from.
+ ///
+ private Stream currentStream;
+
+ ///
+ /// The file header containing general information.
+ /// TODO: Why is this not used? We advance the stream but do not use the values parsed.
+ ///
+ private BmpFileHeader fileHeader;
+
+ ///
+ /// The info header containing detailed information about the bitmap.
+ ///
+ private BmpInfoHeader infoHeader;
+
+ #endregion
+
+ #region IImageDecoder Members
+
+ ///
+ /// Decodes the image from the specified this._stream and sets
+ /// the data to image.
+ ///
+ /// The image, where the data should be set to.
+ /// Cannot be null (Nothing in Visual Basic).
+ /// The this._stream, where the image should be
+ /// decoded from. Cannot be null (Nothing in Visual Basic).
+ ///
+ /// is null.
+ /// - or -
+ /// is null.
+ ///
+ public void Decode(Image image, Stream stream)
+ {
+ this.currentStream = stream;
+
+ try
+ {
+ this.ReadFileHeader();
+ this.ReadInfoHeader();
+
+ int colorMapSize = -1;
+
+ if (this.infoHeader.ClrUsed == 0)
+ {
+ if (this.infoHeader.BitsPerPixel == 1 ||
+ this.infoHeader.BitsPerPixel == 4 ||
+ this.infoHeader.BitsPerPixel == 8)
+ {
+ colorMapSize = (int)Math.Pow(2, this.infoHeader.BitsPerPixel) * 4;
+ }
+ }
+ else
+ {
+ colorMapSize = this.infoHeader.ClrUsed * 4;
+ }
+
+ byte[] palette = null;
+
+ if (colorMapSize > 0)
+ {
+ if (colorMapSize > 255 * 4)
+ {
+ throw new ImageFormatException(
+ string.Format("Invalid bmp colormap size '{0}'", colorMapSize));
+ }
+
+ palette = new byte[colorMapSize];
+
+ this.currentStream.Read(palette, 0, colorMapSize);
+ }
+
+ if (this.infoHeader.Width > ImageBase.MaxWidth || this.infoHeader.Height > ImageBase.MaxHeight)
+ {
+ throw new ArgumentOutOfRangeException(
+ string.Format(
+ "The input bitmap '{0}x{1}' is bigger then the max allowed size '{2}x{3}'",
+ this.infoHeader.Width,
+ this.infoHeader.Height,
+ ImageBase.MaxWidth,
+ ImageBase.MaxHeight));
+ }
+
+ byte[] imageData = new byte[this.infoHeader.Width * this.infoHeader.Height * 4];
+
+ switch (this.infoHeader.Compression)
+ {
+ case BmpCompression.RGB:
+ if (this.infoHeader.HeaderSize != 40)
+ {
+ throw new ImageFormatException(
+ string.Format("Header Size value '{0}' is not valid.", this.infoHeader.HeaderSize));
+ }
+
+ if (this.infoHeader.BitsPerPixel == 32)
+ {
+ this.ReadRgb32(imageData, this.infoHeader.Width, this.infoHeader.Height);
+ }
+ else if (this.infoHeader.BitsPerPixel == 24)
+ {
+ this.ReadRgb24(imageData, this.infoHeader.Width, this.infoHeader.Height);
+ }
+ else if (this.infoHeader.BitsPerPixel == 16)
+ {
+ this.ReadRgb16(imageData, this.infoHeader.Width, this.infoHeader.Height);
+ }
+ else if (this.infoHeader.BitsPerPixel <= 8)
+ {
+ this.ReadRgbPalette(imageData, palette,
+ this.infoHeader.Width,
+ this.infoHeader.Height,
+ this.infoHeader.BitsPerPixel);
+ }
+
+ break;
+ default:
+ throw new NotSupportedException("Does not support this kind of bitmap files.");
+ }
+
+ image.SetPixels(this.infoHeader.Width, this.infoHeader.Height, imageData);
+ }
+ catch (IndexOutOfRangeException e)
+ {
+ throw new ImageFormatException("Bitmap does not have a valid format.", e);
+ }
+ }
+
+ ///
+ /// Returns the y- value based on the given height.
+ ///
+ /// The y- value representing the current row.
+ /// The height of the bitmap.
+ /// The representing the inverted value.
+ private static int Invert(int y, int height)
+ {
+ int row;
+
+ if (height > 0)
+ {
+ row = height - y - 1;
+ }
+ else
+ {
+ row = y;
+ }
+
+ return row;
+ }
+
+ ///
+ /// Reads the color palette from the stream.
+ ///
+ /// The image data to assign the palette to.
+ /// The containing the colors.
+ /// The width of the bitmap.
+ /// The height of the bitmap.
+ /// The number of bits per pixel.
+ private void ReadRgbPalette(byte[] imageData, byte[] colors, int width, int height, int bits)
+ {
+ // Pixels per byte (bits per pixel)
+ int ppb = 8 / bits;
+
+ int arrayWidth = (width + ppb - 1) / ppb;
+
+ // Bit mask
+ int mask = 0xFF >> (8 - bits);
+
+ byte[] data = new byte[(arrayWidth * height)];
+
+ this.currentStream.Read(data, 0, data.Length);
+
+ // Rows are aligned on 4 byte boundaries
+ int alignment = arrayWidth % 4;
+ if (alignment != 0)
+ {
+ alignment = 4 - alignment;
+ }
+
+ for (int y = 0; y < height; y++)
+ {
+ int rowOffset = y * (arrayWidth + alignment);
+
+ for (int x = 0; x < arrayWidth; x++)
+ {
+ int offset = rowOffset + x;
+
+ // Revert the y value, because bitmaps are saved from down to top
+ int row = Invert(y, height);
+
+ int colOffset = x * ppb;
+
+ for (int shift = 0; shift < ppb && (colOffset + shift) < width; shift++)
+ {
+ int colorIndex = (data[offset] >> (8 - bits - (shift * bits))) & mask;
+
+ int arrayOffset = ((row * width) + (colOffset + shift)) * 4;
+ imageData[arrayOffset + 0] = colors[colorIndex * 4];
+ imageData[arrayOffset + 1] = colors[(colorIndex * 4) + 1];
+ imageData[arrayOffset + 2] = colors[(colorIndex * 4) + 2];
+ imageData[arrayOffset + 3] = 255;
+ }
+ }
+ }
+ }
+
+ ///
+ /// Reads the 16 bit color palette from the stream
+ ///
+ /// The image data to assign the palette to.
+ /// The width of the bitmap.
+ /// The height of the bitmap.
+ private void ReadRgb16(byte[] imageData, int width, int height)
+ {
+ const int ScaleR = 256 / 32;
+ const int ScaleG = 256 / 64;
+
+ int alignment;
+ byte[] data = this.GetImageArray(width, height, 2, out alignment);
+
+ for (int y = 0; y < height; y++)
+ {
+ int rowOffset = y * ((width * 2) + alignment);
+
+ // Revert the y value, because bitmaps are saved from down to top
+ int row = Invert(y, height);
+
+ for (int x = 0; x < width; x++)
+ {
+ int offset = rowOffset + (x * 2);
+
+ short temp = BitConverter.ToInt16(data, offset);
+
+ byte r = (byte)(((temp & Rgb16RMask) >> 11) * ScaleR);
+ byte g = (byte)(((temp & Rgb16GMask) >> 5) * ScaleG);
+ byte b = (byte)((temp & Rgb16BMask) * ScaleR);
+
+ int arrayOffset = ((row * width) + x) * 4;
+
+ imageData[arrayOffset + 0] = b;
+ imageData[arrayOffset + 1] = g;
+ imageData[arrayOffset + 2] = r;
+ imageData[arrayOffset + 3] = 255;
+ }
+ }
+ }
+
+ ///
+ /// Reads the 24 bit color palette from the stream
+ ///
+ /// The image data to assign the palette to.
+ /// The width of the bitmap.
+ /// The height of the bitmap.
+ private void ReadRgb24(byte[] imageData, int width, int height)
+ {
+ int alignment;
+ byte[] data = this.GetImageArray(width, height, 3, out alignment);
+
+ for (int y = 0; y < height; y++)
+ {
+ int rowOffset = y * ((width * 3) + alignment);
+
+ // Revert the y value, because bitmaps are saved from down to top
+ int row = Invert(y, height);
+
+ for (int x = 0; x < width; x++)
+ {
+ int offset = rowOffset + (x * 3);
+ int arrayOffset = ((row * width) + x) * 4;
+
+ imageData[arrayOffset + 0] = data[offset + 0];
+ imageData[arrayOffset + 1] = data[offset + 1];
+ imageData[arrayOffset + 2] = data[offset + 2];
+ imageData[arrayOffset + 3] = 255;
+ }
+ }
+ }
+
+ ///
+ /// Reads the 32 bit color palette from the stream
+ ///
+ /// The image data to assign the palette to.
+ /// The width of the bitmap.
+ /// The height of the bitmap.
+ private void ReadRgb32(byte[] imageData, int width, int height)
+ {
+ int alignment;
+ byte[] data = this.GetImageArray(width, height, 4, out alignment);
+
+ for (int y = 0; y < height; y++)
+ {
+ int rowOffset = y * ((width * 4) + alignment);
+
+ // Revert the y value, because bitmaps are saved from down to top
+ int row = Invert(y, height);
+
+ for (int x = 0; x < width; x++)
+ {
+ int offset = rowOffset + (x * 4);
+
+ var arrayOffset = ((row * width) + x) * 4;
+ imageData[arrayOffset + 0] = data[offset + 0];
+ imageData[arrayOffset + 1] = data[offset + 1];
+ imageData[arrayOffset + 2] = data[offset + 2];
+ imageData[arrayOffset + 3] = 255; // Can we get alpha here?
+ }
+ }
+ }
+
+ ///
+ /// Returns a containing the pixels for the current bitmap.
+ ///
+ /// The width of the bitmap.
+ /// The height.
+ /// The number of bytes per pixel.
+ /// The alignment of the pixels.
+ ///
+ /// The containing the pixels.
+ ///
+ private byte[] GetImageArray(int width, int height, int bytes, out int alignment)
+ {
+ int dataWidth = width;
+
+ alignment = (width * bytes) % 4;
+
+ if (alignment != 0)
+ {
+ alignment = 4 - alignment;
+ }
+
+ int size = ((dataWidth * bytes) + alignment) * height;
+
+ byte[] data = new byte[size];
+
+ this.currentStream.Read(data, 0, size);
+
+ return data;
+ }
+
+ ///
+ /// Reads the from the stream.
+ ///
+ private void ReadInfoHeader()
+ {
+ byte[] data = new byte[BmpInfoHeader.Size];
+
+ this.currentStream.Read(data, 0, BmpInfoHeader.Size);
+
+ this.infoHeader = new BmpInfoHeader
+ {
+ HeaderSize = BitConverter.ToInt32(data, 0),
+ Width = BitConverter.ToInt32(data, 4),
+ Height = BitConverter.ToInt32(data, 8),
+ Planes = BitConverter.ToInt16(data, 12),
+ BitsPerPixel = BitConverter.ToInt16(data, 14),
+ ImageSize = BitConverter.ToInt32(data, 20),
+ XPelsPerMeter = BitConverter.ToInt32(data, 24),
+ YPelsPerMeter = BitConverter.ToInt32(data, 28),
+ ClrUsed = BitConverter.ToInt32(data, 32),
+ ClrImportant = BitConverter.ToInt32(data, 36),
+ Compression = (BmpCompression)BitConverter.ToInt32(data, 16)
+ };
+ }
+
+ ///
+ /// Reads the from the stream.
+ ///
+ private void ReadFileHeader()
+ {
+ byte[] data = new byte[BmpFileHeader.Size];
+
+ this.currentStream.Read(data, 0, BmpFileHeader.Size);
+
+ this.fileHeader = new BmpFileHeader
+ {
+ Type = BitConverter.ToInt16(data, 0),
+ FileSize = BitConverter.ToInt32(data, 2),
+ Reserved = BitConverter.ToInt32(data, 6),
+ Offset = BitConverter.ToInt32(data, 10)
+ };
+ }
+
+ #endregion
+ }
+}
diff --git a/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs b/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs
new file mode 100644
index 000000000..4c2f77cfd
--- /dev/null
+++ b/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs
@@ -0,0 +1,180 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// 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);
+ }
+ }
+}
diff --git a/src/ImageProcessor/Formats/Bmp/BmpFileHeader.cs b/src/ImageProcessor/Formats/Bmp/BmpFileHeader.cs
new file mode 100644
index 000000000..f6a525da2
--- /dev/null
+++ b/src/ImageProcessor/Formats/Bmp/BmpFileHeader.cs
@@ -0,0 +1,55 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// Stores general information about the Bitmap file.
+//
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Formats
+{
+ ///
+ /// Stores general information about the Bitmap file.
+ ///
+ ///
+ ///
+ /// The first two bytes of the Bitmap file format
+ /// (thus the Bitmap header) are stored in big-endian order.
+ /// All of the other integer values are stored in little-endian format
+ /// (i.e. least-significant byte first).
+ ///
+ internal class BmpFileHeader
+ {
+ ///
+ /// Defines of the data structure in the bitmap file.
+ ///
+ public const int Size = 14;
+
+ ///
+ /// Gets or sets the Bitmap identifier.
+ /// The field used to identify the bitmap file: 0x42 0x4D
+ /// (Hex code points for B and M)
+ ///
+ public short Type { get; set; }
+
+ ///
+ /// Gets or sets the size of the bitmap file in bytes.
+ ///
+ public int FileSize { get; set; }
+
+ ///
+ /// Gets or sets any reserved data; actual value depends on the application
+ /// that creates the image.
+ ///
+ public int Reserved { get; set; }
+
+ ///
+ /// Gets or sets the offset, i.e. starting address, of the byte where
+ /// the bitmap data can be found.
+ ///
+ public int Offset { get; set; }
+ }
+}
diff --git a/src/ImageProcessor/Formats/Bmp/BmpInfoHeader.cs b/src/ImageProcessor/Formats/Bmp/BmpInfoHeader.cs
new file mode 100644
index 000000000..22886bf9b
--- /dev/null
+++ b/src/ImageProcessor/Formats/Bmp/BmpInfoHeader.cs
@@ -0,0 +1,91 @@
+// --------------------------------------------------------------------------------------------------------------------
+//
+// Copyright © James South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+//
+// This block of bytes tells the application detailed information
+// about the image, which will be used to display the image on
+// the screen.
+//
+//
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace ImageProcessor.Formats
+{
+ ///
+ /// This block of bytes tells the application detailed information
+ /// about the image, which will be used to display the image on
+ /// the screen.
+ ///
+ ///
+ internal class BmpInfoHeader
+ {
+ ///
+ /// Defines of the data structure in the bitmap file.
+ ///
+ public const int Size = 40;
+
+ ///
+ /// Gets or sets the size of this header (40 bytes)
+ ///
+ public int HeaderSize { get; set; }
+
+ ///
+ /// Gets or sets the bitmap width in pixels (signed integer).
+ ///
+ public int Width { get; set; }
+
+ ///
+ /// Gets or sets the bitmap height in pixels (signed integer).
+ ///
+ public int Height { get; set; }
+
+ ///
+ /// Gets or sets the number of color planes being used. Must be set to 1.
+ ///
+ public short Planes { get; set; }
+
+ ///
+ /// Gets or sets the number of bits per pixel, which is the color depth of the image.
+ /// Typical values are 1, 4, 8, 16, 24 and 32.
+ ///
+ public short BitsPerPixel { get; set; }
+
+ ///
+ /// Gets or sets the compression method being used.
+ /// See the next table for a list of possible values.
+ ///
+ public BmpCompression Compression { get; set; }
+
+ ///
+ /// Gets or sets the image size. This is the size of the raw bitmap data (see below),
+ /// and should not be confused with the file size.
+ ///
+ public int ImageSize { get; set; }
+
+ ///
+ /// Gets or sets the horizontal resolution of the image.
+ /// (pixel per meter, signed integer)
+ ///
+ public int XPelsPerMeter { get; set; }
+
+ ///
+ /// Gets or sets the vertical resolution of the image.
+ /// (pixel per meter, signed integer)
+ ///
+ public int YPelsPerMeter { get; set; }
+
+ ///
+ /// Gets or sets the number of colors in the color palette,
+ /// or 0 to default to 2^n.
+ ///
+ public int ClrUsed { get; set; }
+
+ ///
+ /// Gets or sets the number of important colors used,
+ /// or 0 when every color is important{ get; set; } generally ignored.
+ ///
+ public int ClrImportant { get; set; }
+ }
+}
diff --git a/src/ImageProcessor/Formats/Png/PngDecoderCore.cs b/src/ImageProcessor/Formats/Png/PngDecoderCore.cs
index c7d81cd19..3ebe49bbb 100644
--- a/src/ImageProcessor/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageProcessor/Formats/Png/PngDecoderCore.cs
@@ -14,6 +14,7 @@ namespace ImageProcessor.Formats
using System.Collections.Generic;
using System.IO;
using System.Linq;
+ using System.Text;
using ICSharpCode.SharpZipLib.Checksums;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
@@ -40,7 +41,7 @@ namespace ImageProcessor.Formats
private Image currentImage;
///
- /// The stream to decode to.
+ /// The stream to decode from.
///
private Stream currentStream;
@@ -360,8 +361,8 @@ namespace ImageProcessor.Formats
}
}
- string name = System.Text.Encoding.Unicode.GetString(data, 0, zeroIndex);
- string value = System.Text.Encoding.Unicode.GetString(data, zeroIndex + 1, data.Length - zeroIndex - 1);
+ string name = Encoding.Unicode.GetString(data, 0, zeroIndex);
+ string value = Encoding.Unicode.GetString(data, zeroIndex + 1, data.Length - zeroIndex - 1);
this.currentImage.Properties.Add(new ImageProperty(name, value));
}
diff --git a/src/ImageProcessor/Image.cs b/src/ImageProcessor/Image.cs
index 48fbffeb8..eeadc2a09 100644
--- a/src/ImageProcessor/Image.cs
+++ b/src/ImageProcessor/Image.cs
@@ -49,7 +49,7 @@ namespace ImageProcessor
private static readonly Lazy> DefaultDecoders =
new Lazy>(() => new List
{
- // new BmpDecoder(),
+ new BmpDecoder(),
// new JpegDecoder(),
new PngDecoder(),
// new GifDecoder(),
@@ -61,7 +61,7 @@ namespace ImageProcessor
private static readonly Lazy> DefaultEncoders =
new Lazy>(() => new List
{
- // new BmpEncoder(),
+ new BmpEncoder(),
// new JpegEncoder(),
new PngEncoder(),
});
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index eec1241b1..233fc5644 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -45,6 +45,12 @@
+
+
+
+
+
+
diff --git a/src/ImageProcessor/ImageProcessor.csproj.DotSettings b/src/ImageProcessor/ImageProcessor.csproj.DotSettings
index 00ba06120..cd4ba94c1 100644
--- a/src/ImageProcessor/ImageProcessor.csproj.DotSettings
+++ b/src/ImageProcessor/ImageProcessor.csproj.DotSettings
@@ -5,6 +5,7 @@
True
True
True
+ True
True
True
True
diff --git a/src/ImageProcessor/Settings.StyleCop b/src/ImageProcessor/Settings.StyleCop
index 62bf37157..0e93ffff4 100644
--- a/src/ImageProcessor/Settings.StyleCop
+++ b/src/ImageProcessor/Settings.StyleCop
@@ -5,6 +5,7 @@
cr
EX
png
+ rgb
scanline
scanlines
tEXt
diff --git a/tests/ImageProcessor.Tests/Formats/EncoderDecoderTests.cs b/tests/ImageProcessor.Tests/Formats/EncoderDecoderTests.cs
index 77bb36d0e..7cb38d1c3 100644
--- a/tests/ImageProcessor.Tests/Formats/EncoderDecoderTests.cs
+++ b/tests/ImageProcessor.Tests/Formats/EncoderDecoderTests.cs
@@ -15,6 +15,7 @@
//[InlineData("TestImages/Portrait.png")]
//[InlineData("TestImages/Backdrop.jpg")]
//[InlineData("TestImages/Windmill.gif")]
+ [InlineData("../../TestImages/Formats/Bmp/Car.bmp")]
[InlineData("../../TestImages/Formats/Png/cmyk.png")]
public void DecodeThenEncodeImageFromStreamShouldSucceed(string filename)
{
diff --git a/tests/ImageProcessor.Tests/TestImages/Formats/Bmp/Car.bmp.REMOVED.git-id b/tests/ImageProcessor.Tests/TestImages/Formats/Bmp/Car.bmp.REMOVED.git-id
new file mode 100644
index 000000000..e6132fd8c
--- /dev/null
+++ b/tests/ImageProcessor.Tests/TestImages/Formats/Bmp/Car.bmp.REMOVED.git-id
@@ -0,0 +1 @@
+edd8ac1feb2c4649e6f5aa80af8d4cf33642a546
\ No newline at end of file