Aspose word 给每一页添加不同的图片

您好,我当前使用的Aspose.word 版本是23.6,我的需求是给每一页word文档中添加一个不同的图片,文档中包含文字和表格等信息,我当前是使用如下代码实现的,当word文档中如果是纯文本的时候没有问题,但是如果文档是包含整页的表格的话,就会添加图片失败,请问该如何修改代码?

package com.yexiang.practice.util;

import com.aspose.words.Document;
import com.aspose.words.EditingLanguage;
import com.aspose.words.HeaderFooter;
import com.aspose.words.HeaderFooterType;
import com.aspose.words.HorizontalAlignment;
import com.aspose.words.LayoutCollector;
import com.aspose.words.LoadOptions;
import com.aspose.words.Node;
import com.aspose.words.NodeCollection;
import com.aspose.words.NodeType;
import com.aspose.words.Paragraph;
import com.aspose.words.RelativeHorizontalPosition;
import com.aspose.words.RelativeVerticalPosition;
import com.aspose.words.Section;
import com.aspose.words.Shape;
import com.aspose.words.ShapeType;
import com.aspose.words.VerticalAlignment;
import com.aspose.words.WrapType;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class SignUtils {

    public static void main(String[] args) throws Exception {
        String sourcePath = "/Users/yassen/Desktop/test/empty.docx";
        LoadOptions opt = new LoadOptions();
        opt.getLanguagePreferences().setDefaultEditingLanguage(EditingLanguage.CHINESE_PRC);
        Document doc = new Document(sourcePath, opt);
        doc = SignUtils.addGapSign(doc);
        doc.save("/Users/yassen/Desktop/test/result.pdf");
    }

    public static Document addGapSign(Document document) throws Exception {
        List<Paragraph> mainBodyParagraphs = new ArrayList<>();
        for (Paragraph para : (Iterable<Paragraph>) document.getChildNodes(NodeType.PARAGRAPH, true)) {
            if (para.getParentNode().getNodeType() == NodeType.BODY) {
                mainBodyParagraphs.add(para);
            }
        }
        InputStream inputStream = generateImageStream(document.getPageCount() / 20 + 1);
        List<InputStream> imgInputStreamList = splitImage(inputStream, document.getPageCount());

        LayoutCollector layoutCollector = new LayoutCollector(document);
        int pageToInsert = 1;
        for (Paragraph para : mainBodyParagraphs) {
            int paraPage = layoutCollector.getEndPageIndex(para);
            if (paraPage == pageToInsert) {
                Shape shape = new Shape(document, ShapeType.IMAGE);
                shape.isLayoutInCell(false);
                shape.setWrapType(WrapType.NONE);
                shape.getImageData().setImage(imgInputStreamList.get(pageToInsert - 1));
                shape.setRelativeHorizontalPosition(RelativeHorizontalPosition.RIGHT_MARGIN);
                shape.setHorizontalAlignment(HorizontalAlignment.RIGHT);
                shape.setRelativeVerticalPosition(RelativeVerticalPosition.TOP_MARGIN);
                shape.setVerticalAlignment(VerticalAlignment.TOP);
                shape.setBehindText(true);
                para.appendChild(shape);
                pageToInsert++;
            }
        }
        return document.deepClone();
    }


    /**
     * 图片切割
     * @param inputStream 图片路径
     * @param count 切割的份数
     */
    public static List<InputStream> splitImage(InputStream inputStream, Integer count) throws IOException {
        List<InputStream> inputStreamList = new ArrayList<>();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedImage img = ImageIO.read(inputStream);
        int height = img.getHeight();
        int width = img.getWidth();
        int sw = width / count;
        for (int i = 0; i < count; i++) {
            BufferedImage subImg;
            if (i == count - 1) {//最后剩余部分
                subImg = img.getSubimage(i * sw, 0, width - i * sw, height);
            } else {//前n-1块均匀切
                subImg = img.getSubimage(i * sw, 0, sw, height);
            }
            ImageIO.write(subImg, "png", out);
            InputStream subInputStream = new ByteArrayInputStream(out.toByteArray());
            out.flush();
            out.reset();
            inputStreamList.add(subInputStream);
        }
        return inputStreamList;
    }

    public static InputStream generateImageStream(int count) throws IOException {
        List<BufferedImage> images = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            BufferedImage imgTmp = ImageIO.read(new File("/Users/yassen/Desktop/test/sign.png"));
            images.add(imgTmp);
        }
        BufferedImage mergedImg = mergeImages(images, false);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(mergedImg, "png", outputStream);
        ImageIO.write(mergedImg, "png", new File("/Users/yassen/Desktop/test/all.png"));
        return new ByteArrayInputStream(outputStream.toByteArray());
    }

    public static BufferedImage mergeImages(List<BufferedImage> images, boolean isVertical) {
        if (images == null || images.isEmpty()) {
            return null;
        }
        int maxWidth = images.stream().mapToInt(BufferedImage::getWidth).max().orElse(200);
        int maxHeight = images.stream().mapToInt(BufferedImage::getHeight).max().orElse(200);
        // 创建合并后的图像,确保使用透明色彩模型
        BufferedImage mergedImage;
        if (isVertical) {
            int totalHeight = images.stream().mapToInt(BufferedImage::getHeight).sum();
            mergedImage = new BufferedImage(maxWidth, totalHeight, BufferedImage.TYPE_INT_ARGB);
        } else {
            int totalWidth = images.stream().mapToInt(BufferedImage::getWidth).sum();
            mergedImage = new BufferedImage(totalWidth, maxHeight, BufferedImage.TYPE_INT_ARGB);
        }
        Graphics2D g2d = mergedImage.createGraphics();
        int curDrawX = 0, curDrawY = 0;
        for (BufferedImage image : images) {
            g2d.drawImage(image, curDrawX, curDrawY, null);
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
            if (isVertical) {
                curDrawY += image.getHeight();
            } else {
                curDrawX += image.getWidth();
            }
        }
        g2d.dispose();
        return mergedImage;
    }
}

