package cn.report.pdf.sign;

import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.signatures.BouncyCastleDigest;
import com.itextpdf.signatures.DigestAlgorithms;
import com.itextpdf.signatures.IExternalDigest;
import com.itextpdf.signatures.IExternalSignature;
import com.itextpdf.signatures.PdfSignatureAppearance;
import com.itextpdf.signatures.PdfSigner;
import com.itextpdf.signatures.PrivateKeySignature;
import com.itextpdf.signatures.PdfSigner.CryptoStandard;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class CreateSignatureUtils  
{
	public static final String KEYSTORE = "D:\\test\\test.keystore";//"./src/test/resources/encryption/ks";
	public static final char[] PASSWORD = "123456".toCharArray();  // keystore密码
	public static final String SRC = "D:\\test\\1.pdf";
	public static final String DEST = "D:\\test\\target.pdf";
	public static final String stamperSrc = "D:\\test\\2.jpg";//印章路径
	boolean isAppendMode = false;//true不输出;

	public static void main(String[] args) throws GeneralSecurityException, IOException 
	{	 
		// 读取keystore获得私钥和证书链
		BouncyCastleProvider provider = new BouncyCastleProvider();
		Security.addProvider(provider);
		//KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
		KeyStore ks = KeyStore.getInstance("jks");
        //KeyStore ks = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());
        //KeyStore ks = KeyStore.getInstance("PKCS12");
		ks.load(new FileInputStream(KEYSTORE), PASSWORD);
		String alias = ks.aliases().nextElement();
		PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
		Certificate[] chain = ks.getCertificateChain(alias);

		// new一个上边自定义的方法对象，调用签名方法
		CreateSignatureUtils app = new CreateSignatureUtils();
		app.sign(SRC, String.format(DEST, 1), chain, pk, DigestAlgorithms.SHA256, provider.getName(),CryptoStandard.CADES, "Test 1","Ghent");

		// app.sign(SRC, String.format(DEST, 1), chain, pk, DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CMS, "Test 1", "Ghent");
		//app.sign(SRC, String.format(DEST, 2), chain, pk, DigestAlgorithms.SHA512, provider.getName(), PdfSigner.CryptoStandard.CMS, "Test 2", "Ghent");
		//app.sign(SRC, String.format(DEST, 3), chain, pk, DigestAlgorithms.SHA256, provider.getName(), PdfSigner.CryptoStandard.CADES, "Test 3", "Ghent");
		//app.sign(SRC, String.format(DEST, 4), chain, pk, DigestAlgorithms.RIPEMD160, provider.getName(), PdfSigner.CryptoStandard.CADES, "Test 4", "Ghent");
	}

	public void sign(String src,  //需要签章的pdf文件路径
			String dest,  // 签完章的pdf文件路径
			Certificate[] chain, //证书链
			PrivateKey pk, //签名私钥
			String digestAlgorithm,  //摘要算法名称，例如SHA-1
			String provider,  // 密钥算法提供者，可以为null
			CryptoStandard subfilter, //数字签名格式，itext有2种
			String reason,  //签名的原因，显示在pdf签名属性中，随便填
			String location) //签名的地点，显示在pdf签名属性中，随便填
					throws GeneralSecurityException, IOException {
		//目标文件输出流
		FileOutputStream os = new FileOutputStream(dest);

		// Creating the reader and the signer
		PdfReader reader = new PdfReader(src);

		//创建签章工具PdfSigner ，最后一个boolean参数 
		//false的话，pdf文件只允许被签名一次，多次签名，最后一次有效
		//true的话，pdf可以被追加签名，验签工具可以识别出每次签名之后文档是否被修改
		//StampingProperties q = new StampingProperties();
		//q.useAppendMode();
		/*StampingProperties properties = new StampingProperties();
		if (isAppendMode){
			properties.useAppendMode();
		}
		PdfSigner signer = new PdfSigner(reader,os,properties);*/
		PdfSigner signer = new PdfSigner(reader,os,false);//true不输出
		//设置图章的位置和大小
		Rectangle rect = new Rectangle(33,210,100,100);
		doImageStamp(signer,stamperSrc,rect,1,reason,location,false);	
	
		signer.setFieldName("sig");

		//签名算法
		IExternalSignature pks = new PrivateKeySignature(pk,digestAlgorithm, provider);
		//摘要算法
		IExternalDigest digest = new BouncyCastleDigest();
		//调用itext签名方法完成pdf签章
		signer.setCertificationLevel(1);
		signer.signDetached(digest, pks, chain, null, null, null, 0, subfilter);
	}

	/**盖章  对pdf进行签名图片操作（添加签章）
	 * @param pdfSigner
	 * @param imgBytes 图片文件
	 * @param leftBottomX 图片的左下方x坐标
	 * @param leftBottomY 图片的左下方y坐标
	 * @param imgWidth 图片的宽度
	 * @param imgHeight 图片的高度
	 * @param pageNum 页码
	 * @throws MalformedURLException 
	 */
	private void doImageStamp(PdfSigner pdfSigner,String stamperPath/* byte[] imgBytes*/, 
							 Rectangle rect, int pageNum,String reason,String location,
							 Boolean appearFlag)
		throws MalformedURLException 
	{
		//图章图片
		ImageData img = ImageDataFactory.create(stamperPath);
		//读取图章图片，这个image是itext包的image
		//import com.itextpdf.layout.element.Image;
		//Image image = new Image(img);
		//float height = image.getImageHeight();
		//float width = image.getImageWidth();

		//ImageData imageData = ImageDataFactory.create(imgBytes);
		//设置图章的位置和大小
		//设置签名的位置，页码，签名域名称，多次追加签名的时候，签名与名称不能一样
		//签名的位置，是图章相对于pdf页面的位置坐标，原点为pdf页面左下角
		//四个参数的分别是，图章左下角x，图章左下角y，图章宽度，图章高度
		PdfSignatureAppearance appearance = pdfSigner.getSignatureAppearance();
		appearance.setPageRect(rect)
					.setReason(reason)
					.setLocation(location)
					.setReuseAppearance(appearFlag)
					.setPageNumber(pageNum)
					.setSignatureGraphic(img)//设置签章图片
					//.setSignatureGraphic(imageData)
					.setRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC);//设置图章的显示方式
	}
	
}
