本文介紹了是否使用PDFBox將FormXObject內(nèi)容從資源添加到內(nèi)容流?的處理方法,對(duì)大家解決問題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧!
問題描述
我的page1下有FormXObject-&>資源-&>X對(duì)象->;FM0,F(xiàn)M1,F(xiàn)M2..
因此它不是Contents->;Contentstream下不可用的直接內(nèi)容流。因此,我想將的內(nèi)容流從fm0-&>內(nèi)容流移動(dòng)到page1-&>內(nèi)容-&>內(nèi)容流。
當(dāng)我們像這樣并行移動(dòng)內(nèi)容流時(shí),我們必須將FM0相關(guān)資源轉(zhuǎn)移或復(fù)制到頁面級(jí)資源。
1.內(nèi)容流需要復(fù)制到頁面級(jí)內(nèi)容下。
2.色彩空間對(duì)象需要復(fù)制到page1->;資源->;色彩空間下。
3.ExtGState對(duì)象需要復(fù)制到page1->;資源->;ExtGState下。
4.屬性需要復(fù)制到page1下-&>資源(此處需要完全創(chuàng)建)
我嘗試了一些代碼
private PDDocument parseFormXobject(PDDocument document) throws IOException {
PDDocument newdocument = new PDDocument();
for (int pg_ind = 0; pg_ind < document.getNumberOfPages(); pg_ind++) {
List<Object> tokens1 = (List<Object>) (getTokens(document)).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();
int img_count = 0;
for (COSName xObjectName : resources.getXObjectNames()) {
PDXObject xObject = resources.getXObject(xObjectName);
if (xObject instanceof PDFormXObject) {
PDFStreamParser parser = new PDFStreamParser(((PDFormXObject) xObject).getContentStream());
parser.parse();
List<Object> tokens3 = parser.getTokens();
int ind =0;
System.out.println(xObjectName.getName());
for (COSName colorname :((PDFormXObject) xObject).getResources().getColorSpaceNames())
{
COSName new_name = COSName.getPDFName(colorname.getName()+"_Fm"+img_count);
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()+"_Fm"+img_count);
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()+"_Fm"+img_count);
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()+"_Fm"+img_count);
xObject.getCOSObject().setItem(COSName.NAME, new_name);
PDXObject img =((PDFormXObject) xObject).getResources().getXObject(Imgname);
imgdict.setItem(new_name, img);
}
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()) ) {
System.out.println(tokens1.get(k).toString());
tokens1.remove(k-1);
tokens1.remove(k-1);
ind =k-1;
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") ) ) {
COSName new_name = COSName.getPDFName( ((COSName) tokens3.get(k)).getName()+"_Fm"+img_count );
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()+"_Fm"+img_count );
tokens1.add(ind+k, new_name );
}else
tokens1.add(ind+k,tokens3.get(k));
}
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);
}
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);
writer.writeTokens(tokens1);
out.close();
document.getPage(pg_ind).setContents(newContents);
document.getPage(pg_ind).setMediaBox(PDFUtils.Media_box);
document.getPage(pg_ind).setResources(resources);
newdocument.addPage(document.getPage(pg_ind));
}
newdocument.save("D:/Testfiles/stu.pdf");
return newdocument;
}
但我無法獲得準(zhǔn)確的頁面圖形。我失去了一些東西。
input pdf
output pdf
推薦答案
有多個(gè)問題,有些是詳細(xì)問題,有些是概念問題。
包裝在保存圖形狀態(tài)/恢復(fù)圖形狀態(tài)信封中
在繪制XObject時(shí),該XObject中的圖形狀態(tài)更改不會(huì)更改您的當(dāng)前圖形狀態(tài)。為了確保在將XObject指令復(fù)制到頁面內(nèi)容流之后仍然是這樣,您必須將該塊包裝到一個(gè)保存圖形狀態(tài)/恢復(fù)圖形狀態(tài)信封(q…q)中。您可以通過添加以下兩行
來實(shí)現(xiàn)此目的
tokens1.add(ind++, Operator.getOperator("q"));
tokens1.add(ind, Operator.getOperator("Q"));
就在您的指令復(fù)制循環(huán)之前
for (int k=0; k< tokens3.size(); k++) {
...
}
坐標(biāo)系
假設(shè)XObject中的坐標(biāo)系等于頁面的坐標(biāo)系。這并不一定。XObject可能有一個(gè)Matrix條目,表示要應(yīng)用的轉(zhuǎn)換。
邊界框
您不會(huì)限制XObject指令所繪制的區(qū)域。但是XObject有一個(gè)bBox條目,表示要將輸出裁剪到的框。
可選內(nèi)容
XObject還可能有OC條目,表示它們的可選內(nèi)容成員身份。此類成員身份需要轉(zhuǎn)換為等效的可選內(nèi)容標(biāo)記。
標(biāo)記內(nèi)容、結(jié)構(gòu)樹
XObject還可以通過StructParent或StructParents條目引用結(jié)構(gòu)父樹。為了保持文檔的結(jié)構(gòu)完整性,您可能需要大量更新結(jié)構(gòu)樹。
分組
XObject可能包含Group條目,表示其內(nèi)容應(yīng)被視為一個(gè)組。尤其是在透明度組的情況下,這會(huì)導(dǎo)致透明度相關(guān)功能的行為與復(fù)制到頁面內(nèi)容中的相同指令的行為不同。
除非您完全分析以一定透明度繪制的每一位內(nèi)容的效果,并逐一重寫繪制它的指令,否則將指令從XObject復(fù)制到頁面內(nèi)容流將導(dǎo)致顯示的內(nèi)容有很大差異。
用法
您的代碼假定XObject在頁面內(nèi)容流中只使用了一次。情況并非如此,它也可以更頻繁地使用,或者根本不使用。
參考資料
在您要求提供推薦人的評(píng)論中。實(shí)際上,它都在pdf規(guī)范ISO 32000中,已經(jīng)在公開可用的ISO 32000-1中:
8.10表單XObject
Form XObject是PDF內(nèi)容流,它是對(duì)任何圖形對(duì)象序列(包括路徑對(duì)象、文本對(duì)象和采樣圖像)的獨(dú)立描述。一個(gè)表單XObject可以繪制多次(在多個(gè)頁面上或在同一頁面上的多個(gè)位置),并且每次都會(huì)生成相同的結(jié)果,僅受其調(diào)用時(shí)的圖形狀態(tài)的影響。
因此,給定頁面上的任意數(shù)量的使用都是可能的
將do運(yùn)算符應(yīng)用于Form XObject時(shí),符合要求的讀取器應(yīng)執(zhí)行以下任務(wù):
a)保存當(dāng)前圖形狀態(tài),就像通過調(diào)用q運(yùn)算符一樣(參見8.4.4;圖形狀態(tài)運(yùn)算符)
b)將表單詞典的矩陣條目中的矩陣與當(dāng)前轉(zhuǎn)換矩陣(CTM)連接
c)根據(jù)表單詞典的bBox條目進(jìn)行剪輯
d)繪制表單內(nèi)容流中指定的圖形對(duì)象
e)恢復(fù)保存的圖形狀態(tài),就像通過調(diào)用q運(yùn)算符一樣(參見8.4.4;圖形狀態(tài)運(yùn)算符
)
因此,在復(fù)制到頁面內(nèi)容流中時(shí),您應(yīng)該等效使用q/q信封,并遵守Matrix和bbox條目。
8.11.3.3 XObject和批注中的可選內(nèi)容
除了內(nèi)容流中的標(biāo)記內(nèi)容外,表單XObject和圖像XObject(請(qǐng)參閱8.8;外部對(duì)象)和批注(請(qǐng)參閱12.5;批注和注釋)還可以包含OC條目,該條目應(yīng)該是可選的內(nèi)容組或可選的內(nèi)容成員詞典。
表單或圖像XObject的可見性應(yīng)由成員資格詞典引用的組或組的狀態(tài)及其P(或VE)條目以及調(diào)用XObject的上下文中的當(dāng)前可見性狀態(tài)(即,對(duì)象在內(nèi)容流中發(fā)生執(zhí)行操作的位置是否可見)確定。
因此,在復(fù)制到頁面內(nèi)容時(shí),請(qǐng)遵守此可選內(nèi)容信息。
11.6.6透明組XObject
透明度組在PDF中表示為稱為透明度組XObject的特殊類型的組XObject(請(qǐng)參閱”Group XObject”)。組XObject又是一種表單XObject,其區(qū)別在于其表單詞典中存在Group條目(請(qǐng)參閱”表單詞典”)。此條目的值是定義組屬性的附屬組屬性字典。詞典內(nèi)容的格式和含義應(yīng)由其組子類型確定,該子類型由詞典的S條目指定。透明度組(子類型透明度)的條目如表147所示。
…
附件L
因此,從透明組復(fù)制可能會(huì)顯著更改外觀。
14.7.4.3作為內(nèi)容項(xiàng)目的PDF對(duì)象
當(dāng)結(jié)構(gòu)元素的內(nèi)容包括與頁面關(guān)聯(lián)但不直接包括在頁面內(nèi)容流中的整個(gè)PDF對(duì)象(如XObject或批注)時(shí),該對(duì)象應(yīng)在結(jié)構(gòu)元素的K條目中由對(duì)象引用詞典標(biāo)識(shí)(參見表325)。
…
14.7.4.4從內(nèi)容項(xiàng)查找結(jié)構(gòu)元素
…
要定位相關(guān)的父樹條目,樹中表示的每個(gè)對(duì)象或內(nèi)容流都應(yīng)包含一個(gè)特殊的詞典條目,StructParent或StructParents(參見表326)。根據(jù)內(nèi)容項(xiàng)的類型,此條目可能出現(xiàn)在包含標(biāo)記內(nèi)容序列的頁面的頁面對(duì)象中、表單或圖像XObject的流字典中、批注字典中或作為結(jié)構(gòu)元素中的內(nèi)容項(xiàng)包括的任何其他類型的對(duì)象字典中。
此信息以及同一章中的更多信息應(yīng)清楚地表明,必須徹底檢查從XObject復(fù)制到頁面內(nèi)容后的結(jié)構(gòu)信息。
這篇關(guān)于是否使用PDFBox將FormXObject內(nèi)容從資源添加到內(nèi)容流?的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,