Embedding Flex/Flash into PDF

Recently, I’ve been working on a process of embedding an interactive Flash .swf file (compiled from a Flex application) into a PDF for distribution. I’ve managed to get this to work using the iText library created by Bruno Lowagie, which allows me to embed the swf file as a screen annotation in the PDF. There are however, a couple of limitations:

  • Printing: It’s not possible to print the annotation using the built in Acrobat print function. It is possible to provide an image associated with the annotation that is printed in its place, but I’ll leave this as an exercise for the reader. Built in Flex printing is supported.
  • Application size: For the Flex application deployed on a webpage, I typically use the following:
    <mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" width="100%" height="100%">

    However, a bug in the implementation of the Flash Player plug-in inside Acrobat Reader meant that the actual size of the Flex application depended upon the start up size of the Acrobat window. To fix this, I needed to exactly specify the size (at A4 dimensions):

    <Application xmlns:mx="http://www.macromedia.com/2003/mxml" width="842" height="595">

I believe that embedding Flex applications into a PDF will be easier with Acrobat 9, but until then, you may find the following code useful. You can download the library file here and the example code here. Please note that these files are available for you to use under the Apache 2 licence.

Library source:

/**
* Created on 04/05/2008
*
* Flex PDF Creator
*
* Author: Aaron Watkins (aaronDOTwatkinsATgoannaconsultDOTcoDOTuk)
* Website: http://www.goannaconsult.co.uk
*
* Copyright [Aaron Watkins]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.goannaconsult.pdf;

import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
import java.io.*;

public class FlexPDFCreator {
private Document doc;
private PdfWriter writer;
private String outputFile;
private Rectangle r;
private int numPages = 0;

private static final String FLASH_MIME_TYPE = "application/x-shockwave-flash";

public FlexPDFCreator(String outputFile, Rectangle dims) {
doc = new Document(dims);
this.outputFile = outputFile;
r = new Rectangle(0, 0, dims.getWidth(), dims.getHeight());
}

public FlexPDFCreator(String outputFile) {
this(outputFile, PageSize.A4);
}

public void open() throws DocumentException, FileNotFoundException {
writer = null;
numPages = 0;

writer = PdfWriter.getInstance(doc, new FileOutputStream(outputFile));
doc.open();
}

public void close() {
doc.close();
}

public void addFlashPage(String swfFile, String title) throws IOException {
if (numPages++ != 0)
doc.newPage();

writer.addAnnotation(PdfAnnotation.createScreen(writer, r, swfFile,
PdfFileSpecification.fileEmbedded(writer, swfFile, title, null, false), FLASH_MIME_TYPE, true));
}
}

Example Source code:

/**
* Created on 04/05/2008
*
* Flex PDF Creator
*
* Author: Aaron Watkins (aaronDOTwatkinsATgoannaconsultDOTcoDOTuk)
* Website: http://www.goannaconsult.co.uk
*
* Copyright [Aaron Watkins]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import com.goannaconsult.pdf.FlexPDFCreator;

public class FlexPDFCreatorExample {

private static final int ARG_INPUT = 0;
private static final int ARG_TITLE = 1;
private static final int ARG_OUTPUT = 2;
private static final int NUM_ARGS = 3;

public static void usage() {
System.out.println("java -cp iText-2.1.1.jar FlexPDFCreatorExample InputFile Title OutputFile");
System.exit(1);
}

public static void main(String[] args) {
if (args.length != NUM_ARGS)
usage();

FlexPDFCreator pdf = null;
try {
pdf = new FlexPDFCreator(args[ARG_OUTPUT]);
pdf.open();
pdf.addFlashPage(args[ARG_INPUT], args[ARG_TITLE]);
pdf.close();
} catch (Exception e) {
e.printStackTrace();
if (pdf != null)
pdf.close();
System.exit(1);
}

System.exit(0);
}

}

9 Responses to “Embedding Flex/Flash into PDF”

  1. Bruno Lowagie Says:

    [...] The author explains some of the limitations inherent to the current version of Adobe Reader he encountered. A must-read blogpost! [...]

  2. CialisEl Says:

    Usefool post, thx

  3. Nidhi Says:

    Hello,
    i am able to embed swf file into pdf but i am not able to view the file.
    When i open the pdf file it pops the up the message as no player available to play the file.

    I tried all the possible solution available at different sites.

    Just can anyone help me out how to solve the issue.

    My code is

    import java.awt.Graphics2D;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.net.MalformedURLException;

    import com.lowagie.text.Document;
    import com.lowagie.text.DocumentException;
    import com.lowagie.text.Element;
    import com.lowagie.text.Image;
    import com.lowagie.text.PageSize;
    import com.lowagie.text.Paragraph;
    import com.lowagie.text.Rectangle;
    import com.lowagie.text.pdf.DefaultFontMapper;
    import com.lowagie.text.pdf.PdfAnnotation;
    import com.lowagie.text.pdf.PdfAppearance;
    import com.lowagie.text.pdf.PdfContentByte;
    import com.lowagie.text.pdf.PdfDictionary;
    import com.lowagie.text.pdf.PdfFileSpecification;
    import com.lowagie.text.pdf.PdfName;
    import com.lowagie.text.pdf.PdfNumber;
    import com.lowagie.text.pdf.PdfObject;
    import com.lowagie.text.pdf.PdfOutline;
    import com.lowagie.text.pdf.PdfPage;
    import com.lowagie.text.pdf.PdfStream;
    import com.lowagie.text.pdf.PdfTemplate;
    import com.lowagie.text.pdf.PdfWriter;

    public class Sample {
    private static final String FLASH_MIME_TYPE = “application/x-shockwave-flash”;
    private static final String FLAGS_PRINT =”1″;
    public static void main(String args[]) {
    Rectangle r;

    Document doc = new Document(PageSize.A4, 50, 50, 50, 50);
    try {
    r = new Rectangle(0, 0, 50, 50);
    PdfWriter writer = PdfWriter.getInstance(doc,new FileOutputStream(“ITextTest.pdf”));

    doc.open();
    doc.newPage();

    String swfFile=”Bar2D.swf”;
    PdfFileSpecification spec = PdfFileSpecification.fileEmbedded(writer, swfFile, “Post Event Report”, null);
    PdfAnnotation annot = PdfAnnotation.createScreen(writer, r, swfFile, spec, “application/x-shockwave-flash”, true);

    annot.put(PdfName.F, new PdfNumber(FLAGS_PRINT));
    int flag=PdfAnnotation.FLAGS_PRINT;
    annot.put(PdfName.F, new PdfNumber(flag));
    PdfContentByte pdfcontentbyte = writer.getDirectContent();
    PdfTemplate printing = pdfcontentbyte.createTemplate(750F, 400F);

    annot.setAppearance(PdfName.N, printing.createAppearance(750F, 400F));
    writer.addAnnotation(annot);

    doc.close();
    } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (DocumentException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (MalformedURLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }

    }

  4. Abhishek Says:

    I am using .NET, can anyone post .NET code for this.

  5. D.Lak Says:

    It is very useful. Thanks.

  6. Anish Says:

    Hi, i am trying to embed a swf file in a pdf using itext 5 and i want to pass my xml file as a parameter or by some other means to swf file embedded so that it can use it and generate charts….

    Here i am attaching my code.

    package com.huawei.embedflash;

    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.Reader;
    import java.io.StringWriter;
    import java.io.Writer;

    import com.itextpdf.text.Document;
    import com.itextpdf.text.DocumentException;
    import com.itextpdf.text.Rectangle;
    import com.itextpdf.text.pdf.PdfAnnotation;
    import com.itextpdf.text.pdf.PdfContentByte;
    import com.itextpdf.text.pdf.PdfDeveloperExtension;
    import com.itextpdf.text.pdf.PdfFileSpecification;
    import com.itextpdf.text.pdf.PdfIndirectReference;
    import com.itextpdf.text.pdf.PdfName;
    import com.itextpdf.text.pdf.PdfObject;
    import com.itextpdf.text.pdf.PdfTemplate;
    import com.itextpdf.text.pdf.PdfWriter;
    import com.itextpdf.text.pdf.richmedia.RichMediaActivation;
    import com.itextpdf.text.pdf.richmedia.RichMediaAnnotation;
    import com.itextpdf.text.pdf.richmedia.RichMediaConfiguration;
    import com.itextpdf.text.pdf.richmedia.RichMediaInstance;
    import com.itextpdf.text.pdf.richmedia.RichMediaParams;

    class EmbedParam {

    private static final String xmlString=” “;

    EmbedParam() {
    Document doc = new Document();
    try {
    FileOutputStream fos = new FileOutputStream(“result1232.pdf”);
    PdfWriter writer = PdfWriter.getInstance(doc, fos);
    writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
    writer.addDeveloperExtension(PdfDeveloperExtension.ADOBE_1_7_EXTENSIONLEVEL3);
    doc.open();
    RichMediaAnnotation media = new RichMediaAnnotation(writer,new Rectangle(50, 800, 800, 800));
    PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(writer,
    “Column3D.swf”, “result1232.pdf”, null);
    PdfIndirectReference asset = media.addAsset(“Column3D.swf”, fs);
    media.addAsset(“Column3D.swf”, fs);
    RichMediaConfiguration config = new RichMediaConfiguration(PdfName.FLASH);
    RichMediaInstance instance = new RichMediaInstance(PdfName.FLASH);

    RichMediaParams flashVars = new RichMediaParams();

    String vars = “&dataXml=”.concat(xmlString);
    flashVars.setFlashVars(vars);
    System.out.println(flashVars);

    instance.setParams(flashVars);
    instance.setAsset(asset);
    config.addInstance(instance);
    PdfIndirectReference configRef = media.addConfiguration(config);
    RichMediaActivation activation = new RichMediaActivation();
    activation.setConfiguration(configRef);
    media.setActivation(activation);

    PdfAnnotation mediaanote = PdfAnnotation.createScreen(writer,
    new Rectangle(200f, 700f, 400f, 800f), “Column3D.swf”, fs,
    “application/x-shockwave-flash”, true);

    mediaanote.setFlags(PdfAnnotation.FLAGS_PRINT);

    writer.addAnnotation(mediaanote);

    doc.close();
    } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (DocumentException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } finally {
    doc.close();
    }
    }

    public String convertStreamToString(InputStream is)throws IOException
    {
    /*
    * To convert the InputStream to String we use the
    * Reader.read(char[] buffer) method. We iterate until the
    * Reader return -1 which means there’s no more data to
    * read. We use the StringWriter class to produce the string.
    */
    if (is != null)
    {
    Writer writer = new StringWriter();

    char[] buffer = new char[1024];
    try {
    Reader reader = new BufferedReader( new InputStreamReader(is, “UTF-8″));
    int n;
    while ((n = reader.read(buffer)) != -1) {
    writer.write(buffer, 0, n);
    }
    } finally {
    is.close();
    }
    return writer.toString();
    } else {
    return “”;
    }
    }

    public static void main(String[] args) {
    EmbedParam e = new EmbedParam();
    }

    }

    Please help me out with the code….Thanx in advance

  7. Anish Says:

    Ignore the method convertStringToStream(InputStream is)

  8. Jeff Winstron Says:

    This was very helpful. However, the Flex application that I’m embedding
    accesses a web service located on a server. When I attempt to load my data
    from the WebService. I receive the following exception.

    faultDetail = “Channel.Security.Error error Error #2048: Security sandbox violation:

    I have a crossdomain.xml file in the root directory of the webserver.
    Any help is greatly appreciate it.

  9. goanna Says:

    Unfortunately, I haven’t really pursued this (or worked with Flex) in the last 3 or so years, so won’t be able to help you with too many details. At the time of writing, I seem to remember that it was possible to access a web service, but there had to be explicit consent given. Perhaps Acrobat has just been tightened down a bit more… I’d be interested to know if you get past this