pdf links

PDF Rendering
Convert PDF to Image (.NET)
Convert PDF to image on Android (Xamarin)
Convert PDF to image on iOS (Xamarin)
Convert PDF to image in Windows Store apps (.NET)
Convert PDF to image in Windows Phone apps (.NET)
PDF to image in Universal Windows Store apps (.NET)
Free PDF Viewer control for Windows Forms (.NET)
How to integrate PDF Viewer control in WPF app (.NET)
Creating WPF PDF Viewer supporting bookmarks (.NET)
Cross-platform PDF Viewer using GTK# (MONO)
Silverlight PDF viewer control (Silverlight 5)
Multithreaded PDF rendering (.NET)
Convert pdf to image in Silverlight app (C# sample)
How to set fallback fonts for PDF rendering (C#)
Avoiding the out-of-memory exception on rendering (C#)
PDF viewer single page application (WebAPI, AngularJS)
PDF viewer control for Windows 10 universal applications
Use custom ICC profile for CMYK to RGB conversion
PDF layers - separate images, text, annotations, graphics

PDF Forms Creation PDF Security
Conversion to PDF/A
Other topics
PDF Document Manipulation
PDF Content Generation
Fixed and Flow layout document API (.NET)
Creation of grids and tables in PDF (C# sample)
How to create interactive documents using Actions (C# sample)
Text flow effects in PDF (C# sample)
How to generate ordered and bulleted lists in PDF (C# sample)
Convert HTML to PDF using flow layout API (C# sample)
How to use custom fonts for PDF generation (.NET)
Create document with differently sized pages (C#)
Create PDF documents using MONO (C#/MONO/Windows/OSX)
How to use background images for content elements (C#/PDF Kit/FlowLayout)
Add transparent images to PDF document (C#)
Draw round rect borders in PDF documents(C#)
ICC color profiles and and ICC based colors in PDF (C#)
How to use bidirectional and right to left text in PDF (C#)
Create PDF documents from XML templates (C# sample)
How to resize PDF pages and use custom stamps (C#)
Add header and footer to PDF page (.NET sample)
How to use clipping mask for drawing on PDF page
Fill graphics path with gradient brushes in PDF (Shadings)
Apitron PDF Kit and Rasterizer engine settings
Add layers to PDF page (optional content, C# sample)
How to create free text annotation with custom appearance

PDF Content Extraction
PDF Navigation

PDF to TIFF conversion
Contact us if you have a PDF related question and we'll cover it in our blog.

2016-11-30

Convert PDF to tiff using custom bitonal image conversion

Introduction

 

Sometimes default PDF to TIFF conversion doesn't provide the desired results, especially if it comes to black and white tiffs, containing so-called bitonal images. We've recently added a new mechanism into our Apitron PDF Rasterizer product which allows you to use custom bitonal image conversion implementation if you need it. See the sample below to see how it works.

The code

 

Provided code sample is a demo of custom bitonal conversion implementation and shows one of the possible ways to convert an RGB image to its black and white analog.

The idea is to scale the resulting image by the factory of 8 and put variably sized pixels consisting of black dots depending on the luminosity of  the source pixel. Thus one source pixel would correspond to a square formed by 64 black and white 1-bit pixels.

static void Main(string[] args)
{
    using (Stream inputStream = File.OpenRead("../../data/document.pdf"), 
        outputStream = File.Create("out.tiff"))
    {
        using (Document doc = new Document(inputStream))
        {
            doc.SaveToTiff(outputStream, new TiffRenderingSettings()
            {
                // set our conversion delegate
                ConvertToBitonal = MyConvertToBitonal
            });
        }
    }

    Process.Start("out.tiff");
}

private static byte[] MyConvertToBitonal(int width, int height, byte[] imageData, 
    out int resultingWidth, out int resultingHeight)
{
    // we will scale the resulting image,
    // each source pixel will correspond to 64 black and white pixels
    int scaleFactor = 8;
    resultingWidth = width * scaleFactor;
    resultingHeight = height * scaleFactor;

    // create resulting data buffer
    byte[] resultingImage = new byte[width * resultingHeight];
           
    double luminance;

    // black pixel goes first, lighter pixels follow
    byte[] pixel0 = new byte[] {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
    byte[] pixel1 = new byte[] {0x18, 0x3c, 0x7e, 0xFF, 0xFF, 0x7e, 0x3c, 0x18 };
    byte[] pixel2 = new byte[] {0, 0x18, 0x3c, 0x7e, 0x7e, 0x3c, 0x18, 0 };
    byte[] pixel3 = new byte[] {0, 0, 0x18, 0x3c, 0x3c, 0x18, 0, 0 };
    byte[] pixel4 = new byte[] {0, 0, 0, 0x18, 0x18, 0, 0, 0 };

           
    // iterate over the source pixels and modify bitonal image
    // according to own algorithm
    for (int y = 0, offsetY=0, stride=width*4; y < height; ++y, offsetY+=stride)
    {  
        // base offset for final pixel(s)
        int resultingPixelOffsetBase = y*width*scaleFactor;

        for (int x = 0, offsetX=0; x < width; ++x, offsetX+=4)
        {
            // read pixel data
            byte b = imageData[offsetY+offsetX];
            byte g = imageData[offsetY+offsetX+1];
            byte r = imageData[offsetY+offsetX+2];

            // calculate the luminance
            luminance = (0.2126*r + 0.7152*g + 0.0722*b);

            // based on the luminance we'll select which pixel to use
            // from the darkest one to the lightest
            if (luminance < 50)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel0, width);
            }
            else if (luminance<100)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel1, width);
            }
            else if(luminance <150)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel2, width);
            }
            else if (luminance<200)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel3, width);
            }
            else if (luminance < 250)
            {
                SetPixel(resultingImage, resultingPixelOffsetBase+x, pixel4, width);
            }
        }
    }

    return resultingImage;
}

/// Copies pixel data describing resulting pixel shape to the
/// resulting image
private static void SetPixel(byte[] resultingImage, int resultingPixelOffset, byte[] pixelData, 
int strideInBytes)
{
    for (int i = 0; i < pixelData.Length; ++i)
    {
        resultingImage[resultingPixelOffset + strideInBytes*i] = pixelData[i];
    }
}


The source file looks as follows:


Pic.1 Source PDF document
Pic. 1 Source PDF document

And the converted document is on the image below:

Converted bitonal tiff
Pic. 2 Converted bitonal tiff

If you zoom in you'll see that the image consists of variable black dots that create the smooth gradient fill:

 

Pic.3 Bitonal image
Pic.3 Bitonal image

 

 

The complete code sample can be found in our github repo.

 

 Conclusion 

 

The Apitron PDF Rasterizer is a powerful and extensible cross platform library that can be used to handle all PDF rendering tasks with incredible ease and quality. If you have any questions just send us an email and we'll be happy to help you.