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