Display alternate images for view and print in a PDF document

A question on StackOverflow.com asked if it is possible to have 2 alternate versions of an image in a PDF file, one for display and other for print.
Several solutions were given: optional contentform fields or alternate images. In the article below we’ll show how these solutions can be implemented using XFINIUM.PDF library and how they compare to each other.

1. Optional content

First proposed solution was to use optional content groups. This solution requires to create 2 optional content groups. One group is marked for view only while the other group is marked for print only. Each image is drawn inside the corresponding group.

// Create a document and a page. For demo purposes the page size matches the images size.
PdfFixedDocument document = new PdfFixedDocument();
PdfPage page = document.Pages.Add();
page.Width = 800;
page.Height = 600;

// Create an optional content group that is always visible but never printed.
PdfOptionalContentGroup ocgView = new PdfOptionalContentGroup();
ocgView.VisibilityState = PdfOptionalContentGroupVisibilityState.AlwaysVisible;
ocgView.PrintState = PdfOptionalContentGroupPrintState.NeverPrint;
ocgView.DefaultState = PdfOptionalContentGroupDefaultState.On;

// Begin the optional content group in the page content.
page.Graphics.BeginOptionalContentGroup(ocgView);
// Create the view only image and draw it on the page.
PdfPngImage viewImage = new PdfPngImage("multiversion-view.png");
page.Graphics.DrawImage(viewImage, 0, 0, page.Width, page.Height);
// Close the optional content group. 
// Everything inside this group will be displayed only in the viewer.
page.Graphics.EndOptionalContentGroup();

// Create an optional content group that is never visible but always printed.
PdfOptionalContentGroup ocgPrint = new PdfOptionalContentGroup();
ocgPrint.PrintState = PdfOptionalContentGroupPrintState.AlwaysPrint;
ocgPrint.VisibilityState = PdfOptionalContentGroupVisibilityState.NeverVisible;
ocgPrint.DefaultState = PdfOptionalContentGroupDefaultState.Off;

// Begin the optional content group in the page content.
page.Graphics.BeginOptionalContentGroup(ocgPrint);
// Create the view print image and draw it on the page.
PdfPngImage printImage = new PdfPngImage("multiversion-print.png");
// The print only image is drawn in the same position but it can be drawn 
// anywhere on the page since it is not linked in any way to the view only image.
page.Graphics.DrawImage(printImage, 0, 0, page.Width, page.Height);
// Close the optional content group. 
// Everything inside this group will not show in the view and will be printed only.
page.Graphics.EndOptionalContentGroup();

// Save the file.
document.Save("multiversionimages-optionalcontent.pdf");
' Create a document and a page. For demo purposes the page size matches the images size.
Dim document As New PdfFixedDocument()
Dim page As PdfPage = document.Pages.Add()
page.Width = 800
page.Height = 600

' Create an optional content group that is always visible but never printed.
Dim ocgView As New PdfOptionalContentGroup()
ocgView.VisibilityState = PdfOptionalContentGroupVisibilityState.AlwaysVisible
ocgView.PrintState = PdfOptionalContentGroupPrintState.NeverPrint
ocgView.DefaultState = PdfOptionalContentGroupDefaultState.[On]

' Begin the optional content group in the page content.
page.Graphics.BeginOptionalContentGroup(ocgView)
' Create the view only image and draw it on the page.
Dim viewImage As New PdfPngImage("multiversion-view.png")
page.Graphics.DrawImage(viewImage, 0, 0, page.Width, page.Height)
' Close the optional content group. 
' Everything inside this group will be displayed only in the viewer.
page.Graphics.EndOptionalContentGroup()

' Create an optional content group that is never visible but always printed.
Dim ocgPrint As New PdfOptionalContentGroup()
ocgPrint.PrintState = PdfOptionalContentGroupPrintState.AlwaysPrint
ocgPrint.VisibilityState = PdfOptionalContentGroupVisibilityState.NeverVisible
ocgPrint.DefaultState = PdfOptionalContentGroupDefaultState.Off

