Search in sources :

Example 26 with PDRectangle

use of com.tom_roush.pdfbox.pdmodel.common.PDRectangle in project PdfBox-Android by TomRoush.

the class PDAcroForm method flatten.

/**
 * This will flatten the specified form fields.
 *
 * <p>Flattening a form field will take the current appearance and make that part
 * of the pages content stream. All form fields and annotations associated are removed.</p>
 *
 * <p>Invisible and hidden fields will be skipped and will not become part of the
 * page content stream</p>
 *
 * @param fields
 * @param refreshAppearances if set to true the appearances for the form field widgets will be updated
 * @throws IOException
 */
public void flatten(List<PDField> fields, boolean refreshAppearances) throws IOException {
    // Nothing to flatten if there are no fields provided
    if (fields.isEmpty()) {
        return;
    }
    if (!refreshAppearances && getNeedAppearances()) {
        Log.w("PdfBox-Android", "acroForm.getNeedAppearances() returns true, " + "visual field appearances may not have been set");
        Log.w("PdfBox-Android", "call acroForm.refreshAppearances() or " + "use the flatten() method with refreshAppearances parameter");
    }
    // from the XFA content into a static PDF.
    if (xfaIsDynamic()) {
        Log.w("PdfBox-Android", "Flatten for a dynamix XFA form is not supported");
        return;
    }
    // refresh the appearances if set
    if (refreshAppearances) {
        refreshAppearances(fields);
    }
    // the content stream to write to
    PDPageContentStream contentStream;
    // get the widgets per page
    Map<COSDictionary, Set<COSDictionary>> pagesWidgetsMap = buildPagesWidgetsMap(fields);
    // preserve all non widget annotations
    for (PDPage page : document.getPages()) {
        Set<COSDictionary> widgetsForPageMap = pagesWidgetsMap.get(page.getCOSObject());
        // indicates if the original content stream
        // has been wrapped in a q...Q pair.
        boolean isContentStreamWrapped = false;
        List<PDAnnotation> annotations = new ArrayList<PDAnnotation>();
        for (PDAnnotation annotation : page.getAnnotations()) {
            if (widgetsForPageMap != null && !widgetsForPageMap.contains(annotation.getCOSObject())) {
                annotations.add(annotation);
            } else if (!annotation.isInvisible() && !annotation.isHidden() && annotation.getNormalAppearanceStream() != null && annotation.getNormalAppearanceStream().getBBox() != null) {
                contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, !isContentStreamWrapped);
                isContentStreamWrapped = true;
                PDAppearanceStream appearanceStream = annotation.getNormalAppearanceStream();
                PDFormXObject fieldObject = new PDFormXObject(appearanceStream.getCOSObject());
                contentStream.saveGraphicsState();
                // translate the appearance stream to the widget location if there is
                // not already a transformation in place
                boolean needsTranslation = resolveNeedsTranslation(appearanceStream);
                // scale the appearance stream - mainly needed for images
                // in buttons and signatures
                boolean needsScaling = resolveNeedsScaling(annotation, page.getRotation());
                Matrix transformationMatrix = new Matrix();
                boolean transformed = false;
                if (needsTranslation) {
                    transformationMatrix.translate(annotation.getRectangle().getLowerLeftX(), annotation.getRectangle().getLowerLeftY());
                    transformed = true;
                }
                // PDFBOX-4693: field could have a rotation matrix
                Matrix m = appearanceStream.getMatrix();
                int angle = (int) Math.round(Math.toDegrees(Math.atan2(m.getShearY(), m.getScaleY())));
                int rotation = (angle + 360) % 360;
                if (needsScaling) {
                    PDRectangle bbox = appearanceStream.getBBox();
                    PDRectangle fieldRect = annotation.getRectangle();
                    float xScale;
                    float yScale;
                    if (rotation == 90 || rotation == 270) {
                        xScale = fieldRect.getWidth() / bbox.getHeight();
                        yScale = fieldRect.getHeight() / bbox.getWidth();
                    } else {
                        xScale = fieldRect.getWidth() / bbox.getWidth();
                        yScale = fieldRect.getHeight() / bbox.getHeight();
                    }
                    Matrix scalingMatrix = Matrix.getScaleInstance(xScale, yScale);
                    transformationMatrix.concatenate(scalingMatrix);
                    transformed = true;
                }
                if (transformed) {
                    contentStream.transform(transformationMatrix);
                }
                contentStream.drawForm(fieldObject);
                contentStream.restoreGraphicsState();
                contentStream.close();
            }
        }
        page.setAnnotations(annotations);
    }
    // remove the fields
    removeFields(fields);
    // remove XFA for hybrid forms
    dictionary.removeItem(COSName.XFA);
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) COSDictionary(com.tom_roush.pdfbox.cos.COSDictionary) PDPage(com.tom_roush.pdfbox.pdmodel.PDPage) PDAppearanceStream(com.tom_roush.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream) PDAnnotation(com.tom_roush.pdfbox.pdmodel.interactive.annotation.PDAnnotation) ArrayList(java.util.ArrayList) COSArrayList(com.tom_roush.pdfbox.pdmodel.common.COSArrayList) Matrix(com.tom_roush.pdfbox.util.Matrix) PDFormXObject(com.tom_roush.pdfbox.pdmodel.graphics.form.PDFormXObject) PDPageContentStream(com.tom_roush.pdfbox.pdmodel.PDPageContentStream) PDRectangle(com.tom_roush.pdfbox.pdmodel.common.PDRectangle)

