If you want to convert a bitmap into a TIFF, than then you can use the code:
using (System.Drawing.Bitmap sourceBitmap = new System.Drawing.Bitmap(@"C:\Temp\Source.bmp")) { string outputFileName = @"C:\Temp\Destination.tiff"; if (System.IO.File.Exists(outputFileName)) { System.IO.File.Delete(outputFileName); } sourceBitmap.Save(outputFileName, System.Drawing.Imaging.ImageFormat.Tiff); }
If you want to convert a bitmap to a 1bpp monochrome TIFF in C#, I found 4 options:
1. http://www.bobpowell.net/onebit.htm ( no P-Invoke required, but not as fast as other methods )
2. http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/9757dc94-11f3-4b30-a85c-cb9145eba12d (only when you are using WPF)
3. http://www.news2news.com/vfp/?example=493&ver=vcs&PHPSESSID=35494364de9987dfd2a9f3fe18f17565 (less code then option 4, but did not have time to investigate)
4. http://www.wischik.com/lu/programmer/1bpp.html
For the last options I cleanup some code:
using (System.Drawing.Bitmap sourceBitmap = new System.Drawing.Bitmap(@"C:\Temp\Source.bmp")) { using (Bitmap destinationBitmap = sourceBitmap.ConvertToMonochromeTiff()) { string outputFileName = @"C:\Temp\Destination.tiff"; if (System.IO.File.Exists(outputFileName)) { System.IO.File.Delete(outputFileName); } destinationBitmap.Save(outputFileName); } }
Where the ConvertToMonochromeTiff is an extension method to the System.Drawing.Bitmap type:
using System; using System.Drawing; namespace Rli.Extensions { /// <summary> /// Contains extensions methods to the System.Drawing.Bitmap type. /// </summary> public static class BitmapExtensions { #region P-Invoke [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr hObject); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern IntPtr GetDC(IntPtr hwnd); [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleDC(IntPtr hdc); [System.Runtime.InteropServices.DllImport("user32.dll")] public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc); [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern int DeleteDC(IntPtr hdc); [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); [System.Runtime.InteropServices.DllImport("gdi32.dll")] public static extern int BitBlt(IntPtr hdcDst, int xDst, int yDst, int w, int h, IntPtr hdcSrc, int xSrc, int ySrc, int rop); static int SRCCOPY = 0x00CC0020; [System.Runtime.InteropServices.DllImport("gdi32.dll")] static extern IntPtr CreateDIBSection(IntPtr hdc, ref BITMAPINFO bmi, uint Usage, out IntPtr bits, IntPtr hSection, uint dwOffset); static uint BI_RGB = 0; static uint DIB_RGB_COLORS = 0; [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct BITMAPINFO { public uint biSize; public int biWidth, biHeight; public short biPlanes, biBitCount; public uint biCompression, biSizeImage; public int biXPelsPerMeter, biYPelsPerMeter; public uint biClrUsed, biClrImportant; [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 256)] public uint[] cols; } static uint MAKERGB(int r, int g, int b) { return ((uint)(b & 255)) | ((uint)((r & 255) << 8)) | ((uint)((g & 255) << 16)); } #endregion /// <summary> /// Converts the given bitmap to a monochrome tiff bitmap. /// </summary> /// <param name="sourceBitmap">The source bitmap.</param> /// <returns></returns> public static Bitmap ConvertToMonochromeTiff(this Bitmap sourceBitmap) { Bitmap destination = null; int bpp = 1; // Amount of bits to use in pallet, for monochrome use 1 bit (0 = black, 1 = white). uint ncols = (uint)1 << bpp; // Use 2 colours (black and white) for monochrome tiff. int width = sourceBitmap.Width; int height = sourceBitmap.Height; uint size = (uint)(((width + 7) & 0xFFFFFFF8) * height / 8); uint[] pallet = new uint[256]; // Pallet has a fixed size 256, even when we are using fewer colours. pallet[0] = MAKERGB(0, 0, 0); // Create black pixel. pallet[1] = MAKERGB(255, 255, 255); // Create white pixel. BITMAPINFO bmi = new BITMAPINFO() // Create unmanaged monochrome bitmapinfo. { biSize = 40, // The size of the BITMAPHEADERINFO struct. biWidth = width, biHeight = height, biPlanes = 1, biBitCount = (short)bpp, // Amount of bits per pixel (1 for monochrome). biCompression = BI_RGB, biSizeImage = size, biXPelsPerMeter = 1000000, biYPelsPerMeter = 1000000, biClrUsed = ncols, biClrImportant = ncols, cols = pallet }; IntPtr sourceHbitmap = sourceBitmap.GetHbitmap(); // Convert bitmap to unmanaged HBitmap. IntPtr bits0; // Pointer to the raw bits that make up the bitmap. IntPtr destinationHbitmap = CreateDIBSection ( IntPtr.Zero, ref bmi, DIB_RGB_COLORS, out bits0, IntPtr.Zero, 0 ); // Create the indexed bitmap. IntPtr screenDC = GetDC(IntPtr.Zero); // Obtain the DC (= GDI equivalent of "Graphics" in GDI+) for the screen. IntPtr sourceDC = CreateCompatibleDC(screenDC); // Create a DC for the original hbitmap. SelectObject(sourceDC, sourceHbitmap); IntPtr destinationDC = CreateCompatibleDC(screenDC); // Create a DC for the monochrome hbitmap. SelectObject(destinationDC, destinationHbitmap); BitBlt(destinationDC, 0, 0, width, height, sourceDC, 0, 0, SRCCOPY); // Use GDI's BitBlt function to copy from original hbitmap into monocrhome bitmap. destination = System.Drawing.Bitmap.FromHbitmap(destinationHbitmap); // Convert this monochrome hbitmap back into a Bitmap. // Cleanup. DeleteDC(sourceDC); DeleteDC(destinationDC); ReleaseDC(IntPtr.Zero, screenDC); DeleteObject(sourceHbitmap); DeleteObject(destinationHbitmap); return destination; } } }
Hi,
Very good article. i learnt lot of things. I am using .Net Compact Framework 2.0/3.0 and getting error at fallowing line as OutOfMemoryException.
destination = System.Drawing.Bitmap.FromHbitmap(destinationHbitmap); // Convert this monochrome hbitmap back into a Bitmap.
Can you please help me to solve this ?
Thanks,
Siddeswara GM
Nice post! I did find that #2 above CAN be used within a C# console application if you include the WPF libraries (PresentationCore.dll and System.Xaml.dll I think). Then code like this can be used to generate pretty decent 1bpp TIF files:
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
encoder.Compression = TiffCompressOption.Ccitt4;
encoder.Frames.Add(BitmapFrame.Create(imgStream));
Mark
Can the above code be reused to convert to other formats such as Format24bppRgb, Format32bppRgb etc..