public unsafe void Set(Bitmap bitmap, Bitmap bitmapMask, Color transparentColor) { // We need to rotate the images, but we don't want to mess with the source image, lets create a clone Bitmap image = (Bitmap) bitmap.Clone(); Bitmap mask = bitmapMask != null ? (Bitmap) bitmapMask.Clone() : null; try { //.NET has a bug flipping in the Y axis for 1bpp images, let do it ourself if (image.PixelFormat != PixelFormat.Format1bppIndexed) image.RotateFlip(RotateFlipType.RotateNoneFlipY); else Tools.FlipYBitmap(image); if (mask != null) Tools.FlipYBitmap(mask); if (mask != null && (image.Size != mask.Size || mask.PixelFormat != PixelFormat.Format1bppIndexed)) throw new InvalidMultiIconMaskBitmap(); // Palette // Some icons programs like Axialis have program with a reduce palette, so lets create a complete palette instead RGBQUAD[] palette = Tools.RGBQUADFromColorArray(image); // Bitmap Header BITMAPINFOHEADER infoHeader= new BITMAPINFOHEADER(); infoHeader.biSize = (uint) sizeof(BITMAPINFOHEADER); infoHeader.biWidth = (uint) image.Width; infoHeader.biHeight = (uint) image.Height * 2; infoHeader.biPlanes = 1; infoHeader.biBitCount = (ushort) Tools.BitsFromPixelFormat(image.PixelFormat); infoHeader.biCompression = IconImageFormat.BMP; infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = (uint) palette.Length; infoHeader.biClrImportant = 0; // IconImage mEncoder.Header = infoHeader; mEncoder.Colors = palette; // XOR Image BitmapData bmpData = image.LockBits(new Rectangle(0,0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat); IntPtr scanColor= bmpData.Scan0; mEncoder.XOR = new byte[Math.Abs(bmpData.Stride) * bmpData.Height]; Marshal.Copy(scanColor, mEncoder.XOR, 0, mEncoder.XOR.Length); image.UnlockBits(bmpData); infoHeader.biSizeImage = (uint) mEncoder.XOR.Length; // AND Image if (mask == null) { // Lets create the AND Image from the Color Image Bitmap bmpBW = new Bitmap(image.Width, image.Height, PixelFormat.Format1bppIndexed); BitmapData bmpBWData = bmpBW.LockBits(new Rectangle(0,0, image.Width, image.Height), ImageLockMode.ReadWrite, bmpBW.PixelFormat); IntPtr scanBW = bmpBWData.Scan0; mEncoder.AND = new byte[Math.Abs(bmpBWData.Stride) * bmpBWData.Height]; //Let extract the AND image from the XOR image int strideC =Math.Abs(bmpData.Stride); int strideB =Math.Abs(bmpBWData.Stride); int bpp = Tools.BitsFromPixelFormat(image.PixelFormat); int posCY; int posCX; int posBY; int color; Color tColor; RGBQUAD paletteColor; //If the image is 24 bits, then lets make sure alpha channel is 0 if (bpp == 24) transparentColor = Color.FromArgb(0, transparentColor.R, transparentColor.G, transparentColor.B); for(int y=0;y<bmpData.Height; y++) { posBY = strideB * y; posCY = strideC * y; for(int x=0;x<bmpData.Width; x++) { switch (bpp) { case 1: mEncoder.AND[(x >> 3) + posCY] = (byte) mEncoder.XOR[(x >> 3) + posCY]; break; case 4: color = mEncoder.XOR[(x >> 1) + posCY]; paletteColor = mEncoder.Colors[(x & 1) == 0 ? color >> 4 : color & 0x0F]; if (Tools.CompareRGBQUADToColor(paletteColor , transparentColor)) { mEncoder.AND[(x >> 3) + posBY] |= (byte) (0x80 >> (x & 7)); mEncoder.XOR[(x >> 1) + posCY] &= (byte) ((x & 1) == 0 ? 0x0F : 0xF0); } break; case 8: color = mEncoder.XOR[x + posCY]; paletteColor = mEncoder.Colors[color]; if (Tools.CompareRGBQUADToColor(paletteColor , transparentColor)) { mEncoder.AND[(x >> 3) + posBY] |= (byte) (0x80 >> (x & 7)); mEncoder.XOR[x + posCY] = 0; } break; case 16: throw new NotSupportedException("16 bpp images are not supported for Icons"); case 24: posCX = x * 3; tColor = Color.FromArgb(0, mEncoder.XOR[posCX + posCY + 0], mEncoder.XOR[posCX + posCY + 1], mEncoder.XOR[posCX + posCY + 2]); if (tColor == transparentColor) mEncoder.AND[(x >> 3) + posBY] |= (byte) (0x80 >> (x & 7)); break; case 32: if (transparentColor == Color.Transparent) { if (mEncoder.XOR[(x << 2) + posCY + 3] == 0) mEncoder.AND[(x >> 3) + posBY] |= (byte) (0x80 >> (x & 7)); } else { if (mEncoder.XOR[(x << 2) + posCY + 0] == transparentColor.B && mEncoder.XOR[(x << 2) + posCY + 1] == transparentColor.G && mEncoder.XOR[(x << 2) + posCY + 2] == transparentColor.R) { mEncoder.AND[(x >> 3) + posBY] |= (byte) (0x80 >> (x & 7)); mEncoder.XOR[(x << 2) + posCY + 0] = 0; mEncoder.XOR[(x << 2) + posCY + 1] = 0; mEncoder.XOR[(x << 2) + posCY + 2] = 0; } else { mEncoder.XOR[(x << 2) + posCY + 3] = 255; } } break; } } } bmpBW.UnlockBits(bmpBWData); } else { // Mask is coming by parameter, so we don't need to create it BitmapData bmpBWData = mask.LockBits(new Rectangle(0,0, mask.Width, mask.Height), ImageLockMode.ReadOnly, mask.PixelFormat); IntPtr scanBW = bmpBWData.Scan0; mEncoder.AND = new byte[Math.Abs(bmpBWData.Stride) * bmpBWData.Height]; Marshal.Copy(scanBW, mEncoder.AND, 0, mEncoder.AND.Length); mask.UnlockBits(bmpBWData); } } finally { if (image != null) image.Dispose(); if (mask != null) mask.Dispose(); } }
public unsafe void Set(Bitmap bitmap, Bitmap bitmapMask, Color transparentColor) { // We need to rotate the images, but we don't want to mess with the source image, lets create a clone Bitmap image = (Bitmap)bitmap.Clone(); Bitmap mask = bitmapMask != null ? (Bitmap)bitmapMask.Clone() : null; try { //.NET has a bug flipping in the Y axis for 1bpp images, let do it ourself if (image.PixelFormat != PixelFormat.Format1bppIndexed) { image.RotateFlip(RotateFlipType.RotateNoneFlipY); } else { Tools.FlipYBitmap(image); } if (mask != null) { Tools.FlipYBitmap(mask); } if (mask != null && (image.Size != mask.Size || mask.PixelFormat != PixelFormat.Format1bppIndexed)) { throw new InvalidMultiIconMaskBitmap(); } // Palette // Some icons programs like Axialis have program with a reduce palette, so lets create a complete palette instead RGBQUAD[] palette = Tools.RGBQUADFromColorArray(image); // Bitmap Header BITMAPINFOHEADER infoHeader = new BITMAPINFOHEADER(); infoHeader.biSize = (uint)sizeof(BITMAPINFOHEADER); infoHeader.biWidth = (uint)image.Width; infoHeader.biHeight = (uint)image.Height * 2; infoHeader.biPlanes = 1; infoHeader.biBitCount = (ushort)Tools.BitsFromPixelFormat(image.PixelFormat); infoHeader.biCompression = IconImageFormat.BMP; infoHeader.biXPelsPerMeter = 0; infoHeader.biYPelsPerMeter = 0; infoHeader.biClrUsed = (uint)palette.Length; infoHeader.biClrImportant = 0; // IconImage mEncoder.Header = infoHeader; mEncoder.Colors = palette; // XOR Image BitmapData bmpData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat); IntPtr scanColor = bmpData.Scan0; mEncoder.XOR = new byte[Math.Abs(bmpData.Stride) * bmpData.Height]; Marshal.Copy(scanColor, mEncoder.XOR, 0, mEncoder.XOR.Length); image.UnlockBits(bmpData); infoHeader.biSizeImage = (uint)mEncoder.XOR.Length; // AND Image if (mask == null) { // Lets create the AND Image from the Color Image Bitmap bmpBW = new Bitmap(image.Width, image.Height, PixelFormat.Format1bppIndexed); BitmapData bmpBWData = bmpBW.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, bmpBW.PixelFormat); IntPtr scanBW = bmpBWData.Scan0; mEncoder.AND = new byte[Math.Abs(bmpBWData.Stride) * bmpBWData.Height]; //Let extract the AND image from the XOR image int strideC = Math.Abs(bmpData.Stride); int strideB = Math.Abs(bmpBWData.Stride); int bpp = Tools.BitsFromPixelFormat(image.PixelFormat); int posCY; int posCX; int posBY; int color; Color tColor; RGBQUAD paletteColor; //If the image is 24 bits, then lets make sure alpha channel is 0 if (bpp == 24) { transparentColor = Color.FromArgb(0, transparentColor.R, transparentColor.G, transparentColor.B); } for (int y = 0; y < bmpData.Height; y++) { posBY = strideB * y; posCY = strideC * y; for (int x = 0; x < bmpData.Width; x++) { switch (bpp) { case 1: mEncoder.AND[(x >> 3) + posCY] = (byte)mEncoder.XOR[(x >> 3) + posCY]; break; case 4: color = mEncoder.XOR[(x >> 1) + posCY]; paletteColor = mEncoder.Colors[(x & 1) == 0 ? color >> 4 : color & 0x0F]; if (Tools.CompareRGBQUADToColor(paletteColor, transparentColor)) { mEncoder.AND[(x >> 3) + posBY] |= (byte)(0x80 >> (x & 7)); mEncoder.XOR[(x >> 1) + posCY] &= (byte)((x & 1) == 0 ? 0x0F : 0xF0); } break; case 8: color = mEncoder.XOR[x + posCY]; paletteColor = mEncoder.Colors[color]; if (Tools.CompareRGBQUADToColor(paletteColor, transparentColor)) { mEncoder.AND[(x >> 3) + posBY] |= (byte)(0x80 >> (x & 7)); mEncoder.XOR[x + posCY] = 0; } break; case 16: throw new NotSupportedException("16 bpp images are not supported for Icons"); case 24: posCX = x * 3; tColor = Color.FromArgb(0, mEncoder.XOR[posCX + posCY + 0], mEncoder.XOR[posCX + posCY + 1], mEncoder.XOR[posCX + posCY + 2]); if (tColor == transparentColor) { mEncoder.AND[(x >> 3) + posBY] |= (byte)(0x80 >> (x & 7)); } break; case 32: if (transparentColor == Color.Transparent) { if (mEncoder.XOR[(x << 2) + posCY + 3] == 0) { mEncoder.AND[(x >> 3) + posBY] |= (byte)(0x80 >> (x & 7)); } } else { if (mEncoder.XOR[(x << 2) + posCY + 0] == transparentColor.B && mEncoder.XOR[(x << 2) + posCY + 1] == transparentColor.G && mEncoder.XOR[(x << 2) + posCY + 2] == transparentColor.R) { mEncoder.AND[(x >> 3) + posBY] |= (byte)(0x80 >> (x & 7)); mEncoder.XOR[(x << 2) + posCY + 0] = 0; mEncoder.XOR[(x << 2) + posCY + 1] = 0; mEncoder.XOR[(x << 2) + posCY + 2] = 0; } else { mEncoder.XOR[(x << 2) + posCY + 3] = 255; } } break; } } } bmpBW.UnlockBits(bmpBWData); } else { // Mask is coming by parameter, so we don't need to create it BitmapData bmpBWData = mask.LockBits(new Rectangle(0, 0, mask.Width, mask.Height), ImageLockMode.ReadOnly, mask.PixelFormat); IntPtr scanBW = bmpBWData.Scan0; mEncoder.AND = new byte[Math.Abs(bmpBWData.Stride) * bmpBWData.Height]; Marshal.Copy(scanBW, mEncoder.AND, 0, mEncoder.AND.Length); mask.UnlockBits(bmpBWData); } } finally { if (image != null) { image.Dispose(); } if (mask != null) { mask.Dispose(); } } }
public BITMAPINFOHEADER(Stream stream) { this = new BITMAPINFOHEADER(); Read(stream); }
public BITMAPINFOHEADER(Stream stream) { this = new BITMAPINFOHEADER(); this.Read(stream); }