Example 27 with PDRectangle

use of com.tom_roush.pdfbox.pdmodel.common.PDRectangle in project PdfBox-Android by TomRoush.

the class PDFTemplateCreator method buildPDF.

/**
 * Build a PDF with a visible signature step by step, and return it as a stream.
 *
 * @param properties
 * @return InputStream
 * @throws IOException
 */
public InputStream buildPDF(PDVisibleSignDesigner properties) throws IOException {
    Log.i("PdfBox-Android", "pdf building has been started");
    PDFTemplateStructure pdfStructure = pdfBuilder.getStructure();
    // we create array of [Text, ImageB, ImageC, ImageI]
    pdfBuilder.createProcSetArray();
    // create page
    pdfBuilder.createPage(properties);
    PDPage page = pdfStructure.getPage();
    // create template
    pdfBuilder.createTemplate(page);
    PDDocument template = pdfStructure.getTemplate();
    // create /AcroForm
    pdfBuilder.createAcroForm(template);
    PDAcroForm acroForm = pdfStructure.getAcroForm();
    // AcroForm contains signature fields
    pdfBuilder.createSignatureField(acroForm);
    PDSignatureField pdSignatureField = pdfStructure.getSignatureField();
    // create signature
    // TODO
    // The line below has no effect with the CreateVisibleSignature example.
    // The signature field is needed as a "holder" for the /AP tree,
    // but the /P and /V PDSignatureField entries are ignored by PDDocument.addSignature
    pdfBuilder.createSignature(pdSignatureField, page, "");
    // that is /AcroForm/DR entry
    pdfBuilder.createAcroFormDictionary(acroForm, pdSignatureField);
    // create AffineTransform
    pdfBuilder.createAffineTransform(properties.getTransform());
    AffineTransform transform = pdfStructure.getAffineTransform();
    // rectangle, formatter, image. /AcroForm/DR/XObject contains that form
    pdfBuilder.createSignatureRectangle(pdSignatureField, properties);
    pdfBuilder.createFormatterRectangle(properties.getFormatterRectangleParameters());
    PDRectangle bbox = pdfStructure.getFormatterRectangle();
    pdfBuilder.createSignatureImage(template, properties.getImage());
    // create form stream, form and  resource.
    pdfBuilder.createHolderFormStream(template);
    PDStream holderFormStream = pdfStructure.getHolderFormStream();
    pdfBuilder.createHolderFormResources();
    PDResources holderFormResources = pdfStructure.getHolderFormResources();
    pdfBuilder.createHolderForm(holderFormResources, holderFormStream, bbox);
    // that is /AP entry the appearance dictionary.
    pdfBuilder.createAppearanceDictionary(pdfStructure.getHolderForm(), pdSignatureField);
    // inner form stream, form and resource (holder form contains inner form)
    pdfBuilder.createInnerFormStream(template);
    pdfBuilder.createInnerFormResource();
    PDResources innerFormResource = pdfStructure.getInnerFormResources();
    pdfBuilder.createInnerForm(innerFormResource, pdfStructure.getInnerFormStream(), bbox);
    PDFormXObject innerForm = pdfStructure.getInnerForm();
    // inner form must be in the holder form as we wrote
    pdfBuilder.insertInnerFormToHolderResources(innerForm, holderFormResources);
    // Image form is in this structure: /AcroForm/DR/FRM/Resources/XObject/n2
    pdfBuilder.createImageFormStream(template);
    PDStream imageFormStream = pdfStructure.getImageFormStream();
    pdfBuilder.createImageFormResources();
    PDResources imageFormResources = pdfStructure.getImageFormResources();
    pdfBuilder.createImageForm(imageFormResources, innerFormResource, imageFormStream, bbox, transform, pdfStructure.getImage());
    pdfBuilder.createBackgroundLayerForm(innerFormResource, bbox);
    // now inject procSetArray
    pdfBuilder.injectProcSetArray(innerForm, page, innerFormResource, imageFormResources, holderFormResources, pdfStructure.getProcSet());
    COSName imageFormName = pdfStructure.getImageFormName();
    COSName imageName = pdfStructure.getImageName();
    COSName innerFormName = pdfStructure.getInnerFormName();
    // now create Streams of AP
    pdfBuilder.injectAppearanceStreams(holderFormStream, imageFormStream, imageFormStream, imageFormName, imageName, innerFormName, properties);
    pdfBuilder.createVisualSignature(template);
    pdfBuilder.createWidgetDictionary(pdSignatureField, holderFormResources);
    InputStream in = getVisualSignatureAsStream(pdfStructure.getVisualSignature());
    Log.i("PdfBox-Android", "stream returning started, size= " + in.available());
    // we must close the document
    template.close();
    // return result of the stream
    return in;
}
Also used : PDPage(com.tom_roush.pdfbox.pdmodel.PDPage) COSName(com.tom_roush.pdfbox.cos.COSName) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) PDDocument(com.tom_roush.pdfbox.pdmodel.PDDocument) AffineTransform(com.tom_roush.harmony.awt.geom.AffineTransform) PDResources(com.tom_roush.pdfbox.pdmodel.PDResources) PDFormXObject(com.tom_roush.pdfbox.pdmodel.graphics.form.PDFormXObject) PDRectangle(com.tom_roush.pdfbox.pdmodel.common.PDRectangle) PDAcroForm(com.tom_roush.pdfbox.pdmodel.interactive.form.PDAcroForm) PDSignatureField(com.tom_roush.pdfbox.pdmodel.interactive.form.PDSignatureField) PDStream(com.tom_roush.pdfbox.pdmodel.common.PDStream)

