<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="blog.xsl"?>
 <title>Creating TIFF Class F Images</title>
 <excerpt>The BFO PDF Library can create TIFF images from PDF using a number of compression algorithms, 
   including Group 4. If for some reason you want to use Group 3 compression you'll need to use a third 
   party library like JAI. This article shows you how.</excerpt>
 <tags>TIFF Fax AffineTransform JAI pdflibrary</tags>
We recently had a customer who needed to create TIFF Class F images from a PDF. TIFF class F is a subset of 
TIFF used for Faxing, and it has some very specific requirements, namely Group 3 compression and an image 
resolution of 204 x 196 dpi.
When creating black and white TIFF images, our <a href="/products/pdf/">PDF library</a> can only create the 
more modern (and smaller) Group 4, so some other approach was needed. The 
<a href="http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-client-419417.html" el="nofollow">
  JAI library</a> can create TIFF images in a number of configurations, so we thought we'd take a look.
Integrating with a third party library requires supplying the image as a <code>BufferedImage</code>, 
which you can retrieve very easily from the <code>PagePainter</code> class. Here was our first cut of the code:
<pre class="brush:java"><![CDATA[
import java.io.*;
import java.util.*;
import java.awt.image.*;
import javax.media.jai.*;
import com.sun.media.jai.codec.*;
import org.faceless.pdf2.*;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;

public class G3Test2 {

  public static void main(String[] args) throws Exception {
    PDF pdf = new PDF(new PDFReader(new File(args[0])));
    PDFParser parser = new PDFParser(pdf);

    // 1. Create a bi-level ColorModel - 0=white, 1=black
    // JAI requires it round this way for no good reason,
    // which is a shame as PDFParser.BLACKANDWHITE is this
    // but the other way around!
    byte[] b = new byte[] { -1, 0 };
    ColorModel model = new IndexColorModel(1, 2, b, b, b);

    int num = pdf.getNumberOfPages();
    BufferedImage[] images = new BufferedImage[num];
    for (int i=0;i < num;i++) {
      PagePainter painter = parser.getPagePainter(i);
      images[i] = getImage(painter, model);

    FileOutputStream out = new FileOutputStream("out.tif");
    TIFFEncodeParam param = new TIFFEncodeParam();
    ImageEncoder enc = 
        ImageCodec.createImageEncoder("TIFF", out, param);
    if (num > 1) {
      // Add subsequent pages using the odd approach
      // required by JAI.
      List therest = Arrays.asList(images).subList(1, num);

  static BufferedImage getImage(PagePainter painter,
  				ColorModel model, int dpi) {
    return painter.getImage(dpi, model);
This worked well, creating a Group 3 compressed image. However the resolution was 200x200dpi, not the required 204x196dpi.
The solution isn't necessarily obvious, but the approach is very flexible and shows the kind of tricks that can be done by supplying your own image to  <code>Graphics2D</code> object to the <code>PagePainter</code> class instead of relying on it to create one for you. Essentially we create an appropriate sized bitmap, scale its Graphics object appropriately and then paint the PDF to it. Here's the new <code>getImage</code> method.

<pre class="brush:java"><![CDATA[
static BufferedImage getImage(PagePainter painter,
        ColorModel model, int dpix, int dpiy) { 
  PDFPage page = painter.getPage();

  // Find size of image in pixels
  int w = Math.round(page.getWidth() * dpix / 72);
  int h = Math.round(page.getHeight() * dpiy / 72);
  WritableRaster r = Raster.createPackedRaster(
              DataBuffer.TYPE_BYTE, w, h, 1, 1, null);

  BufferedImage img = new BufferedImage(model, r, false, null);
  Graphics2D g = (Graphics2D)img.createGraphics();

  // Apply the anamorphic transform
  float dpi = (float)Math.max(dpix, dpiy);
  if (dpix!=dpiy) {
    g.transform(AffineTransform.getScaleInstance(dpix/dpi, dpiy/dpi));

  // Paint the area of the page we want to see.
  float[] box = page.getBox("ViewBox");
  painter.drawSubImage(g, box[0], box[1], box[2], box[3], dpi);
  return img;
Passing 204 and 196 as the resolution into that method will give an image of the correct size - the last thing we need to to is tell JAI to write the correct resolution units to the image. We added the lines in bold to the code:
<pre class="brush:java; highlight:[2,3,4,5,6,7,8]"><![CDATA[
TIFFField xres = new TIFFField(0x11A,
          TIFFField.TIFF_RATIONAL, 1,
          new long[][] { { 204, 1 } });
TIFFField yres = new TIFFField(0x11B,
          TIFFField.TIFF_RATIONAL, 1,
          new long[][] { { (196, 1 } });
param.setExtraFields(new TIFFField[] { xres, yres });
ImageEncoder enc =
    ImageCodec.createImageEncoder("TIFF", out, param);
Success! The resulting TIFF image is a Class F TIFF. You can download a complete, quick and dirty version of 
this code <a viewtext="true" href="PDFToClassF.java">here</a>.
<include xmlns="http://www.w3.org/2001/XInclude" href="comments.xml"/>