' Begin the optional content group in the page content.
page.Graphics.BeginOptionalContentGroup(ocgPrint)
' Create the view print image and draw it on the page.
Dim printImage As New PdfPngImage("multiversion-print.png")
' The print only image is drawn in the same position but it can be drawn 
' anywhere on the page since it is not linked in any way to the view only image.
page.Graphics.DrawImage(printImage, 0, 0, page.Width, page.Height)
' Close the optional content group. 
' Everything inside this group will not show in the view and will be printed only.
page.Graphics.EndOptionalContentGroup()

' Save the file.
document.Save("multiversionimages-optionalcontent.pdf")

 2. Form fields

The second solution suggested to use form fields with custom appearances. This solution requires to create a form field, we use textboxes, for each image, put the form fields at the position on the page where the image should appear and then draw the images on fields’ appearances. One field is marked as visible but not printable while the other field is marked as hidden but printable.

// Create a document and a page. For demo purposes the page size matches the images size.
PdfFixedDocument document = new PdfFixedDocument();
PdfPage page = document.Pages.Add();
page.Width = 800;
page.Height = 600;

// Create the field that will include the view only image.
// The field is marked as visible but non printable and it covers the entire page.
PdfTextBoxField viewField = new PdfTextBoxField("view");
viewField.ReadOnly = true;
viewField.Widgets[0].Visibility = PdfFieldWidgetVisibility.VisibleNonPrintable;
viewField.Widgets[0].VisualRectangle = 
    new PdfVisualRectangle(0, 0, page.Width, page.Height);
page.Fields.Add(viewField);

// Create a custom appearance for the field.
// Draw the image to cover the entire appearance and 
// then attach the appearance to the field.
PdfAnnotationAppearance viewFieldAppearance = 
    new PdfAnnotationAppearance(page.Width, page.Height);
PdfPngImage viewImage = new PdfPngImage("multiversion-view.png");
viewFieldAppearance.Graphics.DrawImage(viewImage, 
    0, 0, viewFieldAppearance.Width, viewFieldAppearance.Height);
viewField.Widgets[0].NormalAppearance = viewFieldAppearance;

// Create the field that will include the print only image.
// The field is marked as hidden but printable and it covers the entire page.
PdfTextBoxField printField = new PdfTextBoxField("print");
printField.ReadOnly = true;
printField.Widgets[0].Visibility = PdfFieldWidgetVisibility.HiddenPrintable;
printField.Widgets[0].VisualRectangle = 
    new PdfVisualRectangle(0, 0, page.Width, page.Height);
page.Fields.Add(printField);

// Create a custom appearance for the field.
// Draw the image to cover the entire appearance and 
// then attach the appearance to the field.
PdfAnnotationAppearance printFieldAppearance = 
    new PdfAnnotationAppearance(page.Width, page.Height);
PdfPngImage printImage = new PdfPngImage("multiversion-print.png");
printFieldAppearance.Graphics.DrawImage(printImage, 
    0, 0, printFieldAppearance.Width, printFieldAppearance.Height);
printField.Widgets[0].NormalAppearance = printFieldAppearance;

// Save the file.
document.Save("multiversionimages-formfields.pdf");
' Create a document and a page. For demo purposes the page size matches the images size.
Dim document As New PdfFixedDocument()
Dim page As PdfPage = document.Pages.Add()
page.Width = 800
page.Height = 600

' Create the field that will include the view only image.
' The field is marked as visible but non printable and it covers the entire page.
Dim viewField As New PdfTextBoxField("view")
viewField.[ReadOnly] = True
viewField.Widgets(0).Visibility = PdfFieldWidgetVisibility.VisibleNonPrintable
viewField.Widgets(0).VisualRectangle = New PdfVisualRectangle(0, 0, page.Width, page.Height)
page.Fields.Add(viewField)

' Create a custom appearance for the field.
' Draw the image to cover the entire appearance and 
' then attach the appearance to the field.
Dim viewFieldAppearance As New PdfAnnotationAppearance(page.Width, page.Height)
Dim viewImage As New PdfPngImage("multiversion-view.png")
viewFieldAppearance.Graphics.DrawImage(viewImage, 0, 0, viewFieldAppearance.Width, viewFieldAppearance.Height)
viewField.Widgets(0).NormalAppearance = viewFieldAppearance

