2017-04-10 4 views
2

Je voudrais itext7 utiliser pour générer quelque chose comme ce document pdf:IText 7: Comment créer un mélange de texte et de pièces jointes au paragraphe?

the effect that I need

Mais je ne peux pas trouver une méthode pour y parvenir. Ce que je vois dans le tutoriel iText - clickable image should open ms word attachment ne peut pas placer les pièces jointes et le texte ensemble. Vous ne pouvez placer des pièces jointes que sur une page séparée. S'il est itext5, je fais comme ceci:

PdfAnnotation anno = PdfAnnotation.createFileAttachment(writer, null, fileDescribe, pdfFileSpecification); 
chunk.setAnnotation(anno); 
paragrah.add(chunk); 

Je peux donc ajouter du texte, l'annotation dans un paragraphe, mais tutoriel itext7 est le cas:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST)); 
    Rectangle rect = new Rectangle(36, 700, 100, 100); 
    PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdfDoc, PATH, null, "test.docx", null, null, false); 
    PdfAnnotation attachment = new PdfFileAttachmentAnnotation(rect, fs) 
      .setContents("Click me"); 

    PdfFormXObject xObject = new PdfFormXObject(rect); 
    ImageData imageData = ImageDataFactory.create(IMG); 
    PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc); 
    canvas.addImage(imageData, rect, true); 
    attachment.setNormalAppearance(xObject.getPdfObject()); 

    pdfDoc.addNewPage().addAnnotation(attachment); 
    pdfDoc.close(); 

quelqu'un peut me aider?

+0

Merci beaucoup! @mkl –

+0

Veuillez ne pas ajouter votre solution au corps de la question, postez-la plutôt comme réponse. – mkl

Répondre

2

Si j'ai bien compris, vous souhaitez ajouter une annotation parmi les autres éléments de disposition à votre flux de documents.

Il n'existe actuellement aucun moyen rapide d'y parvenir (comme la méthode setAnnotation dans iText5) actuellement dans iText7. Cependant, iText7 est assez flexible pour vous permettre de créer des éléments personnalisés et ne pas creuser très profondément dans le code.

La partie initiale sera la même que dans l'exemple actuel. Ici, une annotation lui-même est mis en place:

PdfDocument pdfDoc = new PdfDocument(new PdfWriter(DEST)); 
Rectangle rect = new Rectangle(36, 700, 50, 50); 
PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdfDoc, PATH, null, "test.docx", null, null, false); 
PdfAnnotation attachment = new PdfFileAttachmentAnnotation(rect, fs) 
     .setContents("Click me"); 

PdfFormXObject xObject = new PdfFormXObject(rect); 
ImageData imageData = ImageDataFactory.create(IMG); 
PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc); 
canvas.addImage(imageData, rect, true); 
attachment.setNormalAppearance(xObject.getPdfObject()); 

Alors, ce que nous voulons atteindre est d'être capable d'ajouter des éléments d'annotation personnalisée à la mise en page flux Document. Dans le meilleur des cas, le code ressemblerait à ceci:

Document document = new Document(pdfDoc); 
Paragraph p = new Paragraph("There are two").add(new AnnotationElement(attachment)).add(new Text("elements")); 
document.add(p); 
document.close(); 

Nous nous retrouvons maintenant avec la définition de la AnnotationElement et correspondant renderer. Élément lui-même n'a pas de logique spécifique à part de créer renderer personnalisé et en passant une annotation à elle:

private static class AnnotationElement extends AbstractElement<AnnotationElement> implements ILeafElement { 
    private PdfAnnotation annotation; 

    public AnnotationElement(PdfAnnotation annotation) { 
     this.annotation = annotation; 
    } 

    @Override 
    protected IRenderer makeNewRenderer() { 
     return new AnnotationRenderer(annotation); 
    } 
} 

La mise en œuvre de renderer a plus de code, mais ce qu'il qui est définit simplement la zone occupée sur layout et ajoute la annotation à la page sur draw. Veuillez noter que cela ne couvre pas tous les cas (par exemple, il n'y a pas assez d'espace pour une annotation), mais cela est plus que suffisant pour les cas simples et à des fins de démonstration.

private static class AnnotationRenderer extends AbstractRenderer implements ILeafElementRenderer { 
    private PdfAnnotation annotation; 