Example 28 with PDRectangle

use of com.tom_roush.pdfbox.pdmodel.common.PDRectangle in project PdfBox-Android by TomRoush.

the class PDVisibleSigBuilder method createFormatterRectangle.

@Override
public void createFormatterRectangle(int[] params) {
    PDRectangle formatterRectangle = new PDRectangle();
    formatterRectangle.setLowerLeftX(Math.min(params[0], params[2]));
    formatterRectangle.setLowerLeftY(Math.min(params[1], params[3]));
    formatterRectangle.setUpperRightX(Math.max(params[0], params[2]));
    formatterRectangle.setUpperRightY(Math.max(params[1], params[3]));
    pdfStructure.setFormatterRectangle(formatterRectangle);
    Log.i("PdfBox-Android", "Formatter rectangle has been created");
}
Also used : PDRectangle(com.tom_roush.pdfbox.pdmodel.common.PDRectangle)

Example 29 with PDRectangle

use of com.tom_roush.pdfbox.pdmodel.common.PDRectangle in project PdfBox-Android by TomRoush.

the class AppearanceGeneratorHelper method insertGeneratedAppearance.

/**
 * Generate and insert text content and clipping around it.
 */
private void insertGeneratedAppearance(PDAnnotationWidget widget, PDAppearanceStream appearanceStream, OutputStream output) throws IOException {
    PDPageContentStream contents = new PDPageContentStream(field.getAcroForm().getDocument(), appearanceStream, output);
    PDRectangle bbox = resolveBoundingBox(widget, appearanceStream);
    // Acrobat calculates the left and right padding dependent on the offset of the border edge
    // This calculation works for forms having been generated by Acrobat.
    // The minimum distance is always 1f even if there is no rectangle being drawn around.
    float borderWidth = 0;
    if (widget.getBorderStyle() != null) {
        borderWidth = widget.getBorderStyle().getWidth();
    }
    PDRectangle clipRect = applyPadding(bbox, Math.max(1f, borderWidth));
    PDRectangle contentRect = applyPadding(clipRect, Math.max(1f, borderWidth));
    contents.saveGraphicsState();
    // Acrobat always adds a clipping path
    contents.addRect(clipRect.getLowerLeftX(), clipRect.getLowerLeftY(), clipRect.getWidth(), clipRect.getHeight());
    contents.clip();
    // get the font
    PDFont font = defaultAppearance.getFont();
    if (font == null) {
        throw new IllegalArgumentException("font is null, check whether /DA entry is incomplete or incorrect");
    }
    if (font.getName().contains("+")) {
        Log.w("PdfBox-Android", "Font '" + defaultAppearance.getFontName().getName() + "' of field '" + field.getFullyQualifiedName() + "' contains subsetted font '" + font.getName() + "'");
        Log.w("PdfBox-Android", "This may bring trouble with PDField.setValue(), PDAcroForm.flatten() or " + "PDAcroForm.refreshAppearances()");
        Log.w("PdfBox-Android", "You should replace this font with a non-subsetted font:");
        Log.w("PdfBox-Android", "PDFont font = PDType0Font.load(doc, new FileInputStream(fontfile), false);");
        Log.w("PdfBox-Android", "acroForm.getDefaultResources().put(COSName.getPDFName(\"" + defaultAppearance.getFontName().getName() + "\", font);");
    }
    // calculate the fontSize (because 0 = autosize)
    float fontSize = defaultAppearance.getFontSize();
    if (fontSize == 0) {
        fontSize = calculateFontSize(font, contentRect);
    }
    // options
    if (field instanceof PDListBox) {
        insertGeneratedListboxSelectionHighlight(contents, appearanceStream, font, fontSize);
    }
    // start the text output
    contents.beginText();
    // write font and color from the /DA string, with the calculated font size
    defaultAppearance.writeTo(contents, fontSize);
    // calculate the y-position of the baseline
    float y;
    // calculate font metrics at font size
    float fontScaleY = fontSize / FONTSCALE;
    float fontBoundingBoxAtSize = font.getBoundingBox().getHeight() * fontScaleY;
    float fontCapAtSize = font.getFontDescriptor().getCapHeight() * fontScaleY;
    float fontDescentAtSize = font.getFontDescriptor().getDescent() * fontScaleY;
    if (field instanceof PDTextField && ((PDTextField) field).isMultiline()) {
        y = contentRect.getUpperRightY() - fontBoundingBoxAtSize;
    } else {
        // Adobe shows the text 'shiftet up' in case the caps don't fit into the clipping area
        if (fontCapAtSize > clipRect.getHeight()) {
            y = clipRect.getLowerLeftY() + -fontDescentAtSize;
        } else {
            // calculate the position based on the content rectangle
            y = clipRect.getLowerLeftY() + (clipRect.getHeight() - fontCapAtSize) / 2;
            // check to ensure that ascents and descents fit
            if (y - clipRect.getLowerLeftY() < -fontDescentAtSize) {
                float fontDescentBased = -fontDescentAtSize + contentRect.getLowerLeftY();
                float fontCapBased = contentRect.getHeight() - contentRect.getLowerLeftY() - fontCapAtSize;
                y = Math.min(fontDescentBased, Math.max(y, fontCapBased));
            }
        }
    }
    // show the text
    float x = contentRect.getLowerLeftX();
    // chars
    if (shallComb()) {
        insertGeneratedCombAppearance(contents, appearanceStream, font, fontSize);
    } else if (field instanceof PDListBox) {
        insertGeneratedListboxAppearance(contents, appearanceStream, contentRect, font, fontSize);
    } else {
        PlainText textContent = new PlainText(value);
        AppearanceStyle appearanceStyle = new AppearanceStyle();
        appearanceStyle.setFont(font);
        appearanceStyle.setFontSize(fontSize);
        // Adobe Acrobat uses the font's bounding box for the leading between the lines
        appearanceStyle.setLeading(font.getBoundingBox().getHeight() * fontScaleY);
        PlainTextFormatter formatter = new PlainTextFormatter.Builder(contents).style(appearanceStyle).text(textContent).width(contentRect.getWidth()).wrapLines(isMultiLine()).initialOffset(x, y).textAlign(field.getQ()).build();
        formatter.format();
    }
    contents.endText();
    contents.restoreGraphicsState();
    contents.close();
}
Also used : PDFont(com.tom_roush.pdfbox.pdmodel.font.PDFont) PDPageContentStream(com.tom_roush.pdfbox.pdmodel.PDPageContentStream) PDRectangle(com.tom_roush.pdfbox.pdmodel.common.PDRectangle)

