Code example combine several pdf files into MO:DCA-P complient afp file.

This java code splits pdf files in a pdf per page and then embeds these pages into an afp file. (each pdf forms a different AFP document)

The program makes use of the afplib courtesy of yan74 and the itextpdf libraries from the Belgian company itext. The code is published according to the iText Software AGPL License. See https://itextpdf.com/AGPL for the details.

See also the content of the pom.xml file.

Improvements consist of rewriting this code more Object Oriented.

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.IOException;

import java.io.InputStream;
import java.util.Arrays;
 
import org.afplib.AfpBuilder;
import org.afplib.afplib.AfplibFactory;
import org.afplib.afplib.AfplibPackage;
import org.afplib.afplib.BAG;
import org.afplib.afplib.BDT;
import org.afplib.afplib.BOC;
import org.afplib.afplib.BOG;
import org.afplib.afplib.BPG;
import org.afplib.afplib.CDD;
import org.afplib.afplib.CDDXocBase;
import org.afplib.afplib.CDDYocBase;
import org.afplib.afplib.CGCSGID;
import org.afplib.afplib.DescriptorPosition;
import org.afplib.afplib.EAG;
import org.afplib.afplib.EDT;
import org.afplib.afplib.EOC;
import org.afplib.afplib.EOG;
import org.afplib.afplib.EPG;
import org.afplib.afplib.FullyQualifiedName;
import org.afplib.afplib.FullyQualifiedNameFQNFormat;
import org.afplib.afplib.FullyQualifiedNameFQNType;
import org.afplib.afplib.MCD;
import org.afplib.afplib.MCDRG;
import org.afplib.afplib.MCF;
import org.afplib.afplib.MCFRG;
import org.afplib.afplib.MappingOption;
import org.afplib.afplib.MappingOptionMapValue;
import org.afplib.afplib.MeasurementUnits;
import org.afplib.afplib.MeasurementUnitsXoaBase;
import org.afplib.afplib.MeasurementUnitsYoaBase;
import org.afplib.afplib.OBD;
import org.afplib.afplib.OBP;
import org.afplib.afplib.OBPRGLength;
import org.afplib.afplib.OBPRefCSys;
import org.afplib.afplib.OBPXoaOrent;
import org.afplib.afplib.OBPXocaOrent;
import org.afplib.afplib.OBPYoaOrent;
import org.afplib.afplib.OBPYocaOrent;
import org.afplib.afplib.OCD;
import org.afplib.afplib.ObjectAreaSize;
import org.afplib.afplib.ObjectAreaSizeSizeType;
import org.afplib.afplib.ObjectClassification;
import org.afplib.afplib.ObjectClassificationObjClass;
import org.afplib.afplib.PGD;
import org.afplib.afplib.PGDXpgBase;
import org.afplib.afplib.PGDYpgBase;
import org.afplib.afplib.PTD;
import org.afplib.afplib.PTDXPBASE;
import org.afplib.afplib.PTDYPBASE;
import org.afplib.afplib.ResourceLocalIdentifier;
import org.afplib.afplib.ResourceLocalIdentifierResType;
import org.afplib.base.SF;
import org.afplib.io.AfpOutputStream;
 
import com.itextpdf.io.source.ByteArrayOutputStream;
import com.itextpdf.kernel.geom.AffineTransform;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfNumber;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
 
/**
 * Demonstration on how to create a new AFP file with a page and some text on
 * it.
 *
 */
public class CombinePDFToAFP {
 
    private static int MAX_OCD_SIZE = 30000;
    