    public AnnotationRenderer(PdfAnnotation annotat) { 
     this.annotation = annotat; 
    } 

    @Override 
    public float getAscent() { 
     return annotation.getRectangle().toRectangle().getHeight(); 
    } 

    @Override 
    public float getDescent() { 
     return 0; 
    } 

    @Override 
    public LayoutResult layout(LayoutContext layoutContext) { 
     occupiedArea = layoutContext.getArea().clone(); 

     float myHeight = annotation.getRectangle().toRectangle().getHeight(); 
     float myWidth = annotation.getRectangle().toRectangle().getWidth(); 
     occupiedArea.getBBox().moveUp(occupiedArea.getBBox().getHeight() - myHeight).setHeight(myHeight); 
     occupiedArea.getBBox().setWidth(myWidth); 

     return new LayoutResult(LayoutResult.FULL, occupiedArea, null, null); 
    } 

    @Override 
    public void draw(DrawContext drawContext) { 
     super.draw(drawContext); 
     annotation.setRectangle(new PdfArray(occupiedArea.getBBox())); 
     drawContext.getDocument().getPage(occupiedArea.getPageNumber()).addAnnotation(annotation); 
    } 

    @Override 
    public IRenderer getNextRenderer() { 
     return new AnnotationRenderer(annotation); 
    } 
} 

S'il vous plaît noter que l'exemple est pour la version actuelle 7.0.3-SNAPSHOT. Peut-être ne fonctionne pas pour la version 7.0.2 encore parce que l'interface ILeafElementRenderer a été ajouté plus tard, mais il serait encore possible d'adapter le code à 7.0.2 si vraiment nécessaire.

+0

Vous pouvez essayer d'inclure ces classes dans la base de code itext. – mkl

+0

Je me demande, cependant, sont les coordonnées 'occupéArea' toujours donné dans le système de coordonnées utilisateur par défaut? Par exemple. si le sens d'écriture est inversé ... – mkl

+0

Hi @mkl. Voulez-vous dire les textes RTL? Dans le cas des textes RTL, la zone occupée est la même, mais le réordonnancement des glyphes a lieu et donc il ne concerne que l'ordre correct des glyphes à imprimer, mais les coordonnées de la zone occupée suivent la même logique et pour le cas LTR. Ou faites-vous référence à quelque chose d'autre comme des matrices de transformation? –

1

Merci pour votre réponse @Alexey Subach, en utilisant votre méthode, j'ai résolu mes propres problèmes. Parce que j'utilise la version 7.0.2-SNAPSHOT. Ainsi, dans la classe AnnotationRenderer fait un peu de changement:

public class AnnotationRenderer extends AbstractRenderer implements IRenderer { 

    private PdfAnnotation annotation; 

    public AnnotationRenderer(PdfAnnotation annotation) { 
    this.annotation = annotation; 
    } 

    public float getAscent(){ 
    return annotation.getRectangle().toRectangle().getHeight(); 
    } 

    public float getDescent(){ 
    return 0; 
    } 

    @Override 
    public LayoutResult layout(LayoutContext layoutContext) { 
    occupiedArea = layoutContext.getArea().clone(); 

    float myHeight = annotation.getRectangle().toRectangle().getHeight(); 
    float myWidth = annotation.getRectangle().toRectangle().getWidth(); 
    occupiedArea.getBBox().moveUp(occupiedArea.getBBox().getHeight() - myHeight).setHeight(myHeight); 
    occupiedArea.getBBox().setWidth(myWidth); 

    return new LayoutResult(LayoutResult.FULL, occupiedArea, null, null); 
    } 

    @Override 
    public IRenderer getNextRenderer() { 
    return new AnnotationRenderer(annotation); 
    } 

    @Override 
    public void draw(DrawContext drawContext) { 
     super.draw(drawContext); 
    annotation.setRectangle(new PdfArray(occupiedArea.getBBox())); 
    drawContext.getDocument().getPage(occupiedArea.getPageNumber()).addAnnotation(annotation); 
} 

}

Je viens itext touché bientôt, juste rencontré ce problème quand je pense qu'ils ne peuvent pas être en mesure de résoudre, mais heureusement obtenu votre aide.En fait, LayoutContext, occupiedArea, LayoutResult ces classes ne comprennent pas pour moi, je pense que j'ai besoin de regarder l'API pour en savoir plus.