使用PDFBox将FormXObject内容并入页面内容流并迁移关联资源的实现问题
FormXObject 内容流迁移实现后出现内容丢失问题
业务场景
- 第一页(page1)的
Resource->Xobjects路径下存储了Fm0、Fm1、Fm2等多个FormXobject对象 - 上述FormXobject的内容未直接挂载在页面的
contents->contentstream节点下,因此需要将Fm0的内容流迁移至page1的contents->contentstream中 - 迁移过程中需要将Fm0关联的所有Resource同步转移或拷贝到页面级资源目录下,结构可参考示意图
迁移要求
- 将FormXObject的内容流拷贝至页面级Contents目录下
- 将Colorspace对象拷贝至
page1->Resource->Colorspace目录下 - 将ExtGState对象拷贝至
page1->Resource->ExtGState目录下 - 在
page1->Resource下按需新建对应结构,完成相关属性资源的拷贝
已编写的实现代码
private static PDDocument parseFormXobject(PDDocument document, Integer pg_ind) throws IOException { List<Object> tokens1 = (List<Object>) (getTokens(document, pg_ind)).get(pg_ind); PDStream newContents = new PDStream(document); OutputStream out = newContents.createOutputStream(COSName.FLATE_DECODE); ContentStreamWriter writer = new ContentStreamWriter(out); PDPage pageinner = document.getPage(pg_ind); PDResources resources = pageinner.getResources(); PDResources new_resources = new PDResources(); new_resources = resources; COSDictionary fntdict = new COSDictionary(); COSDictionary imgdict = new COSDictionary(); COSDictionary extgsdict = new COSDictionary(); COSDictionary colordict = new COSDictionary(); COSDictionary pattern = new COSDictionary(); int img_count = 0; for (COSName xObjectName : resources.getXObjectNames()) { PDXObject xObject = resources.getXObject(xObjectName); if (xObject instanceof PDFormXObject && tokens1.toString().contains(xObjectName.toString()) ) { PDFStreamParser parser = new PDFStreamParser(((PDFormXObject) xObject).getContentStream()); parser.parse(); List<Object> tokens3 = parser.getTokens(); int ind =0; // 判断FormXObject内容流中是否包含文本绘制标记 if (isTextContains(tokens3)){ for (COSName colorname :((PDFormXObject) xObject).getResources().getColorSpaceNames()) { COSName new_name = COSName.getPDFName(colorname.getName()); PDColorSpace pdcolor = ((PDFormXObject) xObject).getResources().getColorSpace(colorname); colordict.setItem(new_name,pdcolor); } for (COSName fontName :((PDFormXObject) xObject).getResources().getFontNames() ) { COSName new_name = COSName.getPDFName(fontName.getName()); PDFont font =((PDFormXObject) xObject).getResources().getFont(fontName); font.getCOSObject().setItem(COSName.NAME, new_name); fntdict.setItem(new_name,font); } for (COSName ExtGSName :((PDFormXObject) xObject).getResources().getExtGStateNames() ) { COSName new_name = COSName.getPDFName(ExtGSName.getName()); PDExtendedGraphicsState ExtGState =((PDFormXObject) xObject).getResources().getExtGState(ExtGSName); ExtGState.getCOSObject().setItem(COSName.NAME, new_name); extgsdict.setItem(new_name,ExtGState); } imgdict.setItem(xObjectName, xObject); for (COSName Imgname :((PDFormXObject) xObject).getResources().getXObjectNames() ) { COSName new_name = COSName.getPDFName(Imgname.getName()); xObject.getCOSObject().setItem(COSName.NAME, new_name); PDXObject img =((PDFormXObject) xObject).getResources().getXObject(Imgname); imgdict.setItem(new_name, img); } for (COSName paternname :((PDFormXObject) xObject).getResources().getPatternNames() ) { COSName new_name = COSName.getPDFName(paternname.getName()); PDAbstractPattern pat = ((PDFormXObject) xObject).getResources().getPattern(paternname); pat.getCOSObject().setItem(COSName.NAME, new_name); pattern.setItem(new_name,pat); } for (int k=0; k< tokens1.size(); k++) { if ( ((tokens1.get(k) instanceof Operator) && ((Operator)tokens1.get(k)).getName().toString().equals("Do")) && ((COSName)tokens1.get(k-1)).getName().toString().equals(xObjectName.getName().toString()) ) { tokens1.remove(k-1); tokens1.remove(k-1); tokens1.add(k-1, Operator.getOperator("q")); if(((PDFormXObject) xObject).getMatrix() != null) { tokens1.add(k, new COSFloat(((PDFormXObject) xObject).getMatrix().getScaleX())); tokens1.add(k + 1, new COSFloat(((PDFormXObject) xObject).getMatrix().getShearY())); tokens1.add(k + 2, new COSFloat(((PDFormXObject) xObject).getMatrix().getShearX())); tokens1.add(k + 3, new COSFloat(((PDFormXObject) xObject).getMatrix().getScaleY())); tokens1.add(k + 4, new COSFloat(((PDFormXObject) xObject).getMatrix().getTranslateX())); tokens1.add(k + 5, new COSFloat(((PDFormXObject) xObject).getMatrix().getTranslateY())); tokens1.add(k + 6, Operator.getOperator("cm")); tokens1.add(k+7, Operator.getOperator("Q")); ind =k+7; }else{ tokens1.add(k, Operator.getOperator("Q")); ind =k; } break; } } for (int k=0; k< tokens3.size(); k++) { if ( (tokens3.size() > k+1) && (tokens3.get(k+1) instanceof Operator) && (((Operator)tokens3.get(k+1)).getName().toString().equals("Do") || ((Operator)tokens3.get(k+1)).getName().toString().equals("gs") || ((Operator)tokens3.get(k+1)).getName().toString().equals("cs") || ((Operator)tokens3.get(k+1)).getName().toString().equals("CS")) ) { COSName new_name = COSName.getPDFName( ((COSName) tokens3.get(k)).getName() ); tokens1.add(ind+k, new_name ); }else if ( (tokens3.size() > k+2) && (tokens3.get(k+2) instanceof Operator) && ((Operator)tokens3.get(k+2)).getName().toString().equals("Tf") ) { COSName new_name = COSName.getPDFName( ((COSName) tokens3.get(k)).getName() ); tokens1.add(ind+k, new_name ); } else tokens1.add(ind+k,tokens3.get(k)); } img_count +=1; }else { imgdict.setItem(xObjectName, xObject); img_count +=1; } }else imgdict.setItem(xObjectName, xObject); } for (COSName fontName :new_resources.getFontNames() ) { PDFont font =new_resources.getFont(fontName); fntdict.setItem(fontName,font); } for (COSName ExtGSName :new_resources.getExtGStateNames() ) { PDExtendedGraphicsState extg =new_resources.getExtGState(ExtGSName); extgsdict.setItem(ExtGSName,extg); } for (COSName colorname :new_resources.getColorSpaceNames() ) { PDColorSpace color =new_resources.getColorSpace(colorname); colordict.setItem(colorname,color); } for (COSName patern :new_resources.getPatternNames() ) { PDAbstractPattern pat =new_resources.getPattern(patern); pattern.setItem(patern,pat); } resources.getCOSObject().setItem(COSName.EXT_G_STATE,extgsdict); resources.getCOSObject().setItem(COSName.FONT,fntdict); resources.getCOSObject().setItem(COSName.XOBJECT,imgdict); resources.getCOSObject().setItem(COSName.COLORSPACE, colordict); resources.getCOSObject().setItem(COSName.PATTERN, pattern); writer.writeTokens(tokens1); out.close(); document.getPage(pg_ind).setContents(newContents); document.getPage(pg_ind).setResources(resources); return document; } private static JSONObject getTokens(PDDocument oldDocument, Integer pageIndex) throws IOException { // 提取指定页面的内容流操作Token列表 JSONObject oldDocumentTokens = new JSONObject(); PDPage pg = oldDocument.getPage(pageIndex); PDFStreamParser parser = new PDFStreamParser(pg); parser.parse(); List<Object> tokens = PDFUtils.removeTokens(parser.getTokens()); oldDocumentTokens.put(pageIndex, tokens); return oldDocumentTokens; } private static boolean isTextContains(List<Object> tokens3) { for (int k=0; k< tokens3.size(); k++) { if (tokens3.get(k) instanceof Operator) { Operator op = (Operator) tokens3.get(k); if(op.getName().equals("BT")) return true; } } return false; }
现存问题
按上述逻辑编写代码实现后,最终生成的PDF无法还原原有的页面图形效果,存在内容丢失的问题。已准备输入PDF样本、输出PDF样本用于效果比对。
内容的提问来源于stack exchange,提问作者fascinating coder
相关产品推荐
相关产品推荐