' Create the field that will include the print only image.
' The field is marked as hidden but printable and it covers the entire page.
Dim printField As New PdfTextBoxField("print")
printField.[ReadOnly] = True
printField.Widgets(0).Visibility = PdfFieldWidgetVisibility.HiddenPrintable
printField.Widgets(0).VisualRectangle = New PdfVisualRectangle(0, 0, page.Width, page.Height)
page.Fields.Add(printField)

' Create a custom appearance for the field.
' Draw the image to cover the entire appearance and 
' then attach the appearance to the field.
Dim printFieldAppearance As New PdfAnnotationAppearance(page.Width, page.Height)
Dim printImage As New PdfPngImage("multiversion-print.png")
printFieldAppearance.Graphics.DrawImage(printImage, 0, 0, printFieldAppearance.Width, printFieldAppearance.Height)
printField.Widgets(0).NormalAppearance = printFieldAppearance

' Save the file.
document.Save("multiversionimages-formfields.pdf")

3. Alternate images

The third solution recommends a PDF feature that solves exactly the requirement described in the question: pdf alternate images. PDF alternate images allow to attach an image to another image and mark the attached image to be used as default for printing. The code below creates an alternate image from the print only image and attaches it to the view only image. In this scenario the only the view image is drawn on the page and when the document is printed the viewer application replaces the image with the print only image.

// Create a document and a page. For demo purposes the page size matches the images size.
PdfFixedDocument document = new PdfFixedDocument();
PdfPage page = document.Pages.Add();
page.Width = 800;
page.Height = 600;

// Load the print only image and create an alternate image from it.
// The alternate image is marked as default for printing.
PdfPngImage printImage = new PdfPngImage("multiversion-print.png");
PdfAlternateImage alternateImage = new PdfAlternateImage(printImage);
alternateImage.DefaultForPrinting = true;
PdfAlternateImageCollection alternateImages = new PdfAlternateImageCollection();
alternateImages.Add(alternateImage);

// Create the view only image and attach the alternate image to it.
PdfPngImage viewImage = new PdfPngImage("multiversion-view.png");
viewImage.AlternateImages = alternateImages;
// The view only image is drawn on the page.
page.Graphics.DrawImage(viewImage, 0, 0, page.Width, page.Height);

// Save the file.
document.Save("multiversionimages-alternateimages.pdf");
' Create a document and a page. For demo purposes the page size matches the images size.
Dim document As New PdfFixedDocument()
Dim page As PdfPage = document.Pages.Add()
page.Width = 800
page.Height = 600

' Load the print only image and create an alternate image from it.
' The alternate image is marked as default for printing.
Dim printImage As New PdfPngImage("multiversion-print.png")
Dim alternateImage As New PdfAlternateImage(printImage)
alternateImage.DefaultForPrinting = True
Dim alternateImages As New PdfAlternateImageCollection()
alternateImages.Add(alternateImage)

' Create the view only image and attach the alternate image to it.
Dim viewImage As New PdfPngImage("multiversion-view.png")
viewImage.AlternateImages = alternateImages
' The view only image is drawn on the page.
page.Graphics.DrawImage(viewImage, 0, 0, page.Width, page.Height)

' Save the file.
document.Save("multiversionimages-alternateimages.pdf")

 Conclusions

At the end you might ask what is the recommended solution? The answer is: it depends. PDF files created with solutions 1 and 3 are printed correctly only by Adobe Reader and a few other applications while the PDF files created with solution 2 are printed correctly by a wider range of applications (this is merely an observation, not a documented scientific study). However, the problem with solution 2 is that the form fields are always on top of page content so you cannot have the images drawn behind text or some other vector graphics and if page content is extracted for creating n-up PDF pages the images in the form fields will not be included.
So choose the solution based on your actual requirements and the possible consumers of the PDF files.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.