예제 #1
0
		public static IImage FromFileFramework(string filename)
		{
			System.Drawing.Image img = System.Drawing.Image.FromFile(filename);
			uint width = (uint)img.Size.Width;
			uint height = (uint)img.Size.Height;

			Image8i ret = null;

			if ((img.PixelFormat & PixelFormat.Alpha) == PixelFormat.Alpha)
			{
				ret = new Image8i(width, height, ChannelFormat.RGBA);

				Bitmap bmp = new Bitmap(img);
				BitmapData data = bmp.LockBits(new Rectangle(0, 0, (int)width, (int)height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
				Marshal.Copy(data.Scan0, ret.ImageData, 0, (int)(width * height * 4));
				bmp.UnlockBits(data);
			}
			else
			{
				ret = new Image8i(width, height, ChannelFormat.RGB);

				Bitmap bmp = new Bitmap(img);
				BitmapData data = bmp.LockBits(new Rectangle(0, 0, (int)width, (int)height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
				if (((int)width * 3) == data.Stride)
				{
					Marshal.Copy(data.Scan0, ret.ImageData, 0, (int)(width * height * 3));
				}
				else
				{
					if (IntPtr.Size == 4)
					{
						for (uint i = 0; i < height; i++)
						{
							Marshal.Copy((IntPtr)(data.Scan0.ToInt32() + (int)(i * data.Stride)), ret.ImageData, (int)(width * 3 * i), (int)(width * 3));
						}
					}
					else if (IntPtr.Size == 8)
					{
						for (uint i = 0; i < height; i++)
						{
							Marshal.Copy((IntPtr)(data.Scan0.ToInt64() + (long)(i * data.Stride)), ret.ImageData, (int)(width * 3 * i), (int)(width * 3));
						}
					}
				}

				bmp.UnlockBits(data);
				data = null;
				bmp.Dispose();
				bmp = null;
			}

			img.Dispose();
			img = null;

			return ret;
		}
예제 #2
0
		public static IImage FromFile(string filename)
		{
			#region Variables
			// Header
			int bfOffBits;		    				// Offset of image data in byte from start of file

			// Information block
			uint biSize;							// Size of information block in byte
			int biWidth;							// Width of bitmap in pixel
			int biHeight;							// Height of bitmap in pixel
			short biPlanes;							// on PCX number of color layers on windows bitmap always 1 (not used)
			short biBitCount;						// Color depth (1, 4, 8, 16, 24, 32 Bit)
			BitmapBitCompression biCompression;		// Compression method
			uint biClrUsed;							// Colors

			// Misc things in info block
			uint bmRed = 0;		// Color mask red
			uint bmGreen = 0;	// Color mask green
			uint bmBlue = 0;	// Color mask blue
			uint bmAlpha = 0;	// Color mask alpha

			// Color table
			List<Color8i> ColorTable = new List<Color8i>();
			#endregion

			// Binary reader to open and read the file
			BinaryReader fileReader = new BinaryReader(File.OpenRead(filename));

			try
			{
				#region Header auslesen
				byte[] buffer = new byte[2];
				fileReader.Read(buffer, 0, 2);
				if (buffer[0] != 'B' && buffer[0] != 'M') throw new InvalidDataException();

				fileReader.ReadInt32(); // bfSize
				fileReader.BaseStream.Seek(10, SeekOrigin.Begin);	// skip bfReserved
				bfOffBits = fileReader.ReadInt32();
				#endregion

				#region Information block (BITMAPINFOHEADER)
				biSize = fileReader.ReadUInt32();

				if (biSize == 12) // OS/2 1.x
				{ 
					biWidth = fileReader.ReadInt16();
					biHeight = fileReader.ReadInt16();
					biPlanes = fileReader.ReadInt16();
					biBitCount = fileReader.ReadInt16();

					// static defined
					biCompression = BitmapBitCompression.BI_RGB;
		
					if (biBitCount == 1 || biBitCount == 4 || biBitCount == 8)
					{
						int CountColors = 1 << biBitCount; // 2^biBitCount

						for (int i = 0; i < CountColors; i++)
						{
							byte blue = fileReader.ReadByte();
							byte green = fileReader.ReadByte();
							byte red = fileReader.ReadByte();
							ColorTable.Add(new Color8i(red, green, blue));
						}
					}
					else if (biBitCount == 16 || biBitCount == 24 || biBitCount == 32)
					{
						// do nothing
					}
					else throw new InvalidDataException();
				}
				else if (biSize == 40 || biSize == 56 || biSize == 64)
				{
					// 40: Windows 3.1x, 95, NT
					// 56: Adobe Photoshop BMP with bit mask (not conform with Bitmap standard!)
					// 64: OS/2 2.x

					biWidth = fileReader.ReadInt32();
					biHeight = fileReader.ReadInt32();
					biPlanes = fileReader.ReadInt16();
					biBitCount = fileReader.ReadInt16();

					biCompression = (BitmapBitCompression)fileReader.ReadUInt32();

					fileReader.ReadUInt32(); // size image
					fileReader.ReadInt32(); // resolution x
					fileReader.ReadInt32(); // resolution y

					biClrUsed = fileReader.ReadUInt32();
					fileReader.ReadUInt32(); // important color

					if (biSize == 64) fileReader.BaseStream.Seek(24, SeekOrigin.Current); // Rest of OS/2 2.x header

					if (biBitCount == 16 || biBitCount == 24 || biBitCount == 32)
					{
						if (biCompression == BitmapBitCompression.BI_BITFIELDS && (biBitCount == 16 || biBitCount == 32))
						{
							bmRed = fileReader.ReadUInt32();
							bmGreen = fileReader.ReadUInt32();
							bmBlue = fileReader.ReadUInt32();
						}
						if (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS && (biBitCount == 16 || biBitCount == 32))
						{
							bmRed = fileReader.ReadUInt32();
							bmGreen = fileReader.ReadUInt32();
							bmBlue = fileReader.ReadUInt32();
							bmAlpha = fileReader.ReadUInt32();
						}
					}
					else if (biBitCount == 1 || biBitCount == 4 || biBitCount == 8)
					{
						uint CountColors = biClrUsed;
						if (biClrUsed == 0) CountColors = 1u << biBitCount; // 2^biBitCount

						for (uint i = 0; i < CountColors; i++)
						{
							byte blue = fileReader.ReadByte();
							byte green = fileReader.ReadByte();
							byte red = fileReader.ReadByte();
							fileReader.BaseStream.Seek(1, SeekOrigin.Current);
							ColorTable.Add(new Color8i(red, green, blue));
						}
					}
					else throw new InvalidDataException(); 
				}
				else
				{
					// 108: Type Windows V4 not supported
					// 124: Type Windows V5 not supported
					throw new NotSupportedException();
				}

				// Consistency check
				if (biPlanes != 1 || biWidth <= 0 || biHeight == 0) throw new InvalidDataException();
				if (biBitCount != 16 && biBitCount != 32 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS ||	biCompression == BitmapBitCompression.BI_BITFIELDS)) throw new InvalidDataException();

				// Downgrade to standard handling if bitfields are standard
				if (biCompression == BitmapBitCompression.BI_BITFIELDS)
				{
					if (biBitCount == 32 && bmRed == 0xFF0000 && bmGreen == 0xFF00 && bmBlue == 0xFF) biCompression = BitmapBitCompression.BI_RGB;
				}
				if (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS)
				{
					if (biBitCount == 32 && bmRed == 0xFF0000 && bmGreen == 0xFF00 && bmBlue == 0xFF && bmAlpha == 0xFF000000) biCompression = BitmapBitCompression.BI_RGB;
				}

				int absHeight = System.Math.Abs(biHeight);
				#endregion

				#region Read image data
				fileReader.BaseStream.Seek(bfOffBits, SeekOrigin.Begin); // seek to image data

				if (biCompression == BitmapBitCompression.BI_RGB)
				{
					#region Uncompressed image data
					if (biBitCount == 1) // 1 Bit
					{
						#region 1 Bit
						// create return image
						Image8i ret;
						if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
						else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

						int bytesPerRow = (int)Statics.Align((uint)(biWidth + 7) / 8, 4);

						int ind = 0;
						buffer = new byte[bytesPerRow];

						while (ColorTable.Count < 2) ColorTable.Add(Color8i.Black);

						if (biHeight > 0) // buttom-up image
						{
							for (int i = absHeight - 1; i >= 0; i--)
							{
								ind = i * biWidth * 3;
								fileReader.Read(buffer, 0, buffer.Length);
								byte pixel = 0;
								for (int a = 0; a < biWidth; a++)
								{
									if (a % 8 == 0) pixel = buffer[a / 8];
									int bit = (pixel & 0x80) == 0x80 ? 1 : 0;
									ret.ImageData[ind++] = ColorTable[bit].B;
									ret.ImageData[ind++] = ColorTable[bit].G;
									ret.ImageData[ind++] = ColorTable[bit].R;
									pixel <<= 1;
								}
							}
						}
						else if (biHeight < 0) // top-down image
						{
							for (int i = 0; i < absHeight; i++)
							{
								fileReader.Read(buffer, 0, buffer.Length);
								byte pixel = 0;

								for (int a = 0; a < biWidth; a++)
								{
									if (a % 8 == 0) pixel = buffer[a / 8];
									int bit = (pixel & 0x80) == 0x80 ? 1 : 0;
									ret.ImageData[ind++] = ColorTable[bit].B;
									ret.ImageData[ind++] = ColorTable[bit].G;
									ret.ImageData[ind++] = ColorTable[bit].R;
									pixel <<= 1;
								}
							}
						}

						return ret;
						#endregion
					}
					else if (biBitCount == 4) // 4 Bit
					{
						#region 4 Bit
						// create return image
						Image8i ret;
						if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
						else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

						int BytesPerRow = (int)Statics.Align((uint)(biWidth * 4 + 7) / 8, 4);

						int ind = 0;
						buffer = new byte[BytesPerRow];

						while (ColorTable.Count < 16) ColorTable.Add(Color8i.Black);

						if (biHeight > 0) // buttom-up image
						{
							for (int i = absHeight - 1; i >= 0; i--)
							{
								ind = i * biWidth * 3;
								fileReader.Read(buffer, 0, buffer.Length);
								byte pixel = 0;
								for (int a = 0; a < biWidth; a++)
								{
									if (a % 2 == 0) pixel = buffer[a / 2];
									int bit = (pixel & 0xF0) >> 4;
									ret.ImageData[ind++] = ColorTable[bit].B;
									ret.ImageData[ind++] = ColorTable[bit].G;
									ret.ImageData[ind++] = ColorTable[bit].R;
									pixel <<= 4;
								}
							}
						}
						else if (biHeight < 0) // top-down image
						{
							for (int i = 0; i < absHeight; i++)
							{
								fileReader.Read(buffer, 0, buffer.Length);
								byte pixel = 0;

								for (int a = 0; a < biWidth; a++)
								{
									if (a % 2 == 0) pixel = buffer[a / 2];
									int bit = (pixel & 0xF0) >> 4;
									ret.ImageData[ind++] = ColorTable[bit].B;
									ret.ImageData[ind++] = ColorTable[bit].G;
									ret.ImageData[ind++] = ColorTable[bit].R;
									pixel <<= 4;
								}
							}
						}
						#endregion
					}
					else if (biBitCount == 8) // 8 Bit
					{
						#region 8 Bit
						// create return image
						Image8i ret;
						if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
						else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

						int bytesPerRow = (int)Statics.Align((uint)biWidth, 4);

						int ind = 0;
						buffer = new byte[bytesPerRow];

						while (ColorTable.Count < 256) ColorTable.Add(Color8i.Black);

						if (biHeight > 0) // buttom-up image
						{
							for (int i = absHeight - 1; i >= 0; i--)
							{
								ind = i * biWidth * 3;
								fileReader.Read(buffer, 0, buffer.Length);
								for (int a = 0; a < biWidth; a++)
								{
									byte pixel = buffer[a];
									ret.ImageData[ind++] = ColorTable[pixel].B;
									ret.ImageData[ind++] = ColorTable[pixel].G;
									ret.ImageData[ind++] = ColorTable[pixel].R;
								}
							}
						}
						else if (biHeight < 0) // top-down image
						{
							for (int i = 0; i < absHeight; i++)
							{
								fileReader.Read(buffer, 0, buffer.Length);
								for (int a = 0; a < biWidth; a++)
								{
									byte pixel = buffer[a];
									ret.ImageData[ind++] = ColorTable[pixel].B;
									ret.ImageData[ind++] = ColorTable[pixel].G;
									ret.ImageData[ind++] = ColorTable[pixel].R;
								}
							}
						}
						#endregion
					}
					else if (biBitCount == 16) // 16 Bit
					{
						#region 16 Bit
						// create return image
						Image8i ret;
						if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
						else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

						int bytesPerRow = (biWidth * 2);

						int ind = 0;
						buffer = new byte[bytesPerRow];

						if (biHeight > 0) // buttom-up image
						{
							for (int i = absHeight - 1; i >= 0; i--)
							{
								ind = i * biWidth * 3;
								fileReader.Read(buffer, 0, buffer.Length);
								for (int a = 0; a < biWidth; a++)
								{
									byte pixelA = buffer[a * 2];
									byte pixelB = buffer[a * 2 + 1];

									int b = (pixelA & 0x1F) << 3;
									int g = ((pixelB & 0x3) << 6) + ((pixelA & 0xE0) >> 2);
									int r = (pixelB & 0x7C) << 1;

									ret.ImageData[ind++] = (byte)(b + b / 32);
									ret.ImageData[ind++] = (byte)(g + g / 32);
									ret.ImageData[ind++] = (byte)(r + r / 32);
								}
							}
						}
						else if (biHeight < 0) // top-down image
						{
							for (int i = absHeight - 1; i >= 0; i--)
							{
								fileReader.Read(buffer, 0, buffer.Length);
								for (int a = 0; a < biWidth; a++)
								{
									byte pixelA = buffer[a * 2];
									byte pixelB = buffer[a * 2 + 1];

									int b = (pixelA & 0x1F) << 3;
									int g = ((pixelB & 0x3) << 6) + ((pixelA & 0xE0) >> 2);
									int r = (pixelB & 0x7C) << 1;

									ret.ImageData[ind++] = (byte)(b + b / 32);
									ret.ImageData[ind++] = (byte)(g + g / 32);
									ret.ImageData[ind++] = (byte)(r + r / 32);
								}
							}
						}
						#endregion
					}
					else if (biBitCount == 24) // 24 Bit
					{
						#region 24 Bit
						// create return image
						Image8i ret;
						if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
						else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

						int bytesPerRow = (biWidth * 3);
						int rest = (int)(Statics.Align((uint)bytesPerRow, 4) - bytesPerRow);

						if (biHeight > 0) // buttom-up image
						{
							for (int i = 0; i < absHeight; i++)
							{
								fileReader.Read(ret.ImageData, ret.ImageData.Length - (i + 1) * bytesPerRow, bytesPerRow);
								if (rest != 0) fileReader.BaseStream.Seek(rest, SeekOrigin.Current);
							}
						}
						else if (biHeight < 0) // top-down image
						{
							if (rest == 0)
							{
								fileReader.Read(ret.ImageData, 0, bytesPerRow * absHeight); // load the whole imahe
							}
							else
							{
								for (int i = 0; i < absHeight; i++)
								{
									fileReader.Read(ret.ImageData, i * bytesPerRow, bytesPerRow);
									if (rest != 0) fileReader.BaseStream.Seek(rest, SeekOrigin.Current);
								}
							}
						}
						#endregion
					}
					else if (biBitCount == 32) // 32 Bit
					{
						#region 32 Bit
						// create return image
						Image8i ret;
						if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
						else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

						int bytesPerRow = (biWidth * 4);
						buffer = new byte[bytesPerRow];

						if (biHeight > 0) // buttom-up image
						{
							for (int i = 0; i < absHeight; i++)
							{
								fileReader.Read(ret.ImageData, ret.ImageData.Length - (i + 1) * bytesPerRow, bytesPerRow);
							}
						}
						else if (biHeight < 0) // top-down image
						{
							fileReader.Read(ret.ImageData, 0, bytesPerRow * absHeight); // load the whole image
						}
						#endregion
					}
					#endregion
				}
				else if (biCompression == BitmapBitCompression.BI_RLE8) // RLE 8 encoded data
				{
					#region RLE 8
					// create return image
					Image8i ret;
					if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
					else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

					if (biBitCount != 8) throw new InvalidDataException();	// only images with 8 bit color depth allowed

					int bytesPerRow = (int)Statics.Align((uint)biWidth, 4);
					int rest = bytesPerRow - biWidth;
					byte[] bufferRLE = new byte[absHeight * bytesPerRow];
					int index = 0;
					int lineCount = 0;

					while (ColorTable.Count < 256) ColorTable.Add(Color8i.Black);

					#region Dekomprimiere RLE 8
					while (fileReader.BaseStream.Position < fileReader.BaseStream.Length && index < (absHeight * bytesPerRow))
					{
						if (rest != 0 && (index / bytesPerRow) != lineCount) throw new InvalidDataException("Bad RLE 8 coding.");
						if (rest == 0 && (index / bytesPerRow) != lineCount) if (index > bytesPerRow * (lineCount + 1)) throw new InvalidDataException("Bad RLE 8 coding.");

						byte cByte = fileReader.ReadByte();

						if (cByte == 0) // command byte
						{
							byte scByte = fileReader.ReadByte();
							switch (scByte)
							{
								case 0: // end of image line
									{
										lineCount++;
										index = lineCount * bytesPerRow;
										break;
									}
								case 1: // end of image
									{
										index = absHeight * bytesPerRow;
										lineCount = absHeight;
										fileReader.BaseStream.Position = fileReader.BaseStream.Length;
										break;
									}
								case 2: // move the corrent image position
									{
										byte vRight = fileReader.ReadByte();	// move right
										if (vRight >= biWidth) throw new InvalidDataException("Bad RLE 8 coding.");

										byte vDown = fileReader.ReadByte();	// move down

										int currentRow = index - lineCount * bytesPerRow;
										if ((currentRow + vRight) >= biWidth) throw new InvalidDataException("Bad RLE 8 coding.");
										if ((lineCount + vDown) >= absHeight) throw new InvalidDataException("Bad RLE 8 coding.");

										lineCount += vDown;
										index = lineCount * bytesPerRow + currentRow + vRight;
										break;
									}
								default: // read bytes 3-255 without changes
									{
										fileReader.Read(bufferRLE, index, scByte);
										index += scByte;

										// if offset odd add seek one byte
										if (scByte % 2 != 0) fileReader.BaseStream.Seek(1, SeekOrigin.Current);

										break;
									}
							}
						}
						else // write data cByte many times
						{
							byte dByte = fileReader.ReadByte();
							for (int i = 0; i < cByte; i++) bufferRLE[index++] = dByte;
						}
					}
					#endregion

					#region Create image an fill
					if (biHeight > 0) // buttom-up image
					{
						int fIndex = 0; // RLE Buffer Index
						index = 0;

						for (int i = absHeight - 1; i >= 0; i--)
						{
							index = i * biWidth * 3;

							for (int a = 0; a < biWidth; a++)
							{
								byte pixel = bufferRLE[fIndex++];
								ret.ImageData[index++] = ColorTable[pixel].B;
								ret.ImageData[index++] = ColorTable[pixel].G;
								ret.ImageData[index++] = ColorTable[pixel].R;
							}

							fIndex += rest;
						}
					}
					else if (biHeight < 0) // top-down image
					{
						int fIndex = 0;	// RLE buffer index
						index = 0;

						for (int i = 0; i < absHeight; i++)
						{
							for (int a = 0; a < biWidth; a++)
							{
								byte pixel = bufferRLE[fIndex++];
								ret.ImageData[index++] = ColorTable[pixel].B;
								ret.ImageData[index++] = ColorTable[pixel].G;
								ret.ImageData[index++] = ColorTable[pixel].R;
							}

							fIndex += rest;
						}
					}
					#endregion
					#endregion
				}
				else if (biCompression == BitmapBitCompression.BI_RLE4) // RLE 4 endocded data
				{
					#region RLE 4
					// create return image
					Image8i ret;
					if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
					else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

					if (biBitCount != 4) throw new InvalidDataException(); // only images with 4 bit color depth allowed

					int BytesPerRow = (int)Statics.Align((uint)biWidth, 4);
					int rest = BytesPerRow - biWidth;
					byte[] bufferRLE = new byte[absHeight * BytesPerRow];
					int index = 0;
					int lineCount = 0;

					while (ColorTable.Count < 16) ColorTable.Add(Color8i.Black);

					#region Dekomprimiere RLE 4
					while (fileReader.BaseStream.Position < fileReader.BaseStream.Length && index < (absHeight * BytesPerRow))
					{
						if (rest != 0 && (index / BytesPerRow) != lineCount) throw new InvalidDataException("Bad RLE 4 coding.");
						if (rest == 0 && (index / BytesPerRow) != lineCount) if (index > BytesPerRow * (lineCount + 1)) throw new InvalidDataException("Bad RLE 4 coding.");

						byte cByte = fileReader.ReadByte();

						if (cByte == 0) // command follows in byte 2
						{
							byte scByte = fileReader.ReadByte();
							switch (scByte)
							{
								case 0: // end of image line
									{
										lineCount++;
										index = lineCount * BytesPerRow;
										break;
									}
								case 1: // end of bitmap
									{
										index = absHeight * BytesPerRow;
										lineCount = absHeight;
										fileReader.BaseStream.Position = fileReader.BaseStream.Length;
										break;
									}
								case 2: // move the current image position
									{
										byte vRight = fileReader.ReadByte();	// move right
										if (vRight >= biWidth) throw new InvalidDataException("Bad RLE 4 coding.");

										byte vDown = fileReader.ReadByte();	// move down

										int currentRow = index - lineCount * BytesPerRow;
										if ((currentRow + vRight) >= biWidth) throw new InvalidDataException("Bad RLE 4 coding.");
										if ((lineCount + vDown) >= absHeight) throw new InvalidDataException("Bad RLE 4 coding.");

										lineCount += vDown;
										index = lineCount * BytesPerRow + currentRow + vRight;
										break;
									}
								default: // read nibbles 3-255 without changes
									{
										byte[] nibbles = new byte[(scByte + 1) / 2];
										fileReader.Read(nibbles, 0, nibbles.Length);

										for (int i = 0; i < nibbles.Length - (cByte % 2); i++)
										{
											bufferRLE[index++] = (byte)(nibbles[i] >> 4);
											bufferRLE[index++] = (byte)(nibbles[i] & 0xF);
										}
										if (cByte % 2 != 0) bufferRLE[index++] = (byte)(nibbles[nibbles.Length - 1] >> 4);

										// if offset odd seek one byte forward
										if (((scByte + 1) / 2) % 2 != 0) fileReader.BaseStream.Seek(1, SeekOrigin.Current);

										break;
									}
							}
						}
						else // write data cByte many times
						{
							byte dByte = fileReader.ReadByte();
							byte aByte = (byte)(dByte >> 4);
							byte bByte = (byte)(dByte & 0xF);

							for (int i = 0; i < cByte / 2; i++)
							{
								bufferRLE[index++] = aByte;
								bufferRLE[index++] = bByte;
							}

							if (cByte % 2 != 0) bufferRLE[index++] = aByte;
						}
					}
					#endregion

					#region Fill image
					if (biHeight > 0) // buttom-up image
					{
						int fIndex = 0; // RLE buffer Index
						index = 0;

						for (int i = absHeight - 1; i >= 0; i--)
						{
							index = i * biWidth * 3;

							for (int a = 0; a < biWidth; a++)
							{
								byte pixel = bufferRLE[fIndex++];
								ret.ImageData[index++] = ColorTable[pixel].B;
								ret.ImageData[index++] = ColorTable[pixel].G;
								ret.ImageData[index++] = ColorTable[pixel].R;
							}

							fIndex += rest;
						}
					}
					else if (biHeight < 0) // top-down image
					{
						int fIndex = 0;	// RLE buffer Index
						index = 0;

						for (int i = 0; i < absHeight; i++)
						{
							for (int a = 0; a < biWidth; a++)
							{
								byte pixel = bufferRLE[fIndex++];
								ret.ImageData[index++] = ColorTable[pixel].B;
								ret.ImageData[index++] = ColorTable[pixel].G;
								ret.ImageData[index++] = ColorTable[pixel].R;
							}

							fIndex += rest;
						}
					}
					#endregion
					#endregion
				}
				else if (biCompression == BitmapBitCompression.BI_BITFIELDS || biCompression == BitmapBitCompression.BI_ALPHABITFIELDS)
				{
					#region BI_BITFIELDS
					// create return image
					Image8i ret;
					if (biBitCount == 32 || (biBitCount == 16 && (biCompression == BitmapBitCompression.BI_ALPHABITFIELDS || biCompression == BitmapBitCompression.BI_BITFIELDS))) ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGBA);
					else ret = new Image8i((uint)biWidth, (uint)absHeight, ChannelFormat.RGB);

					if (biBitCount == 16)
					{
						#region Check bit masks
						bmRed &= 0xffff; // only 16 bit
						bmGreen &= 0xffff;
						bmBlue &= 0xffff;
						bmAlpha &= 0xffff;

						bool doRed = true;
						bool doGreen = true;
						bool doBlue = true;
						bool doAlpha = true;

						if ((bmRed & bmGreen) > 0) throw new InvalidDataException("Bad bit fields");
						if ((bmRed & bmBlue) > 0) throw new InvalidDataException("Bad bit fields");
						if ((bmGreen & bmBlue) > 0) throw new InvalidDataException("Bad bit fields");

						int rshifta = 0;
						while (((bmRed >> rshifta) & 0x1) == 0) rshifta++;
						int rshiftb = rshifta;
						while (((bmRed >> rshiftb) & 0x1) != 0) rshiftb++;
						for (int i = rshiftb; i < 16; i++) if ((bmRed & 1u << i) > 0) throw new InvalidDataException("Bad bit fields");

						int gshifta = 0;
						while (((bmGreen >> gshifta) & 0x1) == 0) gshifta++;
						int gshiftb = gshifta;
						while (((bmGreen >> gshiftb) & 0x1) != 0) gshiftb++;
						for (int i = gshiftb; i < 16; i++) if ((bmGreen & 1u << i) > 0) throw new InvalidDataException("Bad bit fields");

						int bshifta = 0;
						while (((bmBlue >> bshifta) & 0x1) == 0) bshifta++;
						int bshiftb = bshifta;
						while (((bmBlue >> bshiftb) & 0x1) != 0) bshiftb++;
						for (int i = bshiftb; i < 16; i++) if ((bmBlue & 1u << i) > 0) throw new InvalidDataException("Bad bit fields");

						int ashifta = 0;
						int ashiftb = 0;

						if (biCompression == BitmapBitCompression.BI_BITFIELDS)
						{
							bmAlpha = ~(bmRed | bmGreen | bmBlue);

							if (bmAlpha != 0xffff0000)
							{
								bmAlpha &= 0xffff;
								ashifta = 0;
								while (((bmAlpha >> ashifta) & 0x1) == 0) ashifta++;

								ashiftb = ashifta;
								while (((bmAlpha >> ashiftb) & 0x1) != 0) ashiftb++;

								bmAlpha = ~bmAlpha;
								for (int i = ashiftb; i < 16; i++) bmAlpha |= 1u << i;
								bmAlpha = ~bmAlpha;
							}
							else bmAlpha = 0;
						}
						else
						{
							if ((bmAlpha & bmRed) > 0) throw new InvalidDataException("Bad bit fields");
							if ((bmAlpha & bmGreen) > 0) throw new InvalidDataException("Bad bit fields");
							if ((bmAlpha & bmBlue) > 0) throw new InvalidDataException("Bad bit fields");

							ashifta = 0;
							while (((bmAlpha >> ashifta) & 0x1) == 0) ashifta++;
							ashiftb = ashifta;
							while (((bmAlpha >> ashiftb) & 0x1) != 0) ashiftb++;
							for (int i = ashiftb; i < 16; i++) if ((bmAlpha & 1u << i) > 0) throw new InvalidDataException("Bad bit fields");
						}

						if (bmRed == 0) doRed = false;
						if (bmGreen == 0) doGreen = false;
						if (bmBlue == 0) doBlue = false;
						if (bmAlpha == 0) doAlpha = false;

						if (!doRed && !doGreen && !doBlue && !doAlpha) throw new Exception("Bad bit fields");

						int redSize = rshiftb - rshifta;
						int greenSize = gshiftb - gshifta;
						int blueSize = bshiftb - bshifta;
						int alphaSize = ashiftb - ashifta;
						#endregion

						#region 16 Bit
						int BytesPerRow = (biWidth * 2);
						buffer = new byte[BytesPerRow * absHeight];

						if (biHeight > 0) // buttom-up image
						{
							for (int i = 0; i < absHeight; i++)
							{
								fileReader.Read(buffer, buffer.Length - (i + 1) * BytesPerRow, BytesPerRow);
							}
						}
						else if (biHeight < 0) // top-down image
						{
							fileReader.Read(buffer, 0, BytesPerRow * absHeight); // load the whole image
						}

						uint redDiv = 0, greenDiv = 0, blueDiv = 0, alphaDiv = 0;
						if (doRed && redSize < 8) redDiv = 1u << redSize;
						if (doGreen && greenSize < 8) greenDiv = 1u << greenSize;
						if (doBlue && blueSize < 8) blueDiv = 1u << blueSize;
						if (doAlpha && alphaSize < 8) alphaDiv = 1u << alphaSize;

						// Use bitmask
						for (int i = 0; i < biWidth * absHeight; i++)
						{
							int start = i * 4;
							uint color = ((uint)buffer[i * 2 + 1] << 8) + (uint)buffer[i * 2];

							if (doRed)
							{
								uint red = (color & bmRed) >> rshifta;
								if (redSize > 8) red >>= redSize - 8;
								if (redSize < 8)
								{
									red <<= 8 - redSize;
									red += red / redDiv;
								}

								ret.ImageData[start + 2] = (byte)red;
							}
							else ret.ImageData[start + 2] = 0;

							if (doGreen)
							{
								uint green = (color & bmGreen) >> gshifta;
								if (greenSize > 8) green >>= greenSize - 8;
								if (greenSize < 8)
								{
									green <<= 8 - greenSize;
									green += green / greenDiv;
								}
								ret.ImageData[start + 1] = (byte)green;
							}
							else ret.ImageData[start + 1] = 0;

							if (doBlue)
							{
								uint blue = (color & bmBlue) >> bshifta;
								if (blueSize > 8) blue >>= blueSize - 8;
								if (blueSize < 8)
								{
									blue <<= 8 - blueSize;
									blue += blue / blueDiv;
								}
								ret.ImageData[start] = (byte)blue;
							}
							else ret.ImageData[start] = 0;

							if (doAlpha)
							{
								uint alpha = (color & bmAlpha) >> ashifta;
								if (alphaSize > 8) alpha >>= alphaSize - 8;
								if (alphaSize < 8)
								{
									alpha <<= 8 - alphaSize;
									alpha += alpha / alphaDiv;
								}
								ret.ImageData[start + 3] = (byte)alpha;
							}
							else ret.ImageData[start + 3] = 0;
						}
						#endregion
					}
					else if (biBitCount == 32)
					{
						#region Check bit masks
						bool doRed = true;
						bool doGreen = true;
						bool doBlue = true;
						bool doAlpha = true;

						if ((bmRed & bmGreen) > 0) throw new InvalidDataException("Bad bit fields");
						if ((bmRed & bmBlue) > 0) throw new InvalidDataException("Bad bit fields");
						if ((bmGreen & bmBlue) > 0) throw new InvalidDataException("Bad bit fields");

						int rshifta = 0;
						while (((bmRed >> rshifta) & 0x1) == 0) rshifta++;
						int rshiftb = rshifta;
						while (((bmRed >> rshiftb) & 0x1) != 0) rshiftb++;
						for (int i = rshiftb; i < 32; i++) if ((bmRed & 1u << i) > 0) throw new InvalidDataException("Bad bit fields");

						int gshifta = 0;
						while (((bmGreen >> gshifta) & 0x1) == 0) gshifta++;
						int gshiftb = gshifta;
						while (((bmGreen >> gshiftb) & 0x1) != 0) gshiftb++;
						for (int i = gshiftb; i < 32; i++) if ((bmGreen & 1u << i) > 0) throw new InvalidDataException("Bad bit fields");

						int bshifta = 0;
						while (((bmBlue >> bshifta) & 0x1) == 0) bshifta++;
						int bshiftb = bshifta;
						while (((bmBlue >> bshiftb) & 0x1) != 0) bshiftb++;
						for (int i = bshiftb; i < 32; i++) if ((bmBlue & 1u << i) > 0) throw new InvalidDataException("Bad bit fields");

						int ashifta = 0;
						int ashiftb = 0;

						if (biCompression == BitmapBitCompression.BI_BITFIELDS)
						{
							bmAlpha = ~(bmRed | bmGreen | bmBlue);
							if (bmAlpha != 0)
							{
								ashifta = 0;
								while (((bmAlpha >> ashifta) & 0x1) == 0) ashifta++;

								ashiftb = ashifta;
								while (((bmAlpha >> ashiftb) & 0x1) != 0) ashiftb++;

								bmAlpha = ~bmAlpha;
								for (int i = ashiftb; i < 32; i++) bmAlpha |= 1u << i;
								bmAlpha = ~bmAlpha;
							}
						}
						else
						{
							if ((bmAlpha & bmRed) > 0) throw new Exception("Bad bit fields");
							if ((bmAlpha & bmGreen) > 0) throw new Exception("Bad bit fields");
							if ((bmAlpha & bmBlue) > 0) throw new Exception("Bad bit fields");

							ashifta = 0;
							while (((bmAlpha >> ashifta) & 0x1) == 0) ashifta++;
							ashiftb = ashifta;
							while (((bmAlpha >> ashiftb) & 0x1) != 0) ashiftb++;
							for (int i = ashiftb; i < 32; i++) if ((bmAlpha & 1u << i) > 0) throw new InvalidDataException("Bad bit fields");
						}

						if (bmRed == 0) doRed = false;
						if (bmGreen == 0) doGreen = false;
						if (bmBlue == 0) doBlue = false;
						if (bmAlpha == 0) doAlpha = false;

						if (!doRed && !doGreen && !doBlue && !doAlpha) throw new InvalidDataException("Bad bit fields");

						int redSize = rshiftb - rshifta;
						int greenSize = gshiftb - gshifta;
						int blueSize = bshiftb - bshifta;
						int alphaSize = ashiftb - ashifta;
						#endregion

						#region 32 Bit
						int BytesPerRow = (biWidth * 4);

						if (biHeight > 0) // buttom-up image
						{
							for (int i = 0; i < absHeight; i++)
							{
								fileReader.Read(ret.ImageData, ret.ImageData.Length - (i + 1) * BytesPerRow, BytesPerRow);
							}
						}
						else if (biHeight < 0) // top-down image
						{
							fileReader.Read(ret.ImageData, 0, BytesPerRow * absHeight); // load the whole image
						}

						uint redDiv = 0, greenDiv = 0, blueDiv = 0, alphaDiv = 0;
						if (doRed && redSize < 8) redDiv = 1u << redSize;
						if (doGreen && greenSize < 8) greenDiv = 1u << greenSize;
						if (doBlue && blueSize < 8) blueDiv = 1u << blueSize;
						if (doAlpha && alphaSize < 8) alphaDiv = 1u << alphaSize;

						// Use bit mask
						for (int i = 0; i < biWidth * absHeight; i++)
						{
							int start = i * 4;
							uint color = ((uint)ret.ImageData[start + 3] << 24) + ((uint)ret.ImageData[start + 2] << 16) + ((uint)ret.ImageData[start + 1] << 8) + (uint)ret.ImageData[start];

							if (doRed)
							{
								uint red = (color & bmRed) >> rshifta;
								if (redSize > 8) red >>= redSize - 8;
								if (redSize < 8)
								{
									red <<= 8 - redSize;
									red += red / redDiv;
								}
								ret.ImageData[start + 2] = (byte)red;
							}
							else ret.ImageData[start + 2] = 0;

							if (doGreen)
							{
								uint green = (color & bmGreen) >> gshifta;
								if (greenSize > 8) green >>= greenSize - 8;
								if (greenSize < 8)
								{
									green <<= 8 - greenSize;
									green += green / greenDiv;
								}
								ret.ImageData[start + 1] = (byte)green;
							}
							else ret.ImageData[start + 1] = 0;

							if (doBlue)
							{
								uint blue = (color & bmBlue) >> bshifta;
								if (blueSize > 8) blue >>= blueSize - 8;
								if (blueSize < 8)
								{
									blue <<= 8 - blueSize;
									blue += blue / blueDiv;
								}
								ret.ImageData[start] = (byte)blue;
							}
							else ret.ImageData[start] = 0;

							if (doAlpha)
							{
								uint alpha = (color & bmAlpha) >> ashifta;
								if (alphaSize > 8) alpha >>= alphaSize - 8;
								if (alphaSize < 8)
								{
									alpha <<= 8 - alphaSize;
									alpha += alpha / alphaDiv;
								}
								ret.ImageData[start + 3] = (byte)alpha;
							}
							else ret.ImageData[start + 3] = 0;
						}
						#endregion
					}

					return ret;
					#endregion
				}
				#endregion
			}
			finally
			{
				fileReader.Close();
			}

			throw new NotSupportedException();
		}
예제 #3
0
		public static void ToFile(string filename, Image8i image)
		{
			if (image.ChannelFormat == ChannelFormat.BGR||image.ChannelFormat == ChannelFormat.Gray)
			{
				ToFile(filename, image.ToChannelFormatRGB());
				return;
			}

			if (image.ChannelFormat == ChannelFormat.BGRA||image.ChannelFormat == ChannelFormat.GrayAlpha)
			{
				ToFile(filename, image.ToChannelFormatRGBA());
				return;
			}

			BinaryWriter fileWriter = new BinaryWriter(File.Open(filename, FileMode.Create));

			#region Header
			fileWriter.Write('B'); 		// Signature
			fileWriter.Write('M'); 		// Signature
			fileWriter.Write((uint)0); 	// Size of file //TODO add filesize
			fileWriter.Write((uint)0); 	// Reserved
			fileWriter.Write((uint)70); // Offset of image data
			#endregion

			#region Informationsblock
			fileWriter.Write((uint)40); 			// Size of info block
			fileWriter.Write((int)image.Width); 	// Image with
			fileWriter.Write((int)image.Height); 	// Image height (top down image)
			fileWriter.Write((ushort)1); 			// Planes (always one)

			if (image.ChannelFormat == ChannelFormat.RGB) fileWriter.Write((ushort)24); // 24 Bit
			else if (image.ChannelFormat == ChannelFormat.RGBA) fileWriter.Write((ushort)32); // 32 Bit

			fileWriter.Write((uint)0); // Compression (BI_RGB / uncompressed)
			fileWriter.Write((uint)0); // Size of image daza (can be zero)

			fileWriter.Write((int)0); // horizontal resolution of output device in pixel per meter 
			fileWriter.Write((int)0); // vertical resolution of output device in pixel per meter 

			fileWriter.Write((uint)0); // biClrUsed (zero, no palette)
			fileWriter.Write((uint)0); // biClrImportant (zero, no palette)
			#endregion

			#region RGB Quad
			fileWriter.Write((uint)0); // blue
			fileWriter.Write((uint)0); // green
			fileWriter.Write((uint)0); // red
			fileWriter.Write((uint)0); // reserved
			#endregion

			fileWriter.Write(image.GetImageDataWithGranularity(4));

			fileWriter.Close();
		}
예제 #4
0
		public static void SaveToTiff(string filename, Image8i image)
		{
			if (image.ChannelFormat == ChannelFormat.BGR||image.ChannelFormat == ChannelFormat.Gray)
			{
				SaveToPNG(filename, image.ToChannelFormatRGB());
				return;
			}

			if (image.ChannelFormat == ChannelFormat.BGRA||image.ChannelFormat == ChannelFormat.GrayAlpha)
			{
				SaveToPNG(filename, image.ToChannelFormatRGBA());
				return;
			}

			if (image.ChannelFormat == ChannelFormat.RGBA)
			{
				Bitmap bmp = new Bitmap((int)image.Width, (int)image.Height, PixelFormat.Format32bppArgb);
				BitmapData data = bmp.LockBits(new Rectangle(0, 0, (int)image.Width, (int)image.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

				Marshal.Copy(image.ImageData, 0, data.Scan0, (int)(image.Width * image.Height * 4));

				bmp.UnlockBits(data);
				data = null;

				bmp.Save(filename, ImageFormat.Tiff);
				bmp.Dispose();
				bmp = null;
			}
			else
			{
				Bitmap bmp = new Bitmap((int)image.Width, (int)image.Height, PixelFormat.Format24bppRgb);
				BitmapData data = bmp.LockBits(new Rectangle(0, 0, (int)image.Width, (int)image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

				if (((int)image.Width * 3) == data.Stride)
				{
					Marshal.Copy(image.ImageData, 0, data.Scan0, (int)(image.Width * image.Height * 3));
				}
				else
				{
					if (IntPtr.Size == 4)
					{
						for (uint i = 0; i < image.Height; i++)
						{
							Marshal.Copy(image.ImageData, (int)(image.Width * 3 * i), (IntPtr)(data.Scan0.ToInt32() + (int)(i * data.Stride)), (int)(image.Width * 3));
						}
					}
					else if (IntPtr.Size == 8)
					{
						for (uint i = 0; i < image.Height; i++)
						{
							Marshal.Copy(image.ImageData, (int)(image.Width * 3 * i), (IntPtr)(data.Scan0.ToInt64() + (long)(i * data.Stride)), (int)(image.Width * 3));
						}
					}
				}
				bmp.UnlockBits(data);
				data = null;

				bmp.Save(filename, ImageFormat.Tiff);
				bmp.Dispose();
				bmp = null;
			}
		}
예제 #5
0
		public static void SaveToJpeg(string filename, int exifWidth, int exifHeight, byte quality, Image8i image)
		{
			if (image.ChannelFormat == ChannelFormat.BGR||image.ChannelFormat == ChannelFormat.Gray)
			{
				SaveToJpeg(filename, exifWidth, exifHeight, quality, image.ToChannelFormatRGB());
				return;
			}

			if (image.ChannelFormat == ChannelFormat.BGRA||image.ChannelFormat == ChannelFormat.GrayAlpha)
			{
				SaveToJpeg(filename, exifWidth, exifHeight, image.ToChannelFormatRGBA());
				return;
			}

			Bitmap bmp = new Bitmap((int)image.Width, (int)image.Height, PixelFormat.Format24bppRgb);

			BitmapData data = bmp.LockBits(new Rectangle(0, 0, (int)image.Width, (int)image.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

			if (((int)image.Width * 3) == data.Stride)
			{
				Marshal.Copy(image.ImageData, 0, data.Scan0, (int)(image.Width * image.Height * 3));
			}
			else
			{
				if (IntPtr.Size == 4)
				{
					for (uint i = 0; i < image.Height; i++)
					{
						Marshal.Copy(image.ImageData, (int)(image.Width * 3 * i), (IntPtr)(data.Scan0.ToInt32() + (int)(i * data.Stride)), (int)(image.Width * 3));
					}
				}
				else if (IntPtr.Size == 8)
				{
					for (uint i = 0; i < image.Height; i++)
					{
						Marshal.Copy(image.ImageData, (int)(image.Width * 3 * i), (IntPtr)(data.Scan0.ToInt64() + (long)(i * data.Stride)), (int)(image.Width * 3));
					}
				}
			}

			bmp.UnlockBits(data);
			data = null;

			if (exifWidth > 0 && exifHeight > 0)
			{
				PropertyItem o = (PropertyItem)Activator.CreateInstance(typeof(PropertyItem), true);

				byte[] buff = Encoding.ASCII.GetBytes("ASCII\0\0\0" + exifWidth + "x" + exifHeight);
				o.Id = 0x9286;
				o.Type = 7;
				o.Len = buff.Length;
				o.Value = buff;
				bmp.SetPropertyItem(o);

				o = (PropertyItem)Activator.CreateInstance(typeof(PropertyItem), true);
				o.Id = 0x100;
				o.Type = 4;
				o.Len = 4;
				o.Value = BitConverter.GetBytes((uint)exifWidth);
				bmp.SetPropertyItem(o);

				o = (PropertyItem)Activator.CreateInstance(typeof(PropertyItem), true);
				o.Id = 0x101;
				o.Type = 4;
				o.Len = 4;
				o.Value = BitConverter.GetBytes((uint)exifHeight);
				bmp.SetPropertyItem(o);
			}

			if (quality > 100) quality = 100;

			EncoderParameters encoderParameters = new EncoderParameters(1);
			encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)quality);
			bmp.Save(filename, jpegImageCodecInfo, encoderParameters);
			encoderParameters.Dispose();
			bmp.Dispose();
			bmp = null;
		}
예제 #6
0
		public static void SaveToFile(string filename, Image8i image)
		{
			string ext = Paths.GetExtension(filename).ToLower();

			switch (ext)
			{
				case "png":
					{
						SaveToPNG(filename, image);
						break;
					}
				case "jpg":
				case "jpeg":
				case "jpe":
				case "jif":
				case "jfi":
				case "jfif":
				case "psi":
				case "pmi":
					{
						SaveToJpeg(filename, -1, -1, image);
						break;
					}
				case "tga":
					{
						TargaImage.ToFile(filename, image);
						break;
					}
				case "bmp":
				case "dib":
					{
						WindowsBitmap.ToFile(filename, image);
						break;
					}
				case "tiff":
				case "tif":
					{
						SaveToTiff(filename, image);
						break;
					}
				default:
					{
						throw new NotSupportedException();
					}
			}
		}