From e6876199ca915aafdaa99825e102239ab40ba353 Mon Sep 17 00:00:00 2001 From: Quajak Date: Sat, 14 Apr 2018 10:03:37 +0200 Subject: [PATCH 1/3] Now supports 24bit bitmaps --- source/Cosmos.System2/Graphics/Bitmap.cs | 216 ++++++++++++----------- 1 file changed, 117 insertions(+), 99 deletions(-) diff --git a/source/Cosmos.System2/Graphics/Bitmap.cs b/source/Cosmos.System2/Graphics/Bitmap.cs index 6642c3e90..9dff82c87 100644 --- a/source/Cosmos.System2/Graphics/Bitmap.cs +++ b/source/Cosmos.System2/Graphics/Bitmap.cs @@ -50,109 +50,123 @@ namespace Cosmos.System.Graphics } } - private void CreateBitmap(Stream stream) + public Bitmap(Stream stream) : base(0, 0, ColorDepth.ColorDepth32) //Call the image constructor with wrong values { - #region BMP Header - - Byte[] _int = new byte[4]; - Byte[] _short = new byte[2]; - //Assume that we are using the BMP (Windows) header format - //I am using http://www.fastgraph.com/help/bmp_header_format.html - //and https://upload.wikimedia.org/wikipedia/commons/c/c4/BMPfileFormat.png?1519566101894as as reference - stream.Position = 10; - //read header - bytes 10 -> 14 is the offset of the bitmap image data - stream.Read(_int, 0, 4); - uint pixelTableOffset = (uint)BitConverter.ToInt32(_int, 0); - - //now reading size of BITMAPINFOHEADER should be 40 - bytes 14 -> 18 - stream.Read(_int, 0, 4); - uint infoHeaderSize = (uint)BitConverter.ToInt32(_int, 0); - if (infoHeaderSize != 40) + using (stream) { - throw new Exception("Info header size has the wrong value!"); - } - //now reading width of image in pixels - bytes 18 -> 22 - stream.Read(_int, 0, 4); - uint imageWidth = (uint)BitConverter.ToInt32(_int, 0); + #region BMP Header - //now reading height of image in pixels - byte 22 -> 26 - stream.Read(_int, 0, 4); - uint imageHeight = (uint)BitConverter.ToInt32(_int, 0); + Byte[] _int = new byte[4]; + Byte[] _short = new byte[2]; + //Assume that we are using the BMP (Windows) header format + //I am using http://www.fastgraph.com/help/bmp_header_format.html + //and https://upload.wikimedia.org/wikipedia/commons/c/c4/BMPfileFormat.png?1519566101894as as reference - //now reading number of planes should be 1 - byte 26 -> 28 - stream.Read(_short, 0, 2); - ushort planes = (ushort)BitConverter.ToInt16(_short, 0); - if (planes != 1) - { - throw new Exception("Number of planes is not 1! Can not read file!"); - } - //now reading size of bits per pixel (1, 4, 8, 24, 32) - bytes 28 - 30 - stream.Read(_short, 0, 2); - ushort pixelSize = (ushort)BitConverter.ToInt16(_short, 0); - //TODO: Be able to handle other pixel sizes - if (pixelSize != 32) - { - throw new NotImplementedException("Can only handle 32bit pictures!"); - } - //now reading compression type - bytes 30 -> 34 - stream.Read(_int, 0, 4); - uint compression = (uint)BitConverter.ToInt32(_int, 0); - //TODO: Be able to handle compressed files - if (compression != 0) - { - throw new NotImplementedException("Can only handle uncompressed files!"); - } - //now reading total image data size(including padding) - bytes 34 -> 38 - stream.Read(_int, 0, 4); - uint totalImageSize = (uint)BitConverter.ToInt32(_int, 0); - //Somehow this is 0 for my test bmp + //reading magic number to identify if BMP file (BM as string - 42 4D as Hex) - bytes 0 -> 2 + stream.Read(_short, 0, 2); + if ("42-4D" != BitConverter.ToString(_short)) + throw new Exception("Header is not from a BMP"); - #endregion BMP Header + //read size of BMP file - byte 2 -> 6 + stream.Read(_int, 0, 4); + uint fileSize = (uint)BitConverter.ToInt32(_int, 0); - //Set the bitmap to have the correct values - Width = imageWidth; - Height = imageHeight; - Depth = (ColorDepth)pixelSize; + stream.Position = 10; + //read header - bytes 10 -> 14 is the offset of the bitmap image data + stream.Read(_int, 0, 4); + uint pixelTableOffset = (uint)BitConverter.ToInt32(_int, 0); - rawData = new int[Width * Height * pixelSize / 8]; - - #region Pixel Table - - //Calculate padding - int paddingPerRow = 0; - int pureImageSize = (int)(imageWidth * imageHeight * pixelSize / 8); - if (totalImageSize != 0) - { - int remainder = (int)totalImageSize - pureImageSize; - if (remainder < 0) throw new Exception("Total Image Size is smaller than pure image size"); - paddingPerRow = remainder / (int)imageHeight; - } - else - { - //total image size is 0 if it is not compressed - paddingPerRow = 0; - } - //Read data - stream.Position = (int)pixelTableOffset; - int position = 0; - Byte[] pixelData = new byte[pureImageSize]; - stream.Read(pixelData, 0, pureImageSize); - Byte[] pixel = new byte[pixelSize / 8]; //Pixel size is in byte - - for (int x = 0; x < imageWidth; x++) - { - for (int y = 0; y < imageHeight; y++) + //now reading size of BITMAPINFOHEADER should be 40 - bytes 14 -> 18 + stream.Read(_int, 0, 4); + uint infoHeaderSize = (uint)BitConverter.ToInt32(_int, 0); + if (infoHeaderSize != 40) { - pixel[0] = pixelData[position++]; - pixel[1] = pixelData[position++]; - pixel[2] = pixelData[position++]; - pixel[3] = pixelData[position++]; - rawData[x + (imageHeight - (y + 1)) * imageWidth] = BitConverter.ToInt32(pixel, 0); + throw new Exception("Info header size has the wrong value!"); } - position += paddingPerRow; - } + //now reading width of image in pixels - bytes 18 -> 22 + stream.Read(_int, 0, 4); + uint imageWidth = (uint)BitConverter.ToInt32(_int, 0); - #endregion Pixel Table + //now reading height of image in pixels - byte 22 -> 26 + stream.Read(_int, 0, 4); + uint imageHeight = (uint)BitConverter.ToInt32(_int, 0); + + //now reading number of planes should be 1 - byte 26 -> 28 + stream.Read(_short, 0, 2); + ushort planes = (ushort)BitConverter.ToInt16(_short, 0); + if (planes != 1) + throw new Exception("Number of planes is not 1! Can not read file!"); + //now reading size of bits per pixel (1, 4, 8, 24, 32) - bytes 28 - 30 + stream.Read(_short, 0, 2); + ushort pixelSize = (ushort)BitConverter.ToInt16(_short, 0); + //TODO: Be able to handle other pixel sizes + if (!(pixelSize == 32 || pixelSize == 24)) + { + throw new NotImplementedException("Can only handle 32bit pictures!"); + } + //now reading compression type - bytes 30 -> 34 + stream.Read(_int, 0, 4); + uint compression = (uint)BitConverter.ToInt32(_int, 0); + //TODO: Be able to handle compressed files + if (compression != 0) + throw new NotImplementedException("Can only handle uncompressed files!"); + //now reading total image data size(including padding) - bytes 34 -> 38 + stream.Read(_int, 0, 4); + uint totalImageSize = (uint)BitConverter.ToInt32(_int, 0); + + #endregion BMP Header + + //Set the bitmap to have the correct values + Width = imageWidth; + Height = imageHeight; + Depth = (ColorDepth)pixelSize; + + rawData = new int[Width * Height]; + + #region Pixel Table + + //Calculate padding + int paddingPerRow = 0; + int pureImageSize = (int)(imageWidth * imageHeight * pixelSize / 8); + if (totalImageSize != 0) + { + int remainder = (int)totalImageSize - pureImageSize; + if (remainder < 0) throw new Exception("Total Image Size is smaller than pure image size"); + paddingPerRow = remainder / (int)imageHeight; + pureImageSize = (int)totalImageSize; + } + else + { + //total image size is 0 if it is not compressed + paddingPerRow = 0; + } + //Read data + stream.Position = (int)pixelTableOffset; + int position = 0; + Byte[] pixelData = new byte[pureImageSize]; + stream.Read(pixelData, 0, pureImageSize); + Byte[] pixel = new byte[4]; //All must have the same size + + for (int x = 0; x < imageWidth; x++) + { + for (int y = 0; y < imageHeight; y++) + { + if (pixelSize == 32) + pixel[0] = pixelData[position++]; + else + { + pixel[0] = 0; + } + pixel[1] = pixelData[position++]; + pixel[2] = pixelData[position++]; + pixel[3] = pixelData[position++]; + rawData[x + (imageHeight - (y + 1)) * imageWidth] = BitConverter.ToInt32(pixel, 0); + } + position += paddingPerRow; + } + + #endregion Pixel Table + } } public void Save(string path) @@ -165,8 +179,9 @@ namespace Cosmos.System.Graphics public void Save(Stream stream, ImageFormat imageFormat) { - //What should we do when a stream has already been used ie. the position is not 0? - Byte[] file = new Byte[54 /*header*/ + Width * Height * (uint)Depth / 8 /*assume that it is full bytes */]; + //Calculate padding + int padding = ((int)Width * (int)Depth / 8) % 4; + Byte[] file = new Byte[54 /*header*/ + Width * Height * (uint)Depth / 8 + padding * Height]; //Writes all bytes at the end into the stream, rather than a few every time int position = 0; @@ -241,7 +256,7 @@ namespace Cosmos.System.Graphics Array.Copy(data, 0, file, position, 0); position += 4; - //number of important colors in iamge / zero + //number of important colors in image / zero data = BitConverter.GetBytes(0); Array.Copy(data, 0, file, position, 4); position += 4; @@ -250,15 +265,18 @@ namespace Cosmos.System.Graphics //Copy image data position = (int)offset; - Byte[] imageData = new Byte[Width * Height * (int)Depth / 8]; + Byte[] imageData = new Byte[Width * Height * (int)Depth / 8 + padding * Height]; int imageDataPoint = 0; + byte[] bytePadding = new byte[padding]; + int pos = 4 - (int)Depth / 8; + int length = (int)Depth / 8; for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { data = BitConverter.GetBytes(rawData[x + (Height - (y + 1)) * Width]); - Array.Copy(data, 0, imageData, imageDataPoint, data.Length); - imageDataPoint += data.Length; + Array.Copy(data, pos, imageData, imageDataPoint, length); + imageDataPoint += length; } } Array.Copy(imageData, 0, file, position, imageData.Length); From 4905318479873534b9c6c7b80b45f8dfe5f360ad Mon Sep 17 00:00:00 2001 From: Quajak Date: Sat, 14 Apr 2018 10:03:37 +0200 Subject: [PATCH 2/3] Now supports 24bit bitmaps --- source/Cosmos.System2/Graphics/Bitmap.cs | 214 ++++++++++++----------- 1 file changed, 116 insertions(+), 98 deletions(-) diff --git a/source/Cosmos.System2/Graphics/Bitmap.cs b/source/Cosmos.System2/Graphics/Bitmap.cs index 6642c3e90..75f5cb37d 100644 --- a/source/Cosmos.System2/Graphics/Bitmap.cs +++ b/source/Cosmos.System2/Graphics/Bitmap.cs @@ -52,107 +52,121 @@ namespace Cosmos.System.Graphics private void CreateBitmap(Stream stream) { - #region BMP Header - - Byte[] _int = new byte[4]; - Byte[] _short = new byte[2]; - //Assume that we are using the BMP (Windows) header format - //I am using http://www.fastgraph.com/help/bmp_header_format.html - //and https://upload.wikimedia.org/wikipedia/commons/c/c4/BMPfileFormat.png?1519566101894as as reference - stream.Position = 10; - //read header - bytes 10 -> 14 is the offset of the bitmap image data - stream.Read(_int, 0, 4); - uint pixelTableOffset = (uint)BitConverter.ToInt32(_int, 0); - - //now reading size of BITMAPINFOHEADER should be 40 - bytes 14 -> 18 - stream.Read(_int, 0, 4); - uint infoHeaderSize = (uint)BitConverter.ToInt32(_int, 0); - if (infoHeaderSize != 40) + using (stream) { - throw new Exception("Info header size has the wrong value!"); - } - //now reading width of image in pixels - bytes 18 -> 22 - stream.Read(_int, 0, 4); - uint imageWidth = (uint)BitConverter.ToInt32(_int, 0); + #region BMP Header - //now reading height of image in pixels - byte 22 -> 26 - stream.Read(_int, 0, 4); - uint imageHeight = (uint)BitConverter.ToInt32(_int, 0); + Byte[] _int = new byte[4]; + Byte[] _short = new byte[2]; + //Assume that we are using the BMP (Windows) header format + //I am using http://www.fastgraph.com/help/bmp_header_format.html + //and https://upload.wikimedia.org/wikipedia/commons/c/c4/BMPfileFormat.png?1519566101894as as reference - //now reading number of planes should be 1 - byte 26 -> 28 - stream.Read(_short, 0, 2); - ushort planes = (ushort)BitConverter.ToInt16(_short, 0); - if (planes != 1) - { - throw new Exception("Number of planes is not 1! Can not read file!"); - } - //now reading size of bits per pixel (1, 4, 8, 24, 32) - bytes 28 - 30 - stream.Read(_short, 0, 2); - ushort pixelSize = (ushort)BitConverter.ToInt16(_short, 0); - //TODO: Be able to handle other pixel sizes - if (pixelSize != 32) - { - throw new NotImplementedException("Can only handle 32bit pictures!"); - } - //now reading compression type - bytes 30 -> 34 - stream.Read(_int, 0, 4); - uint compression = (uint)BitConverter.ToInt32(_int, 0); - //TODO: Be able to handle compressed files - if (compression != 0) - { - throw new NotImplementedException("Can only handle uncompressed files!"); - } - //now reading total image data size(including padding) - bytes 34 -> 38 - stream.Read(_int, 0, 4); - uint totalImageSize = (uint)BitConverter.ToInt32(_int, 0); - //Somehow this is 0 for my test bmp + //reading magic number to identify if BMP file (BM as string - 42 4D as Hex) - bytes 0 -> 2 + stream.Read(_short, 0, 2); + if ("42-4D" != BitConverter.ToString(_short)) + throw new Exception("Header is not from a BMP"); - #endregion BMP Header + //read size of BMP file - byte 2 -> 6 + stream.Read(_int, 0, 4); + uint fileSize = (uint)BitConverter.ToInt32(_int, 0); - //Set the bitmap to have the correct values - Width = imageWidth; - Height = imageHeight; - Depth = (ColorDepth)pixelSize; + stream.Position = 10; + //read header - bytes 10 -> 14 is the offset of the bitmap image data + stream.Read(_int, 0, 4); + uint pixelTableOffset = (uint)BitConverter.ToInt32(_int, 0); - rawData = new int[Width * Height * pixelSize / 8]; - - #region Pixel Table - - //Calculate padding - int paddingPerRow = 0; - int pureImageSize = (int)(imageWidth * imageHeight * pixelSize / 8); - if (totalImageSize != 0) - { - int remainder = (int)totalImageSize - pureImageSize; - if (remainder < 0) throw new Exception("Total Image Size is smaller than pure image size"); - paddingPerRow = remainder / (int)imageHeight; - } - else - { - //total image size is 0 if it is not compressed - paddingPerRow = 0; - } - //Read data - stream.Position = (int)pixelTableOffset; - int position = 0; - Byte[] pixelData = new byte[pureImageSize]; - stream.Read(pixelData, 0, pureImageSize); - Byte[] pixel = new byte[pixelSize / 8]; //Pixel size is in byte - - for (int x = 0; x < imageWidth; x++) - { - for (int y = 0; y < imageHeight; y++) + //now reading size of BITMAPINFOHEADER should be 40 - bytes 14 -> 18 + stream.Read(_int, 0, 4); + uint infoHeaderSize = (uint)BitConverter.ToInt32(_int, 0); + if (infoHeaderSize != 40) { - pixel[0] = pixelData[position++]; - pixel[1] = pixelData[position++]; - pixel[2] = pixelData[position++]; - pixel[3] = pixelData[position++]; - rawData[x + (imageHeight - (y + 1)) * imageWidth] = BitConverter.ToInt32(pixel, 0); + throw new Exception("Info header size has the wrong value!"); } - position += paddingPerRow; - } + //now reading width of image in pixels - bytes 18 -> 22 + stream.Read(_int, 0, 4); + uint imageWidth = (uint)BitConverter.ToInt32(_int, 0); - #endregion Pixel Table + //now reading height of image in pixels - byte 22 -> 26 + stream.Read(_int, 0, 4); + uint imageHeight = (uint)BitConverter.ToInt32(_int, 0); + + //now reading number of planes should be 1 - byte 26 -> 28 + stream.Read(_short, 0, 2); + ushort planes = (ushort)BitConverter.ToInt16(_short, 0); + if (planes != 1) + throw new Exception("Number of planes is not 1! Can not read file!"); + //now reading size of bits per pixel (1, 4, 8, 24, 32) - bytes 28 - 30 + stream.Read(_short, 0, 2); + ushort pixelSize = (ushort)BitConverter.ToInt16(_short, 0); + //TODO: Be able to handle other pixel sizes + if (!(pixelSize == 32 || pixelSize == 24)) + { + throw new NotImplementedException("Can only handle 32bit pictures!"); + } + //now reading compression type - bytes 30 -> 34 + stream.Read(_int, 0, 4); + uint compression = (uint)BitConverter.ToInt32(_int, 0); + //TODO: Be able to handle compressed files + if (compression != 0) + throw new NotImplementedException("Can only handle uncompressed files!"); + //now reading total image data size(including padding) - bytes 34 -> 38 + stream.Read(_int, 0, 4); + uint totalImageSize = (uint)BitConverter.ToInt32(_int, 0); + + #endregion BMP Header + + //Set the bitmap to have the correct values + Width = imageWidth; + Height = imageHeight; + Depth = (ColorDepth)pixelSize; + + rawData = new int[Width * Height]; + + #region Pixel Table + + //Calculate padding + int paddingPerRow = 0; + int pureImageSize = (int)(imageWidth * imageHeight * pixelSize / 8); + if (totalImageSize != 0) + { + int remainder = (int)totalImageSize - pureImageSize; + if (remainder < 0) throw new Exception("Total Image Size is smaller than pure image size"); + paddingPerRow = remainder / (int)imageHeight; + pureImageSize = (int)totalImageSize; + } + else + { + //total image size is 0 if it is not compressed + paddingPerRow = 0; + } + //Read data + stream.Position = (int)pixelTableOffset; + int position = 0; + Byte[] pixelData = new byte[pureImageSize]; + stream.Read(pixelData, 0, pureImageSize); + Byte[] pixel = new byte[4]; //All must have the same size + + for (int x = 0; x < imageWidth; x++) + { + for (int y = 0; y < imageHeight; y++) + { + if (pixelSize == 32) + pixel[0] = pixelData[position++]; + else + { + pixel[0] = 0; + } + pixel[1] = pixelData[position++]; + pixel[2] = pixelData[position++]; + pixel[3] = pixelData[position++]; + rawData[x + (imageHeight - (y + 1)) * imageWidth] = BitConverter.ToInt32(pixel, 0); + } + position += paddingPerRow; + } + + #endregion Pixel Table + } } public void Save(string path) @@ -165,8 +179,9 @@ namespace Cosmos.System.Graphics public void Save(Stream stream, ImageFormat imageFormat) { - //What should we do when a stream has already been used ie. the position is not 0? - Byte[] file = new Byte[54 /*header*/ + Width * Height * (uint)Depth / 8 /*assume that it is full bytes */]; + //Calculate padding + int padding = ((int)Width * (int)Depth / 8) % 4; + Byte[] file = new Byte[54 /*header*/ + Width * Height * (uint)Depth / 8 + padding * Height]; //Writes all bytes at the end into the stream, rather than a few every time int position = 0; @@ -241,7 +256,7 @@ namespace Cosmos.System.Graphics Array.Copy(data, 0, file, position, 0); position += 4; - //number of important colors in iamge / zero + //number of important colors in image / zero data = BitConverter.GetBytes(0); Array.Copy(data, 0, file, position, 4); position += 4; @@ -250,15 +265,18 @@ namespace Cosmos.System.Graphics //Copy image data position = (int)offset; - Byte[] imageData = new Byte[Width * Height * (int)Depth / 8]; + Byte[] imageData = new Byte[Width * Height * (int)Depth / 8 + padding * Height]; int imageDataPoint = 0; + byte[] bytePadding = new byte[padding]; + int pos = 4 - (int)Depth / 8; + int length = (int)Depth / 8; for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { data = BitConverter.GetBytes(rawData[x + (Height - (y + 1)) * Width]); - Array.Copy(data, 0, imageData, imageDataPoint, data.Length); - imageDataPoint += data.Length; + Array.Copy(data, pos, imageData, imageDataPoint, length); + imageDataPoint += length; } } Array.Copy(imageData, 0, file, position, imageData.Length); From be01d41a36d13b280bb9e90d9e3b99e45b738147 Mon Sep 17 00:00:00 2001 From: Quajak Date: Wed, 18 Apr 2018 17:29:00 +0200 Subject: [PATCH 3/3] Fixed requested changes --- source/Cosmos.System2/Graphics/Bitmap.cs | 221 +++++++++++------------ 1 file changed, 108 insertions(+), 113 deletions(-) diff --git a/source/Cosmos.System2/Graphics/Bitmap.cs b/source/Cosmos.System2/Graphics/Bitmap.cs index 75f5cb37d..e79594a03 100644 --- a/source/Cosmos.System2/Graphics/Bitmap.cs +++ b/source/Cosmos.System2/Graphics/Bitmap.cs @@ -52,121 +52,116 @@ namespace Cosmos.System.Graphics private void CreateBitmap(Stream stream) { - using (stream) + #region BMP Header + + Byte[] _int = new byte[4]; + Byte[] _short = new byte[2]; + //Assume that we are using the BMP (Windows) V3 header format + + //reading magic number to identify if BMP file (BM as string - 42 4D as Hex) - bytes 0 -> 2 + stream.Read(_short, 0, 2); + if (0x424d != BitConverter.ToInt16(_short, 0)) + throw new Exception("Header is not from a BMP"); + + //read size of BMP file - byte 2 -> 6 + stream.Read(_int, 0, 4); + uint fileSize = (uint)BitConverter.ToInt32(_int, 0); + + stream.Position = 10; + //read header - bytes 10 -> 14 is the offset of the bitmap image data + stream.Read(_int, 0, 4); + uint pixelTableOffset = (uint)BitConverter.ToInt32(_int, 0); + + //now reading size of BITMAPINFOHEADER should be 40 - bytes 14 -> 18 + stream.Read(_int, 0, 4); + uint infoHeaderSize = (uint)BitConverter.ToInt32(_int, 0); + if (infoHeaderSize != 40) { - #region BMP Header - - Byte[] _int = new byte[4]; - Byte[] _short = new byte[2]; - //Assume that we are using the BMP (Windows) header format - //I am using http://www.fastgraph.com/help/bmp_header_format.html - //and https://upload.wikimedia.org/wikipedia/commons/c/c4/BMPfileFormat.png?1519566101894as as reference - - //reading magic number to identify if BMP file (BM as string - 42 4D as Hex) - bytes 0 -> 2 - stream.Read(_short, 0, 2); - if ("42-4D" != BitConverter.ToString(_short)) - throw new Exception("Header is not from a BMP"); - - //read size of BMP file - byte 2 -> 6 - stream.Read(_int, 0, 4); - uint fileSize = (uint)BitConverter.ToInt32(_int, 0); - - stream.Position = 10; - //read header - bytes 10 -> 14 is the offset of the bitmap image data - stream.Read(_int, 0, 4); - uint pixelTableOffset = (uint)BitConverter.ToInt32(_int, 0); - - //now reading size of BITMAPINFOHEADER should be 40 - bytes 14 -> 18 - stream.Read(_int, 0, 4); - uint infoHeaderSize = (uint)BitConverter.ToInt32(_int, 0); - if (infoHeaderSize != 40) - { - throw new Exception("Info header size has the wrong value!"); - } - //now reading width of image in pixels - bytes 18 -> 22 - stream.Read(_int, 0, 4); - uint imageWidth = (uint)BitConverter.ToInt32(_int, 0); - - //now reading height of image in pixels - byte 22 -> 26 - stream.Read(_int, 0, 4); - uint imageHeight = (uint)BitConverter.ToInt32(_int, 0); - - //now reading number of planes should be 1 - byte 26 -> 28 - stream.Read(_short, 0, 2); - ushort planes = (ushort)BitConverter.ToInt16(_short, 0); - if (planes != 1) - throw new Exception("Number of planes is not 1! Can not read file!"); - //now reading size of bits per pixel (1, 4, 8, 24, 32) - bytes 28 - 30 - stream.Read(_short, 0, 2); - ushort pixelSize = (ushort)BitConverter.ToInt16(_short, 0); - //TODO: Be able to handle other pixel sizes - if (!(pixelSize == 32 || pixelSize == 24)) - { - throw new NotImplementedException("Can only handle 32bit pictures!"); - } - //now reading compression type - bytes 30 -> 34 - stream.Read(_int, 0, 4); - uint compression = (uint)BitConverter.ToInt32(_int, 0); - //TODO: Be able to handle compressed files - if (compression != 0) - throw new NotImplementedException("Can only handle uncompressed files!"); - //now reading total image data size(including padding) - bytes 34 -> 38 - stream.Read(_int, 0, 4); - uint totalImageSize = (uint)BitConverter.ToInt32(_int, 0); - - #endregion BMP Header - - //Set the bitmap to have the correct values - Width = imageWidth; - Height = imageHeight; - Depth = (ColorDepth)pixelSize; - - rawData = new int[Width * Height]; - - #region Pixel Table - - //Calculate padding - int paddingPerRow = 0; - int pureImageSize = (int)(imageWidth * imageHeight * pixelSize / 8); - if (totalImageSize != 0) - { - int remainder = (int)totalImageSize - pureImageSize; - if (remainder < 0) throw new Exception("Total Image Size is smaller than pure image size"); - paddingPerRow = remainder / (int)imageHeight; - pureImageSize = (int)totalImageSize; - } - else - { - //total image size is 0 if it is not compressed - paddingPerRow = 0; - } - //Read data - stream.Position = (int)pixelTableOffset; - int position = 0; - Byte[] pixelData = new byte[pureImageSize]; - stream.Read(pixelData, 0, pureImageSize); - Byte[] pixel = new byte[4]; //All must have the same size - - for (int x = 0; x < imageWidth; x++) - { - for (int y = 0; y < imageHeight; y++) - { - if (pixelSize == 32) - pixel[0] = pixelData[position++]; - else - { - pixel[0] = 0; - } - pixel[1] = pixelData[position++]; - pixel[2] = pixelData[position++]; - pixel[3] = pixelData[position++]; - rawData[x + (imageHeight - (y + 1)) * imageWidth] = BitConverter.ToInt32(pixel, 0); - } - position += paddingPerRow; - } - - #endregion Pixel Table + throw new Exception("Info header size has the wrong value!"); } + //now reading width of image in pixels - bytes 18 -> 22 + stream.Read(_int, 0, 4); + uint imageWidth = (uint)BitConverter.ToInt32(_int, 0); + + //now reading height of image in pixels - byte 22 -> 26 + stream.Read(_int, 0, 4); + uint imageHeight = (uint)BitConverter.ToInt32(_int, 0); + + //now reading number of planes should be 1 - byte 26 -> 28 + stream.Read(_short, 0, 2); + ushort planes = (ushort)BitConverter.ToInt16(_short, 0); + if (planes != 1) + throw new Exception("Number of planes is not 1! Can not read file!"); + //now reading size of bits per pixel (1, 4, 8, 24, 32) - bytes 28 - 30 + stream.Read(_short, 0, 2); + ushort pixelSize = (ushort)BitConverter.ToInt16(_short, 0); + //TODO: Be able to handle other pixel sizes + if (!(pixelSize == 32 || pixelSize == 24)) + { + throw new NotImplementedException("Can only handle 32bit or 24bit bitmaps!"); + } + //now reading compression type - bytes 30 -> 34 + stream.Read(_int, 0, 4); + uint compression = (uint)BitConverter.ToInt32(_int, 0); + //TODO: Be able to handle compressed files + if (compression != 0) + throw new NotImplementedException("Can only handle uncompressed files!"); + //now reading total image data size(including padding) - bytes 34 -> 38 + stream.Read(_int, 0, 4); + uint totalImageSize = (uint)BitConverter.ToInt32(_int, 0); + + #endregion BMP Header + + //Set the bitmap to have the correct values + Width = imageWidth; + Height = imageHeight; + Depth = (ColorDepth)pixelSize; + + rawData = new int[Width * Height]; + + #region Pixel Table + + //Calculate padding + int paddingPerRow = 0; + int pureImageSize = (int)(imageWidth * imageHeight * pixelSize / 8); + if (totalImageSize != 0) + { + int remainder = (int)totalImageSize - pureImageSize; + if (remainder < 0) throw new Exception("Total Image Size is smaller than pure image size"); + paddingPerRow = remainder / (int)imageHeight; + pureImageSize = (int)totalImageSize; + } + else + { + //total image size is 0 if it is not compressed + paddingPerRow = 0; + } + //Read data + stream.Position = (int)pixelTableOffset; + int position = 0; + Byte[] pixelData = new byte[pureImageSize]; + stream.Read(pixelData, 0, pureImageSize); + Byte[] pixel = new byte[4]; //All must have the same size + + for (int x = 0; x < imageWidth; x++) + { + for (int y = 0; y < imageHeight; y++) + { + if (pixelSize == 32) + pixel[0] = pixelData[position++]; + else + { + pixel[0] = 0; + } + pixel[1] = pixelData[position++]; + pixel[2] = pixelData[position++]; + pixel[3] = pixelData[position++]; + rawData[x + (imageHeight - (y + 1)) * imageWidth] = BitConverter.ToInt32(pixel, 0); + } + position += paddingPerRow; + } + + #endregion Pixel Table } public void Save(string path)