PDF Layers合并图层部分双层丢失

重写itext的PdfCopy类
package com.lowagie.text.pdf;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.ExceptionConverter;

/**
 * also copy ocgs from imported pages; 
 * the optional Configs item of OCProperties (an array of alternate optional content configurations) is ignored (no copy)
 * 
 * parts of the code copied from PdfCopy  
 * 19.5.2007
 * 
 * @author Jürgen Hofmann (j.hofmann at processmc dot de)
 * 
 */
public class PdfCopyWithOcg extends PdfCopy {

	// merge ocgs with equal display name. 
	// normally each ocg from different documents has its own display name in the layer-tab of acrobat reader.
	// if set true, ocgs with equal names are combined - in this case, the configuration of the first ocg is used
	private	boolean mergeEqualNames = false;		 	

	private final HashMap currentOcgs = new HashMap();	// original reference and new reference of ocg
	private final HashMap ocgNames = new HashMap();		// display name of ocg, used to merge ocg with equal display names
	private final HashSet orderSet = new HashSet();		// holds ocgs of the new ORDER dictionary
	private PdfDictionary dDictionary = null; 			// the new D dictionary
	
	public static void main(String[] args) {
		// we create a PDF file
		try {
			// we create a PdfReader object
			//PdfReader reader = new PdfReader("C:\\temp\\automatic.pdf");
			PdfReader reader = new PdfReader("C:\\temp\\phil04.pdf");
			// step 1
			Document document = new Document(reader.getPageSizeWithRotation(1));
			// step 2
			PdfCopyWithOcg copy = new PdfCopyWithOcg(document, new FileOutputStream(
					"C:\\temp\\test_out.pdf"));
			// step 3
			document.open();
			// step 4
//			copy.setMergeEqualNames(true);
			System.out.println("Tampered? " + reader.isTampered());

/*			PdfImportedPage page;
			int n = reader.getNumberOfPages();
			for (int i = 1; i < 5; ++i) {
				page = copy.getImportedPage(reader, i);
				copy.addPage(page);
			}
			
			reader = new PdfReader("C:\\temp\\phil5.pdf");
			n = reader.getNumberOfPages();
			for (int i = 1; i < 3; ++i) {
				page = copy.getImportedPage(reader, i);
				copy.addPage(page);
			}
*/
			reader = new PdfReader("C:\\temp\\contentgroups.pdf");
			copy.addPage(copy.getImportedPage(reader, 1));
			reader = new PdfReader("C:\\temp\\layers.pdf");
			copy.addPage(copy.getImportedPage(reader, 1));
			reader = new PdfReader("C:\\temp\\nestedlayers.pdf");
			copy.addPage(copy.getImportedPage(reader, 1));
			reader = new PdfReader("C:\\temp\\optionalcontent.pdf");
			copy.addPage(copy.getImportedPage(reader, 1));
			reader = new PdfReader("C:\\temp\\orderedlayers.pdf");
			copy.addPage(copy.getImportedPage(reader, 1));
			System.out.println("Tampered? " + reader.isTampered());
			// step 5
			
			document.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}


    /**
     * Constructor
     * @param document
     * @param os outputstream
     */
 	public PdfCopyWithOcg(Document document, OutputStream os) throws DocumentException {
		super(document, os);
		OCProperties = new PdfOCProperties();
	}

    /*
     * the getCatalog method is part of PdfCopy.
     * we wrap this so that we can add the OCProperties
     */
    @Override
	protected PdfDictionary getCatalog(PdfIndirectReference rootObj) {
        try {
            PdfDictionary theCat = pdf.getCatalog(rootObj);
            if (acroForm != null) theCat.put(PdfName.ACROFORM, acroForm);
            
            // added
            if(OCProperties != null) theCat.put(PdfName.OCPROPERTIES, OCProperties);
            
            if (newBookmarks == null || newBookmarks.isEmpty())
                return theCat;
            PdfDictionary top = new PdfDictionary();
            PdfIndirectReference topRef = getPdfIndirectReference();
            Object kids[] = SimpleBookmark.iterateOutlines(this, topRef, newBookmarks, false);
            top.put(PdfName.FIRST, (PdfIndirectReference)kids[0]);
            top.put(PdfName.LAST, (PdfIndirectReference)kids[1]);
            top.put(PdfName.COUNT, new PdfNumber(((Integer)kids[2]).intValue()));
            addToBody(top, topRef);
            theCat.put(PdfName.OUTLINES, topRef);
            return theCat;
        }
        catch (IOException e) {
            throw new ExceptionConverter(e);
        }
    }

    /*
     * the PdfIndirectReference method is part of PdfCopy.
     * we wrap this so that we can extend it
     */
	@Override
	protected PdfIndirectReference copyIndirect(PRIndirectReference in) throws IOException, BadPdfFormatException {
		PdfIndirectReference theRef;
		RefKey key = new RefKey(in);
		IndirectReferences iRef = (IndirectReferences)indirects.get(key);
		if (iRef != null) {
			theRef = iRef.getRef();
			if (iRef.getCopied())
				return theRef;
		}
		else {
			theRef = body.getPdfIndirectReference();
			iRef = new IndirectReferences(theRef);
			indirects.put(key, iRef);
		}
		PdfObject obj = PdfReader.getPdfObjectRelease(in);
		if (obj != null && obj.isDictionary()) {
			PdfName type = (PdfName)((PdfDictionary)obj).get(PdfName.TYPE);
			if (type != null && PdfName.PAGE.equals(type))
				return theRef;
		}
		obj = copyObject(obj);
		// *************** OCG start **************
		//PDF Reference Version 1.7, 4.10.2, optional content in content streams:
		// ...
		// The property list associated with the marked content specifies either an optional
		// content group or optional content membership dictionary to which the content
		// belongs. Because a group must be an indirect object and a membership dictionary
		// contains references to indirect objects,...
		// 
		// save all ocgs of the imported page, so we can reconstruct a valid ocproperties dictionary
		if (obj != null && obj.isDictionary() ) {
			PdfName type = (PdfName)((PdfDictionary)obj).get(PdfName.TYPE);
			if (type != null  && PdfName.OCG.equals(type)) { 
				// referenced Object is OCG
				PdfString name = (PdfString)((PdfDictionary)obj).get(PdfName.NAME);
				if (mergeEqualNames && name != null) {
					IndirectReferences ref = (IndirectReferences)ocgNames.get(name.toString());
					if (ref == null)
						ocgNames.put(name.toString(), iRef);
					else {
						currentOcgs.put(key,ref);
						return ref.getRef();
					}
				}
				currentOcgs.put(key,iRef);
			}
		}
		// ************** OCG end ****************

		iRef.setCopied();
		addToBody(obj, theRef);
		return theRef;
	}

    /**
     * Add an imported page to our output
     * @param iPage an imported page
     * @throws IOException, BadPdfFormatException
     */
	@Override
	public void addPage(PdfImportedPage iPage) throws IOException, BadPdfFormatException {
		int pageNum = setFromIPage(iPage);

		// initialize current OCGs
		currentOcgs.clear();
		// initialize OCProperties dictionary
		if (dDictionary == null) {
			dDictionary = new PdfDictionary();
			dDictionary.put(PdfName.ORDER, new PdfArray());
			dDictionary.put(PdfName.AS, new PdfArray());
			PdfArray ocgs = new PdfArray();
			OCProperties.put(PdfName.D, dDictionary);
			OCProperties.put(PdfName.OCGS, ocgs);
		}
		
		PdfDictionary thePage = reader.getPageN(pageNum);
		PRIndirectReference origRef = reader.getPageOrigRef(pageNum);
		reader.releasePage(pageNum);
		RefKey key = new RefKey(origRef);
		PdfIndirectReference pageRef;
		IndirectReferences iRef = (IndirectReferences)indirects.get(key);
		if (iRef != null && !iRef.getCopied()) {
			pageReferences.add(iRef.getRef());
			iRef.setCopied();
		}
		pageRef = getCurrentPage();
		if (iRef == null) {
			iRef = new IndirectReferences(pageRef);
			indirects.put(key, iRef);
		}
		iRef.setCopied();
		PdfDictionary newPage = copyDictionary(thePage);
		root.addPage(newPage);
		++currentPageNumber;

		// set OCProperties
		updateOCProperties(reader); 
	
	}

	/*
	 * set new OCProperties
	 * 
	 * from PDF-Reference 1.7 (section 4.10):
	 * OCG: Type [name (OCG), required]
	 *      Name [string, required]
	 *      Intent [name or array (View, Design), optional]
	 *      Usage [dict, optional]
	 *      | - CreatorInfo [dict, optional]
	 *      | - Language [dict, optional]
	 *      | - Export [dict, optional]
	 *      | - Zoom [dict, optional]
	 *      | - Print [dict, optional]
	 *      | - View [dict, optional]
	 *      | - User [dict, optional]
	 *      | - PageElement [dict, optional]
	 *      
	 * OCProperties - OCGs [array,required]
	 *            | - Configs [array, optional] (see D)               **** not yet handled ****
	 *            | - D [dict, required]
	 *                | - Name [text, optional]
	 *                | - Creator [text, optional]
	 *                | - BaseState [name (ON, OFF, Unchanged), optional]
	 *                | - ON [array, optional]
	 *                | - OFF [array, optional]
	 *                | - Intent [name or array (View, Design, All; or combinations), optional]
	 *                | - AS [array, optional]
	 *                    | - Event [name (View,Print,Export), required]
	 *                    | - OCGs [array, optional]
	 *                    | - Category [array, required] (array of names corresponding to a usage dict (View Print Export Zoom User Language)
	 *                | - ORDER [array, optional]
	 *                    | - ocgs or arrays for nested ocgs with (optional) first entry as string
	 *                | - ListMode [name (AllPages, VisiblePages), optional]
	 *                | - RBGroups [array, optional]
	 *                | - Locked [array, optional] (PDF 1.6)
	 *                
	 * 
	 */
	private void updateOCProperties(PdfReader reader) throws IOException, BadPdfFormatException { 
		PdfObject obj;
		PdfDictionary catalog = reader.getCatalog();
		obj = PdfReader.getPdfObject(catalog.get(PdfName.OCPROPERTIES));
		if (obj == null || !obj.isDictionary()) return;
		PdfDictionary ocproperties = (PdfDictionary)obj;

		obj = PdfReader.getPdfObject(ocproperties.get(PdfName.D));
		if (obj == null || !obj.isDictionary()) return;
		PdfDictionary d = (PdfDictionary)obj; 

		// Name
		obj = PdfReader.getPdfObject(d.get(PdfName.NAME));
		if (obj != null && obj.isString())
			if (dDictionary.get(PdfName.NAME) == null)
				dDictionary.put(PdfName.NAME, obj);

		// Creator
		obj = PdfReader.getPdfObject(d.get(PdfName.CREATOR));
		if (obj != null && obj.isString())
			if (dDictionary.get(PdfName.CREATOR) == null)
				dDictionary.put(PdfName.CREATOR, obj);

		// ON
		if (getBaseState(dDictionary) != null && !getBaseState(dDictionary).equals(PdfName.ON))
			addOcgs(PdfName.ON,d);
		
		// OFF
		if (getBaseState(dDictionary) == null || !getBaseState(dDictionary).equals(PdfName.OFF))
			addOcgs(PdfName.OFF,d);

		// Locked (since PDF 1.6)
		addOcgs(new PdfName("Locked"),d);

		//Intent (name or array)
		obj = PdfReader.getPdfObject(d.get(PdfName.INTENT));
		if (obj != null && obj.isName())
			if (dDictionary.get(PdfName.INTENT) == null)
				dDictionary.put(PdfName.INTENT, obj);
		
		// ListMode
		obj = PdfReader.getPdfObject(d.get(PdfName.LISTMODE));
		if (obj != null && obj.isName())
			if (dDictionary.get(PdfName.LISTMODE) == null)
				dDictionary.put(PdfName.LISTMODE, obj);

		// ORDER
		PdfArray order = null;
		obj = PdfReader.getPdfObject(d.get(PdfName.ORDER));
		if (obj != null && obj.isArray()) order = (PdfArray)obj;
		else order = new PdfArray();
		
		// iterate over all Order items
		Iterator it = order.listIterator();
		while (it.hasNext()) {																
			PdfObject item = (PdfObject)it.next();
			if (item != null && item.isArray() && ((PdfArray)item).size() > 0) { 			// array of ocgs 
					PdfArray subArray = getOrderArray((PdfArray)item);
					if (subArray.size() > 0) ((PdfArray)(dDictionary.get(PdfName.ORDER))).add(subArray);
			}
			if (item != null && item.isIndirect())
				if (currentOcgs.containsKey(new RefKey((PdfIndirectReference)item))) {
					IndirectReferences ocg = (IndirectReferences)currentOcgs.get(new RefKey((PdfIndirectReference)item));
					if (ocg != null && !orderSet.contains(ocg)) {
						((PdfArray)(dDictionary.get(PdfName.ORDER))).add(ocg.getRef());
						orderSet.add(ocg);
					}
				}
		}

		// AS
		PdfArray as = null;
		obj = PdfReader.getPdfObject(d.get(PdfName.AS));
		if (obj != null && obj.isArray()) as = (PdfArray)obj;
		else as = new PdfArray();

		it = as.listIterator();
		while (it.hasNext()) {	// iterate over all AS entries 
			obj = (PdfObject)it.next();
			PdfDictionary asItem = (PdfDictionary)PdfReader.getPdfObject(obj);
			PdfDictionary newAsEntry = new PdfDictionary();

			obj = asItem.get(PdfName.OCGS); 
			PdfArray ocgs = (PdfArray)PdfReader.getPdfObject(obj); 
			if (ocgs == null || ocgs.size() == 0) continue;
			
			obj = asItem.get(PdfName.EVENT);
			PdfName event = (PdfName)PdfReader.getPdfObject(obj);

			PdfArray newOcgs = new PdfArray();
			Iterator itOcg = ocgs.listIterator();
			while (itOcg.hasNext()) {
				PdfIndirectReference ocg = (PdfIndirectReference)itOcg.next();
				IndirectReferences newOcg = (IndirectReferences)currentOcgs.get(new RefKey(ocg)); // ocg may not be included in current page 
				if (newOcg != null && !newAsContainsOcgAndEvent(newOcg.getRef(),event))
					if (currentOcgs.containsKey(new RefKey(ocg)))
						newOcgs.add(newOcg.getRef());
			}
			
			if (newOcgs.size() == 0) continue;
			obj = asItem.get(PdfName.CATEGORY); //(Zoom Print View User PageElement Export Language CreaterInfo?)
			PdfArray category = (PdfArray)copyObject(obj);

			if (newOcgs.size() > 0) {
				newAsEntry.put(PdfName.EVENT, event);
				newAsEntry.put(PdfName.OCGS, newOcgs);
				newAsEntry.put(PdfName.CATEGORY, category);
				((PdfArray)(dDictionary.get(PdfName.AS))).add(newAsEntry);
			}
		}		
		
		// save all OCGS
		Iterator ocgIt = currentOcgs.values().iterator();
		while (ocgIt.hasNext()) {
			IndirectReferences ocg = (IndirectReferences)ocgIt.next();
			if (!((PdfArray)(OCProperties.get(PdfName.OCGS))).contains(ocg.getRef()))
				((PdfArray)(OCProperties.get(PdfName.OCGS))).add(ocg.getRef());
		}

		// RBGroups
		PdfArray rbGroups = null;
		obj = PdfReader.getPdfObject(d.get(PdfName.RBGROUPS));
		if (obj != null && obj.isArray()) rbGroups = (PdfArray)obj;
		else rbGroups = new PdfArray();
		
		it = rbGroups.listIterator();
		while (it.hasNext()) {																
			PdfObject item = (PdfObject)it.next();
			if (item != null && item.isArray() && ((PdfArray)item).size() > 0) { 			 
					PdfArray subArray = getSubArray((PdfArray)item);
					if (subArray.size() > 0) {
						PdfArray array = (PdfArray)(dDictionary.get(PdfName.RBGROUPS));
						if (array == null) {
							array = new PdfArray();
							dDictionary.put(PdfName.RBGROUPS, array);
						}
						array.add(subArray);
					}
			}
		}
	}

	/*
	 * add array of ocgs from original D to new D, if not yet set
	 */
	private void addOcgs(PdfName pdfName, PdfDictionary dDict) {
		PdfArray array = null;
		PdfObject obj = PdfReader.getPdfObject(dDict.get(pdfName));
		if (obj != null && obj.isArray()) array = (PdfArray)obj;
		else array = new PdfArray();
		Iterator it = array.listIterator();
		while (it.hasNext()) {
			PdfObject object = (PdfObject)it.next();
			if (object != null && object.isIndirect())
				if (currentOcgs.containsKey(new RefKey((PdfIndirectReference)object))) {
					PdfIndirectReference ocg = ((IndirectReferences)currentOcgs.get(new RefKey((PdfIndirectReference)object))).getRef();
					if (ocg != null && (dDictionary.get(pdfName)== null || !((PdfArray)dDictionary.get(pdfName)).contains(ocg))) {
						if (dDictionary.get(pdfName) == null) dDictionary.put(pdfName, new PdfArray());
						((PdfArray)(dDictionary.get(pdfName))).add(ocg);
					}
				}
		}
	}
	
	/*
	 * check if given ocg-event combination already exists in new AS  
	 */
	private boolean newAsContainsOcgAndEvent(PdfIndirectReference ocg, PdfName event) {
		PdfArray as = (PdfArray)dDictionary.get(PdfName.AS);
		if (as == null || as.size() == 0) return false;
		Iterator it = as.listIterator();
		while (it.hasNext()) {
			PdfDictionary asEntry = (PdfDictionary)it.next();
			if (asEntry == null) continue;
			PdfArray ocgs = (PdfArray)asEntry.get(PdfName.OCGS);
			if (ocgs == null || ocgs.size() == 0) continue;
			PdfName ev = (PdfName)asEntry.get(PdfName.EVENT);
			if (ev == null) continue;
			if (ocgs.contains(ocg) && ev.equals(event)) return true;
		}
		return false;
	}
	
	/*
	 * evaluate sub arrays of Order array
	 */
	private PdfArray getOrderArray(PdfArray array)  {
		PdfArray newArray = new PdfArray();
		if (array != null && array.size() > 0) { 
			int i = 0;
			String name = null;
			if (array.getPdfObject(i) != null && array.getPdfObject(i).isString()) {	// first entry may be String
				name = array.getPdfObject(i).toString();
				++i;
			}
			for(;i < array.size(); ++i) {
				PdfObject entry = array.getPdfObject(i);
				if (entry != null && entry.isIndirect() && currentOcgs.containsKey(new RefKey((PdfIndirectReference)entry))) {
					IndirectReferences ocg = (IndirectReferences)currentOcgs.get(new RefKey((PdfIndirectReference)entry));
					if (!orderSet.contains(ocg)) {
						newArray.add(ocg.getRef());
						orderSet.add(ocg);
					}
				}
				if (entry != null && entry.isArray()) {
					PdfArray subArray = getOrderArray((PdfArray)entry);
					if (subArray.size() > 0) newArray.add(subArray);
				}
			}
			if (newArray.size() > 0 && name != null) newArray.addFirst(new PdfString(name));
		}
		return newArray;
	}
	
	/*
	 *  get copy of PdfArray (of ocgs and other PdfArrays...); only copy ocgs of the current page 
	 */
	private PdfArray getSubArray(PdfArray array)  {
		PdfArray newArray = new PdfArray();
		if (array != null && array.size() > 0) { 
			int i = 0;
			for(;i < array.size(); ++i) {
				PdfObject entry = array.getPdfObject(i);
				if (entry != null && entry.isIndirect() && currentOcgs.containsKey(new RefKey((PdfIndirectReference)entry))) {
					IndirectReferences ocg = (IndirectReferences)currentOcgs.get(new RefKey((PdfIndirectReference)entry));
					newArray.add(ocg.getRef());
				}
				if (entry != null && entry.isArray()) {
					PdfArray subArray = getSubArray((PdfArray)entry);
					if (subArray.size() > 0) newArray.add(subArray);
				}
			}
		}
		return newArray;
	}

	/*
	 * return BaseState of dict
	 */
	private PdfName getBaseState(PdfDictionary dict) {
		PdfObject obj = dict.get(new PdfName("BaseState"));
		if (obj != null && obj.isName()) return (PdfName)obj;
		return null;
	}
	
	 /**
	  * merge ocgs with equal display names. 
	  * the configuration of the first ocg is used.
	  * @param mergeEqualNames
	  */
	 public void setMergeEqualNames(boolean mergeEqualNames) {
		 this.mergeEqualNames = mergeEqualNames;
	 }

}

 

转载于:https://my.oschina.net/rock912/blog/609795

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值