All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.idsec.signservice.security.sign.pdf.document.VisibleSignatureImage Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
/*
 * Copyright 2019-2024 IDsec Solutions AB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package se.idsec.signservice.security.sign.pdf.document;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.batik.transcoder.SVGAbstractTranscoder;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;

/**
 * Data object holding the parameters necessary to provide a signature image to a PDF document.
 *
 * @author Martin Lindström ([email protected])
 * @author Stefan Santesson ([email protected])
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class VisibleSignatureImage {

  /** Default date format. */
  public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm z";

  /** Constant representing "first page" (1). */
  public static final int FIRST_PAGE = 1;

  /** Contants representing "last page" (0). */
  public static final int LAST_PAGE = 0;

  /** The page number where the image should be inserted. 0 means last page. */
  private int page;

  /** The x-axis offset in pixels where the image should be inserted. */
  private int xOffset;

  /** The y-axis offset in pixels where the image should be inserted. */
  private int yOffset;

  /** The zoom percentagy of the image, where 0 means original size. */
  private int zoomPercent;

  /** A map of name value pairs that will be included in the image (if it supports it). */
  private Map personalizationParams;

  /** The width of the image in pixels. */
  private int pixelImageWidth;

  /** The height of the image in pixels. */
  private int pixelImageHeight;

  /** Tells whether the sign date should be included in the image. */
  private boolean includeDate;

  /** Date format for signing time. The default is {@link #DEFAULT_DATE_FORMAT}. */
  private String dateFormat;

  /** The contents of the SVG image. */
  private String svgImage;

  /**
   * Generates PDFBox signature options that includes the visible signature.
   * 

* Invokes {@link #getVisibleSignatureOptions(PDDocument, Date, int)} with {@code signatureSize} set to 0. *

* * @param doc the PDF document where the visible signature will be added * @param signTime the time when this signature is claimed to be created * @return a signature options object with visible signature * @throws IOException for errors creating the signature options */ public SignatureOptions getVisibleSignatureOptions(final PDDocument doc, final Date signTime) throws IOException { return this.getVisibleSignatureOptions(doc, signTime, 0); } /** * Generates PDFBox signature options that includes the visible signature. * * @param doc the PDF document where the visible signature will be added * @param signTime the time when this signature is claimed to be created * @param signatureSize the preferred size of the signature data content (0 will use default size) * @return a signature options object with visible signature * @throws IOException for errors creating the signature options */ public SignatureOptions getVisibleSignatureOptions(final PDDocument doc, final Date signTime, final int signatureSize) throws IOException { final SignatureOptions sigOptons = new SignatureOptions(); sigOptons.setPreferredSignatureSize(signatureSize); // If page is less than 1, set to last page. this.page = this.page < 1 ? doc.getNumberOfPages() : this.page; try (final InputStream imageStream = this.createImageFromSVG( this.getPersonalizedSvgImage(this.svgImage, signTime))) { final PDVisibleSignDesigner visibleSignDesigner = new PDVisibleSignDesigner(doc, imageStream, this.page); visibleSignDesigner.xAxis(this.xOffset).yAxis(this.yOffset).zoom(this.zoomPercent).adjustForRotation(); final PDVisibleSigProperties visibleSignatureProperties = new PDVisibleSigProperties(); // visibleSignatureProperties.signerName(name).signerLocation(location).signatureReason(reason). visibleSignatureProperties.page(this.page).visualSignEnabled(true).setPdVisibleSignature(visibleSignDesigner) .buildSignature(); // Set signature in signature options sigOptons.setVisualSignature(visibleSignatureProperties.getVisibleSignature()); sigOptons.setPage(this.page - 1); return sigOptons; } catch (final TranscoderException e) { final String msg = String.format("Failed to create visible signature options - %s", e.getMessage()); log.error("{}", msg, e); throw new IOException(msg, e); } } private InputStream createImageFromSVG(final String svg) throws TranscoderException { final Reader reader = new BufferedReader(new StringReader(svg)); final TranscoderInput svgImage = new TranscoderInput(reader); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final TranscoderOutput tcOut = new TranscoderOutput(bos); final PNGTranscoder pngTranscoder = new PNGTranscoder(); pngTranscoder.addTranscodingHint(SVGAbstractTranscoder.KEY_WIDTH, Float.valueOf(String.valueOf(this.pixelImageWidth))); pngTranscoder.addTranscodingHint(SVGAbstractTranscoder.KEY_HEIGHT, Float.valueOf(String.valueOf(this.pixelImageHeight))); pngTranscoder.transcode(svgImage, tcOut); return new ByteArrayInputStream(bos.toByteArray()); } private String getPersonalizedSvgImage(final String svg, final Date signingTime) { String personalizedJson = svg; final Set keySet = this.personalizationParams.keySet(); for (final String parameterId : keySet) { personalizedJson = personalizedJson.replaceAll("##" + parameterId.toUpperCase() + "##", this.personalizationParams.get(parameterId)); } if (this.includeDate) { personalizedJson = personalizedJson.replaceAll("##SIGNTIME##", this.createDateFormatter().format(signingTime)); } return personalizedJson; } private SimpleDateFormat createDateFormatter() { return this.dateFormat != null ? new SimpleDateFormat(this.dateFormat) : new SimpleDateFormat(DEFAULT_DATE_FORMAT); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy