PDF to grayscale TIFF

In the .NET framework the support for grayscale bitmaps is a bit puzzling. If you use bitmaps with format PixelFormat.Format16bppGrayScale you may get memory exceptions, which in fact means that this format is not supported. However, there is a way to convert PDF to grayscale Tiff in C# using PDFRasterizer.NET.

.NET: System.Drawing.Imaging.PixelFormats

In System.Drawing.Imaging, the PixelFormat.Format16bppGrayScale is defined in the .NET framework but it is not supported. Second, the is not even a definition for 8 bits per pixel grayscale bitmaps. So at first it looks impossible to create grayscale tiff file with 8, 16 or any other number of bits per pixel.

You may think that the color matrix may offer a usable solution to this (see this link), but in this context this is not the case. It only converts the colored pixels into gray, but it does not discard the Red, Green And Blues color channels.

So you end up with a gray image with the size of a color image.

In a interesting blog written by Lucian Wischik (link) demonstrates how use grayscale images.

For this purpose grayscale functionality is used that is present in GDI but is absent from the standard .NET framework. This works fine but you end up with a lot of code.

.NET: System.Windows.Media.PixelFormats

The PixelFormats class (note the ‘s’ on the end) however does offer a lot of grayscale options, like Gray2 (2 bits per pixel), Gray 4, Gray8 and Gray16. This option can be used in the FormatConvertedBitmap class, which cooperates nicely with the TiffBitmapEncoder or the JpegBitmapEncoder class. We can use these to convert a color-bitmap that is generated by PDFRasterizer into a grayscale bitmap and write this e.g. to a tiff file.

Code sample to convert PDF to grayscale TIFF in C# .NET

The following code sample that converts a PDF document to a multipage grayscale demonstrates this:

using ( FileStream file = new FileStream(pathToPdfDocument, FileMode.Open, FileAccess.Read))
{ 
  document = new Document( file );
}

//
// convert PDF via RGB bitmaps to grayscale tiff using the TiffBitmapEncoder
//
const float dpi = 300.00f;
const float scale = dpi/72;
var grayTiffStream = new FileStream("../../out_gray16bpp.tiff", FileMode.Create);
var tiffEncoder = new TiffBitmapEncoder();
tiffEncoder.Compression = TiffCompressOption.Zip;

var nPages = document.Pages.Count;
for (var i = 0; i < nPages; i++)
{
  var pdfPage = document.Pages[i];
  var rgbBitmap = new Bitmap((int) (pdfPage.Width/72.0*dpi), (int) (pdfPage.Height/72.0*dpi));
  var rgbGraphics = Graphics.FromImage(rgbBitmap);
  rgbGraphics.ScaleTransform(scale, scale);
  pdfPage.Draw(rgbGraphics);
  var rgbBitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                        rgbBitmap.GetHbitmap(),
                        IntPtr.Zero,
                        Int32Rect.Empty,
                        BitmapSizeOptions.FromEmptyOptions());
  var grayBitmap = new FormatConvertedBitmap();
  grayBitmap.BeginInit();
  grayBitmap.Source = rgbBitmapSource;
  grayBitmap.DestinationFormat = PixelFormats.Gray16;
  grayBitmap.EndInit();
  tiffEncoder.Frames.Add(BitmapFrame.Create(grayBitmap));
}
tiffEncoder.Save(grayTiffStream);