word文件:
empty.docx (13.4 KB)
pdf文件:
result.pdf (57.0 KB)

@songyassen 您只处理了主体段落,但表格内也有段落。我认为您需要处理所有段落。

NodeCollection allParagraphs = document.getChildNodes(NodeType.PARAGRAPH, true);
for (Paragraph para : (Iterable<Paragraph>) allParagraphs) {

此外,您还可以更改

int paraPage = layoutCollector.getEndPageIndex(para);
int paraPage = layoutCollector.getStartPageIndex(para);

转换前的word文件:
test3.docx (20.3 KB)

转换后的pdf文件:
result2.pdf (114.4 KB)

@songyassen 出现这种情况是因为您只在第一页和最后一页有段落。您需要使用运行节点来获取正确的页面。请像这样更新代码:

LoadOptions opt = new LoadOptions();
opt.getLanguagePreferences().setDefaultEditingLanguage(EditingLanguage.CHINESE_PRC);
Document doc = new Document("test3.docx", opt);
doc = addGapSign(doc);
doc.save("result.docx");

public static Document addGapSign(Document document) throws Exception {
    DocumentBuilder builder = new DocumentBuilder(document);
    InputStream inputStream = generateImageStream(document.getPageCount() / 20 + 1);
    ArrayList<InputStream> imgInputStreamList = splitImage(inputStream, document.getPageCount());

    LayoutCollector layoutCollector = new LayoutCollector(document);
    int pageToInsert = 1;
    NodeCollection runs = document.getChildNodes(NodeType.RUN, true);
    for (Run run : (Iterable<Run>) runs) {
        int runPage = layoutCollector.getStartPageIndex(run);
        if (runPage == pageToInsert) {
            Shape shape = builder.insertImage(imgInputStreamList.get(pageToInsert - 1));
            shape.isLayoutInCell(false);
            shape.setWrapType(WrapType.NONE);
            shape.setRelativeHorizontalPosition(RelativeHorizontalPosition.RIGHT_MARGIN);
            shape.setHorizontalAlignment(HorizontalAlignment.RIGHT);
            shape.setRelativeVerticalPosition(RelativeVerticalPosition.TOP_MARGIN);
            shape.setVerticalAlignment(VerticalAlignment.TOP);
            shape.setBehindText(true);
            builder.moveTo(run);
            builder.insertNode(shape);
            pageToInsert++;

            layoutCollector.clear();
            document.updatePageLayout();
        }
    }
    return document.deepClone();
}

您好,如您所说,我使用了上面的代码,但是转换后的PDF依然没有在全部页面上添加图片,效果如以下文件所示:
转换前word文档:
test3.docx (18.8 KB)

转换后的PDF文档:
result2.pdf (139.2 KB)

@songyassen 您有一个单元格的一个大运行。在这种情况下,您能做的就是在添加图像之前再添加一个步骤来分割运行:

LoadOptions opt = new LoadOptions();
opt.getLanguagePreferences().setDefaultEditingLanguage(EditingLanguage.CHINESE_PRC);
Document doc = new Document("test3.docx", opt);
prepareRuns(doc);
doc = addGapSign(doc);
doc.save("result.pdf");

private static void prepareRuns(Document doc) {
    NodeCollection runs = doc.getChildNodes(NodeType.RUN, true);
    for (Run run : (Iterable<Run>) runs) {
        if (run.getText().length() > 100) {
            splitRun(run, 10);
        }
    }
}

/**
 * Splits the text of the specified run into two runs.
 * Inserts the new run just after the specified run.
 */
private static void splitRun(Run run, int position) {
    Run afterRun = (Run) run.deepClone(true);
    afterRun.setText(run.getText().substring(position));

    run.setText(run.getText().substring(0, position));
    run.getParentNode().insertAfter(afterRun, run);
}