Example 30 with PDRectangle

use of com.tom_roush.pdfbox.pdmodel.common.PDRectangle in project PdfBox-Android by TomRoush.

the class PDAcroForm method resolveNeedsScaling.

/**
 * Check if there needs to be a scaling transformation applied.
 *
 * @param annotation
 * @param rotation
 * @return the need for a scaling transformation.
 */
private boolean resolveNeedsScaling(PDAnnotation annotation, int rotation) {
    PDAppearanceStream appearanceStream = annotation.getNormalAppearanceStream();
    // Check if there is a transformation within the XObjects content
    PDResources resources = appearanceStream.getResources();
    if (resources != null && resources.getXObjectNames().iterator().hasNext()) {
        return true;
    }
    PDRectangle bbox = appearanceStream.getBBox();
    PDRectangle fieldRect = annotation.getRectangle();
    if (rotation == 90 || rotation == 270) {
        return Float.compare(bbox.getWidth(), fieldRect.getHeight()) != 0 || Float.compare(bbox.getHeight(), fieldRect.getWidth()) != 0;
    } else {
        return Float.compare(bbox.getWidth(), fieldRect.getWidth()) != 0 || Float.compare(bbox.getHeight(), fieldRect.getHeight()) != 0;
    }
}
Also used : PDAppearanceStream(com.tom_roush.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream) PDResources(com.tom_roush.pdfbox.pdmodel.PDResources) PDRectangle(com.tom_roush.pdfbox.pdmodel.common.PDRectangle)