    private static void insertBlankPage(AfpOutputStream out, int page) {
           BPG bpg = new AfpBuilder()
                                                         // Begin Page
                    .with(AfplibPackage.BPG__PAGE_NAME, "BLANK"+page)
                    .create(BPG.class);
 
        
           BAG bag = new AfpBuilder()                                            // Active Environment Group
                    .create(BAG.class);
           
 
            PGD pgd = new AfpBuilder()                                            // Page descriptor
                    .with(AfplibPackage.PGD__XPG_BASE, PGDXpgBase.CONST10INCHES_VALUE)
                    .with(AfplibPackage.PGD__YPG_BASE, PGDYpgBase.CONST10INCHES_VALUE)
                    .with(AfplibPackage.PGD__XPG_UNITS, 14400)                    // 1440 dpi resolution
                    .with(AfplibPackage.PGD__YPG_UNITS, 14400)                    // 1440 dpi resolution
                    .with(AfplibPackage.PGD__XPG_SIZE, 11906)                    // 210 mm
                    .with(AfplibPackage.PGD__YPG_SIZE, 16838)                    // 297 mm
                    .with(AfplibPackage.PGD__RESERVED, 0)
                    .create(PGD.class);
 
            PTD ptd = new AfpBuilder()                                            // Page Text Descriptor
                    .with(AfplibPackage.PTD__XPBASE, PTDXPBASE.CONST_TENINCHES_VALUE)
                    .with(AfplibPackage.PTD__YPBASE, PTDYPBASE.CONST_TENINCHES_VALUE)
                    .with(AfplibPackage.PTD__XPUNITVL, 14400)                    // 1440 dpi resolution
                    .with(AfplibPackage.PTD__YPUNITVL, 14400)                    // 1440 dpi resolution
                    .with(AfplibPackage.PTD__XPEXTENT, 11906)                    // 210 mm
                    .with(AfplibPackage.PTD__YPEXTENT, 16838)                    // 297 mm
                    .create(PTD.class);
            
            EAG eag = new AfpBuilder()  // End Active Area Group
                    .create(EAG.class);
            EPG epg = new AfpBuilder()                                            // End Page
                    .create(EPG.class);
 
 
        try {
         for(SF sf : Arrays.asList(bpg, bag, pgd, ptd, eag, epg)) {  
                 out.writeStructuredField(sf);
         }
        } catch (IOException e) {
            System.out.println("IO Error!");
            e.printStackTrace();
        }
    }
 
