public static void SaveColorToBMP(string filePath, Microsoft.Psi.Imaging.Image rgbImage) { using (FileStream fs = new FileStream(filePath, FileMode.Create)) { BitmapFileHeader header = default(BitmapFileHeader); BitmapInfoHeader infoheader = default(BitmapInfoHeader); header.Type = 0x4d42; int headerSize = Marshal.SizeOf(header); int infoSize = Marshal.SizeOf(infoheader); header.OffBits = Marshal.SizeOf(header) + Marshal.SizeOf(infoheader); header.Size = header.OffBits + 3 * rgbImage.Width * rgbImage.Height; header.Reserved1 = 0; header.Reserved2 = 0; byte[] bufferHeader = StructAsByteArray(header); fs.Write(bufferHeader, 0, bufferHeader.Length); infoheader.Size = Marshal.SizeOf(infoheader); infoheader.Width = rgbImage.Width; infoheader.Height = rgbImage.Height; infoheader.Planes = 1; infoheader.BitCount = 24; infoheader.Compression = 0; // Uncompressed infoheader.SizeImage = rgbImage.Width * rgbImage.Height * 3; infoheader.XPelsPerMeter = 96; infoheader.YPelsPerMeter = 96; infoheader.ClrUsed = 0; infoheader.ClrImportant = 0; byte[] bufferInfoHeader = StructAsByteArray(infoheader); fs.Write(bufferInfoHeader, 0, bufferInfoHeader.Length); byte[] imageData = new byte[infoheader.SizeImage]; Marshal.Copy(rgbImage.ImageData, imageData, 0, infoheader.SizeImage); fs.Write(imageData, 0, infoheader.SizeImage); } }
public BitmapWriter(Stream stream, int width, int height) : base(stream) { _width = width; _height = height; var fileSize = width * height * 4 + 14 + 40; _bitmapFileHeader = new BitmapFileHeader((uint)fileSize, 14 + 40); _bitmapInfoHeader = new BitmapInfoHeader(width, -height); WriteHeader(); }
private BitmapFileHeader ReadBitmapFileHeader(BinaryReader br) { BitmapFileHeader BFH = new BitmapFileHeader(); BFH.type = br.ReadUInt16(); BFH.size = br.ReadUInt32(); BFH.reserved1 = br.ReadUInt16(); BFH.reserved2 = br.ReadUInt16(); BFH.offBits = br.ReadUInt32(); return(BFH); }
/// <summary> /// the DIB readed should solve the issue reported here: https://sourceforge.net/projects/greenshot/forums/forum/676083/topic/6354353/index/page/1 /// </summary> /// <returns>Image</returns> private static Image GetDIBImage(IDataObject dataObejct) { try { // If the EnableSpecialDIBClipboardReader flag in the config is set, use the code from: // http://www.thomaslevesque.com/2009/02/05/wpf-paste-an-image-from-the-clipboard/ // to read the DeviceIndependentBitmap from the clipboard, this might fix bug 3576125 if (config.EnableSpecialDIBClipboardReader) { MemoryStream dibStream = GetFromDataObject(dataObejct, DataFormats.Dib) as MemoryStream; if (isValidStream(dibStream)) { LOG.Info("Found valid DIB stream, trying to process it."); byte[] dibBuffer = new byte[dibStream.Length]; dibStream.Read(dibBuffer, 0, dibBuffer.Length); BitmapInfoHeader infoHeader = BinaryStructHelper.FromByteArray <BitmapInfoHeader>(dibBuffer); LOG.InfoFormat("Using special DIB format reader for biCompression {0}", infoHeader.biCompression); int fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader)); uint infoHeaderSize = infoHeader.biSize; int fileSize = (int)(fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage); BitmapFileHeader fileHeader = new BitmapFileHeader(); fileHeader.bfType = BitmapFileHeader.BM; fileHeader.bfSize = fileSize; fileHeader.bfReserved1 = 0; fileHeader.bfReserved2 = 0; fileHeader.bfOffBits = (int)(fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4); byte[] fileHeaderBytes = BinaryStructHelper.ToByteArray <BitmapFileHeader>(fileHeader); using (MemoryStream bitmapStream = new MemoryStream()) { bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); bitmapStream.Write(dibBuffer, 0, dibBuffer.Length); bitmapStream.Seek(0, SeekOrigin.Begin); using (Image tmpImage = Image.FromStream(bitmapStream)) { if (tmpImage != null) { return(ImageHelper.Clone(tmpImage)); } } } } } else { LOG.Info("Skipping special DIB format reader as it's disabled in the configuration."); } } catch (Exception dibEx) { LOG.Error("Problem retrieving DIB from clipboard.", dibEx); } return(null); }
/// <summary> /// An existing bitmap file. /// </summary> /// <param name="filename">A file in a .bmp format.</param> public BitmapFile(string filename) { var data = File.ReadAllBytes(filename); var pFileHeaderData = Marshal.AllocHGlobal(Marshal.SizeOf(_header)); try { Marshal.Copy(data, 0, pFileHeaderData, Marshal.SizeOf(_header)); _header = (BitmapFileHeader)Marshal.PtrToStructure(pFileHeaderData, typeof (BitmapFileHeader)); } finally { Marshal.FreeHGlobal(pFileHeaderData); } var size = data.Length - Marshal.SizeOf(_header); var bitmapData = new byte[size]; Buffer.BlockCopy(data, Marshal.SizeOf(_header), bitmapData, 0, size); _bitmap = new DeviceIndependentBitmap(bitmapData); }
private void _checkResource(string res, List <ValidationErrorView> errors, ReadableTuple <int> tuple, HashSet <string> processed, ValidationErrors error, string type, ServerDbs serverDb, List <GrfImageType> allowedTypes) { if (processed.Add(res)) { var result = _database.MetaGrf.GetData(res); if (result == null) { errors.Add(new ResourceError(error, tuple.Key, type + ": " + res, serverDb, this, res)); } else { if (SdeAppConfiguration.VaResInvalidFormat) { GrfImage image = new GrfImage(result); foreach (var imType in allowedTypes) { if (image.GrfImageType == imType) { if (imType == GrfImageType.Bgr24) { BitmapFileHeader bitmap = new BitmapFileHeader(new ByteReader(result)); if (bitmap.DibHeader.ColorTableUsed != 0 || bitmap.DibHeader.ColorTableImportant != 0) { errors.Add(new ResourceError(ValidationErrors.ResInvalidType, tuple.Key, "SuspiciousImageFormat: " + res, serverDb, this, res) { ImageType = imType }); return; } } return; } } errors.Add(new ResourceError(ValidationErrors.ResInvalidType, tuple.Key, "ImageType: " + res, serverDb, this, res) { ImageType = allowedTypes[0] }); } } } }
public void Save(string filename) { const byte BYTES_PER_PIXEL = 3; int row_increment_ = width * BYTES_PER_PIXEL; using (FileStream stream = File.Create(filename)) { BitmapInformationHeader bih = new BitmapInformationHeader(); bih.width = (uint)width; bih.height = (uint)height; bih.bit_count = BYTES_PER_PIXEL << 3; bih.clr_important = 0; bih.clr_used = 0; bih.compression = 0; bih.planes = 1; bih.size = (uint)Marshal.SizeOf(bih); bih.x_pels_per_meter = 0; bih.y_pels_per_meter = 0; bih.size_image = (((bih.width * BYTES_PER_PIXEL) + 3) & 0x0000FFFC) * bih.height; BitmapFileHeader bfh = new BitmapFileHeader(); bfh.type = 19778; bfh.size = (uint)(Marshal.SizeOf(bfh) + Marshal.SizeOf(bih) + bih.size_image); bfh.reserved1 = 0; bfh.reserved2 = 0; bfh.off_bits = (uint)(Marshal.SizeOf(bih) + Marshal.SizeOf(bfh)); stream.Write(GetBytes(bfh), 0, Marshal.SizeOf(bfh)); stream.Write(GetBytes(bih), 0, Marshal.SizeOf(bih)); int padding = (4 - ((3 * width) % 4)) % 4; byte[] padding_data = { 0x00, 0x00, 0x00, 0x00 }; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Color32 c = buffer[y * width + x]; byte[] bgr = { c.b, c.g, c.r }; stream.Write(bgr, 0, 3); } stream.Write(padding_data, 0, padding); } } }
/// <summary> /// An existing bitmap file. /// </summary> /// <param name="filename">A file in a .bmp format.</param> public BitmapFile(string filename) { var data = File.ReadAllBytes(filename); var pFileHeaderData = Marshal.AllocHGlobal(Marshal.SizeOf(_header)); try { Marshal.Copy(data, 0, pFileHeaderData, Marshal.SizeOf(_header)); _header = (BitmapFileHeader)Marshal.PtrToStructure(pFileHeaderData, typeof(BitmapFileHeader)); } finally { Marshal.FreeHGlobal(pFileHeaderData); } var size = data.Length - Marshal.SizeOf(_header); var bitmapData = new byte[size]; Buffer.BlockCopy(data, Marshal.SizeOf(_header), bitmapData, 0, size); _bitmap = new DeviceIndependentBitmap(bitmapData); }
static unsafe byte[] MakeBitmapFileHeader(ulong fileSize) { var header = new BitmapFileHeader { bfType = 0x4D42, bfSize = fileSize, //bfReserved1 = 0, //bfReserved2 = 0, bfOffBits = 54, }; const int size = 14; var bytes = new byte[size]; fixed(byte *pbytes = bytes) { *(BitmapFileHeader *)pbytes = header; } return(bytes); }
public void Save(string filename) { if (string.IsNullOrEmpty(filename)) { throw new ArgumentNullException(nameof(filename)); } if (disposedValue) { throw new ObjectDisposedException(nameof(FastBitmap)); } int sizeOfFileHeader = sizeof(BitmapFileHeader); int sizeOfInfoHeader = sizeof(BitmapInfoHeader); int dibSectionLength = (Width * Height) * 3; int realInfoHeaderSize = Marshal.ReadInt32(_bitmapInfoHeader); if (realInfoHeaderSize != 0 && sizeOfInfoHeader != realInfoHeaderSize) { sizeOfInfoHeader = realInfoHeaderSize; } BitmapFileHeader fileHeader = new BitmapFileHeader { OffsetBits = (uint)(sizeOfFileHeader + sizeOfInfoHeader), Size = (uint)(dibSectionLength + sizeOfFileHeader + sizeOfInfoHeader), Type = 0x4D42 }; byte[] bitmap = new byte[sizeOfFileHeader + sizeOfInfoHeader + dibSectionLength]; Marshal.Copy((IntPtr)(void *)&fileHeader, bitmap, 0, sizeOfFileHeader); Marshal.Copy(_bitmapInfoHeader, bitmap, sizeOfFileHeader, sizeOfInfoHeader); Marshal.Copy(_dibSection, bitmap, sizeOfFileHeader + sizeOfInfoHeader, dibSectionLength); File.WriteAllBytes(filename, bitmap); }
/// <summary> /// Get a DIB from the Clipboard /// </summary> /// <param name="clipboardAccessToken"></param> /// <returns>Bitmap or null</returns> public static Bitmap GetAsDeviceIndependendBitmap(this IClipboardAccessToken clipboardAccessToken) { var formats = clipboardAccessToken.AvailableFormats().ToList(); if (!formats.Contains(StandardClipboardFormats.Bitmap.AsString())) { return(null); } var format17Bytes = clipboardAccessToken.GetAsBytes(StandardClipboardFormats.Bitmap.AsString()); var infoHeader = BinaryStructHelper.FromByteArray <BitmapInfoHeader>(format17Bytes); if (infoHeader.IsDibV5) { Log.Warn().WriteLine("Getting DIBV5 (format 17) when requesting DIB"); return(null); } // Bitmap version older than 5 var fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader)); var fileHeader = BitmapFileHeader.Create(infoHeader); var fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader); using (var bitmapStream = new MemoryStream()) { bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); bitmapStream.Write(format17Bytes, 0, format17Bytes.Length); bitmapStream.Seek(0, SeekOrigin.Begin); var image = BitmapHelper.FromStream(bitmapStream); if (image != null) { return(image); } } return(null); }
/// <summary>Reads header information from a stream.</summary> private void Initialise(Stream stream) { BinaryReader rdr; int first; try { rdr = new BinaryReader(stream); first = rdr.PeekChar(); } catch (ArgumentException aex) { throw new DibException("Unable to initialise DIB", aex); } // see if it has a BitmapFileHeader at the beginning if (first == 'B') { _fileHeader = new BitmapFileHeader(rdr); } // determine the Dib type (the BitmapFileHeader will have advanced the reader) // maybe do some validation on the structs? switch (rdr.PeekChar()) { case 12: Class = DibClass.Core; break; case 40: Class = DibClass.V3; break; case 108: Class = DibClass.V4; break; case 124: Class = DibClass.V5; break; default: throw new DibException("Unrecognised BitmapInfoHeader dwSize"); } _infoHeader = FillBitmapHeader(rdr, Class); if (_fileHeader.bfType == 0) { // if no fileheader was read earlier // create the FileHeader _fileHeader = CreateFileHeader(); } else { // resize the data array to remove the fileheader var sizeOfBitmapFileHeader = Marshal.SizeOf(typeof(BitmapFileHeader)); var newData = new byte[_dibData.Length - sizeOfBitmapFileHeader]; Array.Copy(_dibData, sizeOfBitmapFileHeader, newData, 0, newData.Length); _dibData = newData; } }
/// <summary> /// bitmapのロード /// </summary> /// <param name="path"></param> /// <param name="bfh"></param> /// <param name="bih"></param> /// <param name="colorPal"></param> /// <param name="bitData"></param> /// <returns></returns> private static bool Load(string path, out BitmapFileHeader bfh, out BitmapInfoHeader bih, out Color[] colorPal, out byte[] bitData) { var ext = Path.GetExtension(path).ToLower(); if (ext != ".bmp") { goto ErrorHandler; } var readData = new byte[4]; FileStream fs; try { fs = File.Open(path, FileMode.Open, FileAccess.Read); if (fs == null) { goto ErrorHandler; } } catch { goto ErrorHandler; } // ヘッダ情報読み込み fs.Read(readData, 0, 2); bfh.fType = BitConverter.ToUInt16(readData, 0); fs.Read(readData, 0, 4); bfh.fSize = BitConverter.ToUInt32(readData, 0); fs.Read(readData, 0, 2); bfh.fReserved1 = BitConverter.ToUInt16(readData, 0); fs.Read(readData, 0, 2); bfh.fReserved2 = BitConverter.ToUInt16(readData, 0); fs.Read(readData, 0, 4); bfh.fOffset = BitConverter.ToUInt32(readData, 0); fs.Read(readData, 0, 4); bih.biSize = BitConverter.ToUInt32(readData, 0); fs.Read(readData, 0, 4); bih.biWidth = BitConverter.ToInt32(readData, 0); fs.Read(readData, 0, 4); bih.biHeight = BitConverter.ToInt32(readData, 0); fs.Read(readData, 0, 2); bih.biPlanes = BitConverter.ToUInt16(readData, 0); fs.Read(readData, 0, 2); bih.biBitCount = BitConverter.ToUInt16(readData, 0); fs.Read(readData, 0, 4); bih.biCompression = BitConverter.ToUInt32(readData, 0); fs.Read(readData, 0, 4); bih.biSizeImage = BitConverter.ToUInt32(readData, 0); fs.Read(readData, 0, 4); bih.biXPelsPerMeter = BitConverter.ToInt32(readData, 0); fs.Read(readData, 0, 4); bih.biYPelsPerMeter = BitConverter.ToInt32(readData, 0); fs.Read(readData, 0, 4); bih.biClrUsed = BitConverter.ToUInt32(readData, 0); fs.Read(readData, 0, 4); bih.biClrImportant = BitConverter.ToUInt32(readData, 0); // データ読み込み long palSize = (bfh.fOffset - 14 - 40) / 4; if (palSize != 0) { colorPal = new Color[palSize]; for (int i = 0; i < palSize; ++i) { fs.Read(readData, 0, 4); colorPal[i] = new Color(readData[2], readData[1], readData[0], readData[3]); } } else { colorPal = null; } int stride = ((bih.biWidth * bih.biBitCount + 31) / 32) * 4; bitData = new byte[stride * bih.biHeight]; for (int i = 0; i < bih.biHeight; ++i) { fs.Read(bitData, i * stride, stride); } // rgbの順がbgrなので入れ替え for (int i = 0; i < stride * bih.biHeight / 4; ++i) { var idx = i * 4; var t = bitData[idx]; bitData[idx] = bitData[idx + 2]; bitData[idx + 2] = t; } fs.Close(); fs.Dispose(); return(true); ErrorHandler: Debug.LogError("-----BitmapLoaderError-----"); bfh.fType = 0; bfh.fSize = 0; bfh.fReserved1 = 0; bfh.fReserved2 = 0; bfh.fOffset = 0; bih.biSize = 0; bih.biWidth = 0; bih.biHeight = 0; bih.biPlanes = 0; bih.biBitCount = 0; bih.biCompression = 0; bih.biSizeImage = 0; bih.biXPelsPerMeter = 0; bih.biYPelsPerMeter = 0; bih.biClrUsed = 0; bih.biClrImportant = 0; colorPal = null; bitData = null; return(false); }
/// <summary> /// Helper method to try to get an image in the specified format from the dataObject /// the DIB reader should solve some issues /// It also supports Format17/DibV5, by using the following information: http://stackoverflow.com/a/14335591 /// </summary> /// <param name="format">string with the format</param> /// <param name="dataObject">IDataObject</param> /// <returns>Bitmap or null</returns> private static Bitmap GetBitmapForFormat(string format, IDataObject dataObject) { var clipboardObject = GetFromDataObject(dataObject, format); var imageStream = clipboardObject as MemoryStream; if (!IsValidStream(imageStream)) { // TODO: add "HTML Format" support here... return(clipboardObject as Bitmap); } if (CoreConfig.EnableSpecialDIBClipboardReader) { if (format == FORMAT_17 || format == DataFormats.Dib) { Log.Info().WriteLine("Found DIB stream, trying to process it."); try { if (imageStream != null) { var dibBuffer = new byte[imageStream.Length]; imageStream.Read(dibBuffer, 0, dibBuffer.Length); var infoHeader = BinaryStructHelper.FromByteArray <BitmapInfoHeader>(dibBuffer); if (!infoHeader.IsDibV5) { Log.Info().WriteLine("Using special DIB <v5 format reader with biCompression {0}", infoHeader.Compression); var fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader)); var fileHeader = BitmapFileHeader.Create(infoHeader); var fileHeaderBytes = BinaryStructHelper.ToByteArray(fileHeader); using (var bitmapStream = new MemoryStream()) { bitmapStream.Write(fileHeaderBytes, 0, fileHeaderSize); bitmapStream.Write(dibBuffer, 0, dibBuffer.Length); bitmapStream.Seek(0, SeekOrigin.Begin); var image = BitmapHelper.FromStream(bitmapStream); if (image != null) { return(image); } } } else { Log.Info().WriteLine("Using special DIBV5 / Format17 format reader"); // CF_DIBV5 var gcHandle = IntPtr.Zero; try { var handle = GCHandle.Alloc(dibBuffer, GCHandleType.Pinned); gcHandle = GCHandle.ToIntPtr(handle); return (new Bitmap(infoHeader.Width, infoHeader.Height, -(int)(infoHeader.SizeImage / infoHeader.Height), infoHeader.BitCount == 32 ? PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb, new IntPtr(handle.AddrOfPinnedObject().ToInt32() + infoHeader.OffsetToPixels + (infoHeader.Height - 1) * (int)(infoHeader.SizeImage / infoHeader.Height)) )); } catch (Exception ex) { Log.Error().WriteLine(ex, "Problem retrieving Format17 from clipboard."); } finally { if (gcHandle == IntPtr.Zero) { GCHandle.FromIntPtr(gcHandle).Free(); } } } } } catch (Exception dibEx) { Log.Error().WriteLine(dibEx, "Problem retrieving DIB from clipboard."); } } } else { Log.Info().WriteLine("Skipping special DIB format reader as it's disabled in the configuration."); } try { if (imageStream != null) { imageStream.Seek(0, SeekOrigin.Begin); var tmpImage = BitmapHelper.FromStream(imageStream); if (tmpImage != null) { Log.Info().WriteLine("Got image with clipboard format {0} from the clipboard.", format); return(tmpImage); } } } catch (Exception streamImageEx) { Log.Error().WriteLine(streamImageEx, $"Problem retrieving {format} from clipboard."); } return(null); }
/// <summary> /// Convert a DeviceIndependentBitmap to a <see cref="BitmapSource"/> /// </summary> /// <param name="memoryStream">The <see cref="MemoryStream"/> to convert</param> /// <param name="maxHeight">The maximum height of the picture. Use null to don't specify a maximum height</param> /// <returns>Returns a <see cref="BitmapSource"/>. If the memoryStream is null, returns null.</returns> internal static BitmapSource DeviceIndependentBitmapToBitmapSource(MemoryStream memoryStream, int?maxHeight) { if (memoryStream == null) { return(null); } var bytes = memoryStream.ToArray(); var resultMemoryStream = new MemoryStream(); var width = BitConverter.ToInt32(bytes, 4); var height = BitConverter.ToInt32(bytes, 8); var bpp = BitConverter.ToInt16(bytes, 14); if (bpp == 32) { // Potentially, this way of convert, by using System.Drawing.Bitmap (non-WPF) can keep the transparency of the picture. var gch = GCHandle.Alloc(bytes, GCHandleType.Pinned); Bitmap bmp = null; try { var ptr = new IntPtr((long)gch.AddrOfPinnedObject() + 40); bmp = new Bitmap(width, height, width * 4, PixelFormat.Format32bppRgb, ptr); bmp.MakeTransparent(Color.Transparent); bmp.RotateFlip(RotateFlipType.Rotate180FlipX); bmp.Save(resultMemoryStream, ImageFormat.Png); } finally { gch.Free(); if (bmp != null) { bmp.Dispose(); } } } else { // This way does not keep transparency var infoHeader = FromByteArrayToStruct <BitmapInfoHeader>(bytes); var fileHeaderSize = Marshal.SizeOf(typeof(BitmapFileHeader)); var infoHeaderSize = infoHeader.biSize; var fileSize = fileHeaderSize + infoHeader.biSize + infoHeader.biSizeImage; var fileHeader = new BitmapFileHeader { bfType = BitmapFileHeader.BM, bfSize = fileSize, bfReserved1 = 0, bfReserved2 = 0, bfOffBits = fileHeaderSize + infoHeaderSize + infoHeader.biClrUsed * 4 }; var fileHeaderBytes = StructToByteArray(fileHeader); resultMemoryStream.Write(fileHeaderBytes, 0, fileHeaderSize); resultMemoryStream.Write(bytes, 0, bytes.Length); resultMemoryStream.Seek(0, SeekOrigin.Begin); resultMemoryStream.Flush(); } var result = new BitmapImage(); result.BeginInit(); result.CacheOption = BitmapCacheOption.OnLoad; result.CreateOptions = BitmapCreateOptions.PreservePixelFormat; if (maxHeight.HasValue) { result.DecodePixelHeight = maxHeight.Value; } result.StreamSource = resultMemoryStream; result.EndInit(); result.Freeze(); return(result); }
public void Other() { var hDc = User32.GetWindowDC(IntPtr.Zero); var hMemDc = Gdi32.CreateCompatibleDC(hDc); var bi = new BitmapInfoHeader(); bi.biSize = (uint)Marshal.SizeOf(bi); bi.biBitCount = 24; //Creating RGB bitmap. The following three members don't matter bi.biClrUsed = 0; bi.biClrImportant = 0; bi.biCompression = 0; bi.biHeight = Height; bi.biWidth = Width; bi.biPlanes = 1; var cb = (int)(bi.biHeight * bi.biWidth * bi.biBitCount / 8); //8 is bits per byte. bi.biSizeImage = (uint)(((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight); //bi.biXPelsPerMeter = XPelsPerMeter; //bi.biYPelsPerMeter = YPelsPerMeter; bi.biXPelsPerMeter = 96; bi.biYPelsPerMeter = 96; var pBits = IntPtr.Zero; //Allocate memory for bitmap bits var pBI = Kernel32.LocalAlloc((uint)LocalMemoryFlags.LPTR, new UIntPtr(bi.biSize)); // Not sure if this needed - simply trying to keep marshaller happy Marshal.StructureToPtr(bi, pBI, false); //This will return IntPtr to actual DIB bits in pBits var hBmp = Gdi32.CreateDIBSection(hDc, ref pBI, 0, out pBits, IntPtr.Zero, 0); //Marshall back - now we have BitmapInfoHeader correctly filled in Marshal.PtrToStructure(pBI, bi); var biNew = (BitmapInfoHeader)Marshal.PtrToStructure(pBI, typeof(BitmapInfoHeader)); //Usual stuff var hOldBitmap = Gdi32.SelectObject(hMemDc, hBmp); //Grab bitmap var nRet = Gdi32.BitBlt(hMemDc, 0, 0, bi.biWidth, bi.biHeight, hDc, Left, Top, CopyPixelOperations.SourceCopy | CopyPixelOperations.CaptureBlt); // Allocate memory for a copy of bitmap bits var realBits = new byte[cb]; // And grab bits from DIBSestion data Marshal.Copy(pBits, realBits, 0, cb); //This simply creates valid bitmap file header, so it can be saved to disk var bfh = new BitmapFileHeader(); bfh.bfSize = (uint)cb + 0x36; // Size of header + size of Native.BitmapInfoHeader size of bitmap bits bfh.bfType = 0x4d42; //BM bfh.bfOffBits = 0x36; // var hdrSize = 14; var header = new byte[hdrSize]; BitConverter.GetBytes(bfh.bfType).CopyTo(header, 0); BitConverter.GetBytes(bfh.bfSize).CopyTo(header, 2); BitConverter.GetBytes(bfh.bfOffBits).CopyTo(header, 10); //Allocate enough memory for complete bitmap file var data = new byte[cb + bfh.bfOffBits]; //BITMAPFILEHEADER header.CopyTo(data, 0); //BitmapInfoHeader header = new byte[Marshal.SizeOf(bi)]; var pHeader = Kernel32.LocalAlloc((uint)LocalMemoryFlags.LPTR, new UIntPtr((uint)Marshal.SizeOf(bi))); Marshal.StructureToPtr(biNew, pHeader, false); Marshal.Copy(pHeader, header, 0, Marshal.SizeOf(bi)); Kernel32.LocalFree(pHeader); header.CopyTo(data, hdrSize); //Bitmap bits realBits.CopyTo(data, (int)bfh.bfOffBits); //Native.SelectObject(_compatibleDeviceContext, _oldBitmap); //Native.DeleteObject(_compatibleBitmap); //Native.DeleteDC(_compatibleDeviceContext); //Native.ReleaseDC(_desktopWindow, _windowDeviceContext); Gdi32.SelectObject(hMemDc, hOldBitmap); Gdi32.DeleteObject(hBmp); Gdi32.DeleteDC(hMemDc); User32.ReleaseDC(IntPtr.Zero, hDc); }
/// <summary> /// Read the DIB of the indicated frame and report it as a /// raw <see cref="Image"/>. /// </summary> /// <param name="frameNumber">The zero based frame index.</param> /// <param name="imageStream">Must be closed by the caller when the /// returned <see cref="Image"/> is no longer needed.</param> /// <returns>The frame pixels or <i>null</i> if the indicated /// frame does not exist.</returns> public Image GetFrame( int frameNumber, out Stream imageStream ) { // Clear output imageStream = null; // Try to read DIB IntPtr rDIB = AVIStreamGetFrame( m_Frame, frameNumber ); // None if (IntPtr.Zero == rDIB) return null; // Read the sizes int fSize = BitmapFileHeader.SizeOf; short hSize = Marshal.ReadInt16( rDIB, 0 ); int iSize = Marshal.ReadInt32( rDIB, 20 ); // Create proper file header header BitmapFileHeader pHead = new BitmapFileHeader(); pHead.bfType = 0x4D42; pHead.bfReserved1 = 0; pHead.bfReserved2 = 0; pHead.bfOffBits = fSize + hSize; pHead.bfSize = pHead.bfOffBits + iSize; // Allocate buffer byte[] aBuf = new byte[pHead.bfSize]; // For a moment use unmanaged memory GCHandle hHead = GCHandle.Alloc( pHead, GCHandleType.Pinned ); // With cleanup try { // Copy header in Marshal.Copy( hHead.AddrOfPinnedObject(), aBuf, 0, fSize ); } finally { // Relax hHead.Free(); } // Copy DIB in Marshal.Copy( rDIB, aBuf, fSize, hSize + iSize ); // Create output stream MemoryStream pOut = new MemoryStream( aBuf, false ); // With cleanup try { // Load an image Image pRet = Image.FromStream( pOut ); // Report result imageStream = pOut; // Do not clear pOut = null; // Report return pRet; } finally { // Stream no longer used if (null != pOut) pOut.Close(); } }