Aggregations

PDRectangle (com.tom_roush.pdfbox.pdmodel.common.PDRectangle)82 IOException (java.io.IOException)19 PDResources (com.tom_roush.pdfbox.pdmodel.PDResources)13 PDAppearanceContentStream (com.tom_roush.pdfbox.pdmodel.PDAppearanceContentStream)12 PDColor (com.tom_roush.pdfbox.pdmodel.graphics.color.PDColor)11 Matrix (com.tom_roush.pdfbox.util.Matrix)11 COSArray (com.tom_roush.pdfbox.cos.COSArray)10 PDPage (com.tom_roush.pdfbox.pdmodel.PDPage)10 PDAppearanceStream (com.tom_roush.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream)9 Path (android.graphics.Path)8 AffineTransform (com.tom_roush.harmony.awt.geom.AffineTransform)7 PDFormXObject (com.tom_roush.pdfbox.pdmodel.graphics.form.PDFormXObject)6 COSBase (com.tom_roush.pdfbox.cos.COSBase)5 PDDocument (com.tom_roush.pdfbox.pdmodel.PDDocument)5 PDPageContentStream (com.tom_roush.pdfbox.pdmodel.PDPageContentStream)5 COSDictionary (com.tom_roush.pdfbox.cos.COSDictionary)4 COSName (com.tom_roush.pdfbox.cos.COSName)4 PDExtendedGraphicsState (com.tom_roush.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState)4 PDAnnotationTextMarkup (com.tom_roush.pdfbox.pdmodel.interactive.annotation.PDAnnotationTextMarkup)4 PDAnnotationWidget (com.tom_roush.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget)4