    public void createAFPwithPage(AfpOutputStream out, String pat) throws IOException {
 
        EDT edt = new AfpBuilder() // End Document
                .create(EDT.class);
 
        int dpi = 360;
        int xsize = 2976;
        int ysize = 4209;
        int pageCount = 0;
 
        BAG bag = new AfpBuilder() // Active Environment Group
                .create(BAG.class);
 
        MCF mcf = new AfpBuilder() // Map coded font
                .withMember(new AfpBuilder()
                        .withMember(new AfpBuilder()
                                .with(AfplibPackage.FULLY_QUALIFIED_NAME__FQN_TYPE,
                                        FullyQualifiedNameFQNType.CONST_CODE_PAGE_NAME_REFERENCE_VALUE)
                                .with(AfplibPackage.FULLY_QUALIFIED_NAME__FQN_FORMAT,
                                        FullyQualifiedNameFQNFormat.CONST_CHARACTERSTRING_VALUE)
                                .with(AfplibPackage.FULLY_QUALIFIED_NAME__FQ_NAME, "T1000395") // codepage
                                .create(FullyQualifiedName.class)) // Codepage
                                                                    // reference
                        .withMember(new AfpBuilder()
                                .with(AfplibPackage.FULLY_QUALIFIED_NAME__FQN_TYPE,
                                        FullyQualifiedNameFQNType.CONST_FONT_CHARACTER_SET_NAME_REFERENCE_VALUE)
                                .with(AfplibPackage.FULLY_QUALIFIED_NAME__FQN_FORMAT,
                                        FullyQualifiedNameFQNFormat.CONST_CHARACTERSTRING_VALUE)
                                .with(AfplibPackage.FULLY_QUALIFIED_NAME__FQ_NAME, "C1N20000") // Font
                                .create(FullyQualifiedName.class)) // Font
                                                                    // reference
                        .withMember(new AfpBuilder()
                                .with(AfplibPackage.RESOURCE_LOCAL_IDENTIFIER__RES_TYPE,
                                        ResourceLocalIdentifierResType.CONST_CODED_FONT_VALUE)
                                .with(AfplibPackage.EXTENDED_RESOURCE_LOCAL_IDENTIFIER__RES_LID, 1) // identifier
                                .create(ResourceLocalIdentifier.class))
                        .create(MCFRG.class))
                .create(MCF.class);
 
        PGD pgd = new AfpBuilder() // Page descriptor
                .with(AfplibPackage.PGD__XPG_BASE, PGDXpgBase.CONST10INCHES_VALUE)
                .with(AfplibPackage.PGD__YPG_BASE, PGDYpgBase.CONST10INCHES_VALUE)
                .with(AfplibPackage.PGD__XPG_UNITS, 14400) // 1440 dpi
                                                            // resolution
                .with(AfplibPackage.PGD__YPG_UNITS, 14400) // 1440 dpi
                                                            // resolution
                .with(AfplibPackage.PGD__XPG_SIZE, 11906) // 210 mm
                .with(AfplibPackage.PGD__YPG_SIZE, 16838) // 297 mm
                .with(AfplibPackage.PGD__RESERVED, 0).create(PGD.class);
 
        EAG eag = new AfpBuilder() // End Active Area Group
                .create(EAG.class);
        EPG epg = new AfpBuilder() // End Page
                .create(EPG.class);
 
        File folder = new File(".");
        File[] listOfFiles = folder.listFiles(new FileFilter() {
 
            public boolean accept(File pathname) {
                if (pathname.getName().startsWith(pat)) {
                    return pathname.getName().endsWith(".pdf") || pathname.isDirectory();
                } else
                    return false;
            }
        });
        for (int i = 0; i < listOfFiles.length; i++) {
            File inFile = listOfFiles[i];
            System.out.println(inFile);
 
            BDT bdt = new AfpBuilder() // Begin Document
                    .with(AfplibPackage.BDT__DOC_NAME, "DOC" + i)
                    .withMember(new AfpBuilder().with(AfplibPackage.CGCSGID__GCSGID, 65535)
                            .with(AfplibPackage.CGCSGID__CPGID, 500) // Encode
                                                                        // all
                                                                        // CHARs
                                                                        // in
                                                                        // EBCDIC
                            .create(CGCSGID.class))
                    .create(BDT.class);
 
            out.writeStructuredField(bdt);
            // Open the pdf
            InputStream pdfin = new BufferedInputStream(new FileInputStream(inFile));
            PdfReader reader = new PdfReader(pdfin);
            @SuppressWarnings("resource")
            PdfDocument pdfDoc = new PdfDocument(reader);
            int n = pdfDoc.getNumberOfPages();
            //System.out.println("Pages=" + n);
 
    
 
            //System.out.println("N-pages=" + n);
            float A4height = 842.0f;
            float A4width = 595.0f;
            int rotation;
            for (int pg = 1; pg <= n; pg++) {
                ++pageCount;
 
                BPG bpg = new AfpBuilder() // Begin Page
                        .with(AfplibPackage.BPG__PAGE_NAME, "PAGE" + pageCount+"-"+pg).create(BPG.class);
 
                for (SF sf : Arrays.asList(bpg, bag, mcf, pgd, eag)) {
                    out.writeStructuredField(sf);
                }
                //System.out.println("Page=" + pg);
 
                
 
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                PdfWriter writer = new PdfWriter(baos);
                PdfDocument pdfOut = new PdfDocument(writer);
                PdfNumber pdfrotation;
 
                PdfCanvas canvas;
                PdfFormXObject page;
                Rectangle rect = new Rectangle(0, 0, A4width, A4height);
                PageSize ps = new PageSize(rect);
                canvas = new PdfCanvas(pdfOut.addNewPage(ps));
 
                page = pdfDoc.getPage(pg).copyAsFormXObject(pdfOut);
                page.flush();
 
                pdfrotation = page.getPdfObject().getAsNumber(PdfName.Rotate);
                if (pdfrotation != null) {
                    rotation = pdfrotation.intValue();
                    rotation = 0; // Just delete the rotation....
                }
 
                float height = page.getHeight();
                float width = page.getWidth();
 
                // System.out.println("height="+height);
                // System.out.println("width="+width);
 
                float scale = 1.0f; // must be calculated... To Do.
                float hscale;
                float wscale;
 
                if (width > height) {
                    wscale = A4height / width;
                    hscale = A4width / height;
                    rotation = 90;
                } else {
                    wscale = A4width / width;
                    hscale = A4height / height;
                    rotation = 0;
                }
                if (wscale < hscale)
                    scale = wscale;
                else if (hscale < wscale)
                    scale = hscale;
                float[] matrix = new float[6];
 
                // System.out.println("scale="+scale);
 
                pdfrotation = page.getPdfObject().getAsNumber(PdfName.Rotate);
                if (pdfrotation != null) {
                    rotation = pdfrotation.intValue();
                    rotation = 0; // Just delete the rotation....
                }
 
                // System.out.println("rotation="+rotation);
 
                AffineTransform at = new AffineTransform();
                if (rotation == 0)
                    at = AffineTransform.getTranslateInstance(0, 0);
                else if (rotation == 90) {
                    at.concatenate(AffineTransform.getRotateInstance(Math.toRadians(-rotation)));
                    at.concatenate(AffineTransform.getTranslateInstance(-A4height, 0));
 
                }
 
                // rescale the page such that it fits a single A4
                at.concatenate(AffineTransform.getScaleInstance(scale, scale));
 
                at.getMatrix(matrix);
 
                // Perform a matrix transform of the page such that the page is
                // oriented in portrait mode.
 
                canvas.addXObject(page, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
 
                page.put(PdfName.Rotate, new PdfNumber(0));
                page.flush(); // portrait
                canvas.saveState();
                canvas.restoreState();
 
                pdfOut.close();
 
                canvas.release();
 
                // Open the file we have just written
                //System.out.println("length=" + baos.size());
                InputStream stream = new ByteArrayInputStream(baos.toByteArray());
                writer.close();
                //System.out.println("Available=" + stream.available());
 
                pdfoc(dpi, xsize, ysize, stream, out, "PAGE" + pageCount + "-" + pg, i); // Create
                // a afp
                // document
                // per
                // pdf page
 
                stream.close();
                out.writeStructuredField(epg);
            }
            if ((n ==1) || (n % 2)!=0 ) {
                ++pageCount;
                insertBlankPage(out, pageCount);
            }
            out.writeStructuredField(edt);
 
                
            
 
            pdfin.close();
 
        } // for
        out.flush();
        out.close();
    }
 
    private void pdfoc(int dpi, int xsize, int ysize, InputStream fin, AfpOutputStream out, String ovlName, int i)
            throws IOException {
 
        //System.out.println("pdfoc" + ovlName);
 
        out.writeStructuredField(new AfpBuilder()
                .withMember(new AfpBuilder()
                        .with(AfplibPackage.OBJECT_CLASSIFICATION__OBJ_CLASS,
                                ObjectClassificationObjClass.CONST_TIMEINVARIANT_VALUE)
                        .with(AfplibPackage.OBJECT_CLASSIFICATION__STRUC_FLGS, 64512)
                        .with(AfplibPackage.OBJECT_CLASSIFICATION__REG_OBJ_ID,
                                new byte[] { 0x06, 0x07, 0x2b, 0x12, 0x00, 0x04, 0x01, 0x01, 0x3f, 0x00, 0x00, 0x00,
                                        0x00, 0x00, 0x00, 0x00 })
                        .create(ObjectClassification.class))
                .with(AfplibPackage.BOC__OBJ_CNAME, ovlName).create(BOC.class));
 
        out.writeStructuredField(new AfpBuilder().create(BOG.class));
 
        out.writeStructuredField(new AfpBuilder()
                .withMember(new AfpBuilder().with(AfplibPackage.DESCRIPTOR_POSITION__DES_POS_ID, 1)
                        .create(DescriptorPosition.class))
                .withMember(new AfpBuilder()
                        .with(AfplibPackage.MEASUREMENT_UNITS__XOA_BASE, MeasurementUnitsXoaBase.CONST10INCHES_VALUE)
                        .with(AfplibPackage.MEASUREMENT_UNITS__YOA_BASE, MeasurementUnitsYoaBase.CONST10INCHES_VALUE)
                        .with(AfplibPackage.MEASUREMENT_UNITS__XOA_UNITS, dpi * 10)
                        .with(AfplibPackage.MEASUREMENT_UNITS__YOA_UNITS, dpi * 10).create(MeasurementUnits.class))
                .withMember(new AfpBuilder()
                        .with(AfplibPackage.OBJECT_AREA_SIZE__SIZE_TYPE,
                                ObjectAreaSizeSizeType.CONST_OBJECT_AREA_SIZE_VALUE)
                        .with(AfplibPackage.OBJECT_AREA_SIZE__XOA_SIZE, xsize)
                        .with(AfplibPackage.OBJECT_AREA_SIZE__YOA_SIZE, ysize).create(ObjectAreaSize.class))
                .create(OBD.class));
 
        out.writeStructuredField(new AfpBuilder().with(AfplibPackage.OBP__OA_POS_ID, 1)
                .with(AfplibPackage.OBP__RG_LENGTH, OBPRGLength.CONST_LENGTH23_VALUE)
                .with(AfplibPackage.OBP__XOA_OSET, 0).with(AfplibPackage.OBP__YOA_OSET, 0)
                .with(AfplibPackage.OBP__XOA_ORENT, OBPXoaOrent.CONST0DEGREES_VALUE)
                .with(AfplibPackage.OBP__YOA_ORENT, OBPYoaOrent.CONST90DEGREES_VALUE)
                .with(AfplibPackage.OBP__XOCA_OSET, 0).with(AfplibPackage.OBP__YOCA_OSET, 0)
                .with(AfplibPackage.OBP__XOCA_ORENT, OBPXocaOrent.CONST0DEGREES_VALUE)
                .with(AfplibPackage.OBP__YOCA_ORENT, OBPYocaOrent.CONST90DEGREES_VALUE)
                .with(AfplibPackage.OBP__REF_CSYS, OBPRefCSys.CONST_PAGE_OR_OVERLAY_VALUE).create(OBP.class));
 
        out.writeStructuredField(
                new AfpBuilder()
                        .withMember(
                                new AfpBuilder().withMember(new AfpBuilder()
                                        .with(AfplibPackage.MAPPING_OPTION__MAP_VALUE,
                                                MappingOptionMapValue.CONST_POSITIONANDTRIM_VALUE)
                                        .create(MappingOption.class)).create(MCDRG.class))
                        .create(MCD.class));
 
        out.writeStructuredField(new AfpBuilder().with(AfplibPackage.CDD__XOC_BASE, CDDXocBase.CONST10IN_VALUE)
                .with(AfplibPackage.CDD__YOC_BASE, CDDYocBase.CONST10IN_VALUE)
                .with(AfplibPackage.CDD__XOC_UNITS, dpi * 10).with(AfplibPackage.CDD__YOC_UNITS, dpi * 10)
                .with(AfplibPackage.CDD__XOC_SIZE, xsize).with(AfplibPackage.CDD__XOC_SIZE, ysize).create(CDD.class));
 
        out.writeStructuredField(new AfpBuilder().create(EOG.class));
 
        byte[] buffer = new byte[MAX_OCD_SIZE];
        int l;
        while ((l = fin.read(buffer)) > 0) {
            //System.out.println("l=" + l);
            OCD ocd = AfplibFactory.eINSTANCE.createOCD();
            byte[] c = new byte[l];
            System.arraycopy(buffer, 0, c, 0, l);
            ocd.setObjCdat(c);
            out.writeStructuredField(ocd);
            //System.out.print(".");
        }
        out.writeStructuredField(new AfpBuilder().with(AfplibPackage.EOC__OBJ_CNAME, ovlName).create(EOC.class));
 
    }
 
    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println("Proper Usage is: java -jar CombinePDFToAFP pattern outfile.afp");
            System.exit(0);
        }
        try {
            String pat = args[0];
            String outFile = args[1];
            new CombinePDFToAFP().createAFPwithPage(new AfpOutputStream(new FileOutputStream(outFile)), pat);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
}