Browse Source

add: 在PDF中显示数字签名

wzl 11 months ago
parent
commit
f73b39e53e

+ 4 - 2
packages/core/src/annotation/layer.js

@@ -986,7 +986,8 @@ class ComPDFAnnotationLayer {
             viewport: this.viewport,
             scale: this.scale,
             eventBus: this.eventBus,
-            layer: this
+            layer: this,
+            messageHandler: this.messageHandler
           })
           this.annotationsArray.push(signatureFields)
         }
@@ -1282,7 +1283,8 @@ class ComPDFAnnotationLayer {
         viewport: this.viewport,
         scale: this.scale,
         eventBus: this.eventBus,
-        layer: this
+        layer: this,
+        messageHandler: this.messageHandler
       })
       this.annotationsArray.push(signatureFields)
     }

+ 1 - 1
packages/core/src/annotation/stamp.js

@@ -124,7 +124,7 @@ export default class Stamp extends Base {
 
       const imageArray = await this.messageHandler.sendWithPromise('GetRenderAnnot', {
         annotPtr: this.annotation.annotPtr,
-        annotation: this.annotation,
+        rect: this.annotation.rect,
         scale: this.scale
       })
 

+ 2 - 1
packages/core/src/annotation_store.js

@@ -4,5 +4,6 @@ export default {
   notFirstRender: false,
   creating: false,
   fileData: null,
-  $t: null
+  $t: null,
+  signatures: [],
 }

+ 58 - 24
packages/core/src/form/signature_fields.js

@@ -2,7 +2,7 @@ import Base from '../annotation/base';
 import { getActualPoint, getClickPoint, createSvg, createElement } from '../annotation/utils';
 import { onClickOutside } from '../ui_utils'
 
-export default class signatureFields extends Base {
+export default class SignatureFields extends Base {
   
   constructor ({
     container,
@@ -12,7 +12,7 @@ export default class signatureFields extends Base {
     scale,
     eventBus,
     layer,
-    show = false
+    messageHandler
   }) {
     super({
       container,
@@ -20,13 +20,12 @@ export default class signatureFields extends Base {
       page,
       viewport,
       scale,
-      eventBus,
-      show
+      eventBus
     })
 
     this.layer = layer
+    this.messageHandler = messageHandler
     this.hidden = true
-    this.initial = false
     this.outline = null
 
     this.start = null
@@ -38,7 +37,7 @@ export default class signatureFields extends Base {
     this.startCircle = null
     this.endCircle = null
 
-    this.show = show
+    this.ratio = window.devicePixelRatio || 1
 
     this.onMousedown = this.handleMouseDown.bind(this)
     this.onMouseup = this.handleMouseUp.bind(this)
@@ -47,10 +46,12 @@ export default class signatureFields extends Base {
     this.render()
   }
 
-  render () {
+  async render () {
     this.eventBus._on('setProperty', this.setProperty.bind(this))
     this.eventBus._on('deleteSignature', this.onDelete)
 
+    // console.log(this.layer.annotationStore.signatures)
+
     for (let key in this.annotation) {
       if (key === 'background-color') {
         let newName = 'backgroundColor'
@@ -95,10 +96,8 @@ export default class signatureFields extends Base {
     annotationContainer.style.width = rect.width + 'px'
     annotationContainer.style.height = rect.height + 'px'
     this.annotationContainer = annotationContainer
-    this.annotationContainer.addEventListener('mousedown', this.handleClick.bind(this))
 
-    let shapeElement
-    shapeElement = createElement(
+    let shapeElement = createElement(
       'div',
       {
         left: 0,
@@ -110,11 +109,29 @@ export default class signatureFields extends Base {
         position: 'relative'
       }
     )
-
     this.shapeElement = shapeElement
 
-    this.annotationContainer.append(this.shapeElement)
+    if (this.annotation.digitalSignaturePtr) {
+      const initRect = this.rectCalc({ start, end })
+      const imgSrc = await this.getSignatureImage(initRect)
+  
+      let imgEle = document.createElement('img')
+      imgEle.style.width = '100%'
+      imgEle.style.height = '100%'
+      imgEle.style.pointerEvents = 'none'
+
+      this.annotationContainer.style.zIndex = 1
+      this.shapeElement.style.position = 'absolute'
+      this.shapeElement.style.zIndex = -1
 
+      imgEle.src = imgSrc
+      this.imgEle = imgEle
+
+      this.annotationContainer.append(this.imgEle)
+    }
+
+    this.annotationContainer.append(this.shapeElement)
+    this.annotationContainer.addEventListener('mousedown', this.handleClick.bind(this))
     this.container.append(this.annotationContainer)
 
     this.outerLineContainer = document.createElement('div')
@@ -297,14 +314,10 @@ export default class signatureFields extends Base {
     this.outerLine.append(this.topRect)
     this.outerLineContainer.append(this.outerLine)
     this.outerLineContainer.append(this.deletetButton)
-    this.initial = true
-
-    if (this.show) this.handleClick()
   }
 
   getActualRect (viewport, s,) {
-    const annotation = this.annotation
-    const { left: x1, top: y1, right: x2, bottom: y2 } = annotation.rect
+    const { left: x1, top: y1, right: x2, bottom: y2 } = this.annotation.rect
     
     const start = getActualPoint(
       {
@@ -374,7 +387,6 @@ export default class signatureFields extends Base {
   }
 
   updateTool () {
-    if (!this.initial) return
     if (this.hidden) {
       if (this.layer.annotationStore.selectedElementName === this.annotation.name) {
         this.layer.annotationStore.selectedElementName = null
@@ -392,6 +404,9 @@ export default class signatureFields extends Base {
 
   handleClick () {
     if (!this.hidden || document.fullscreenElement || this.layer.annotationStore.creating || this.layer.toolMode === 'editor' || document.getElementById("sign-image-save")) return
+    if (this.imgEle && !this.shapeElement) return
+    if (this.layer.pageDiv.querySelector('.annotationLayer svg').style.cursor === 'crosshair' && this.layer.toolMode !== 'sign') return
+
     if (this.layer.tool === 'signatureFields') {
       this.hidden = false
       this.updateTool()
@@ -435,9 +450,7 @@ export default class signatureFields extends Base {
     document.addEventListener('mouseup', this.onMouseup)
     document.addEventListener('touchmove', this.onMousemove)
     document.addEventListener('touchend', this.onMouseup)
-
-    this.handleClick()
-  };
+  }
 
   handleMouseMove (event) {
     if (event.button !== 0 && event.type === 'mousemove') return
@@ -752,8 +765,29 @@ export default class signatureFields extends Base {
     }
   }
 
-  isURL (str) {
-    const pattern = /^(?:(?:https?|ftp):\/\/)?(?:www\.)?(?:[\w]+\.){1,3}(?:[a-z]{2,})?(?:\/[\w .-]*)*(?:\?[^\s]*)?$/;
-    return pattern.test(str);
+  async getSignatureImage(rect) {
+    const imgRect = {
+      width: parseInt(rect.width * this.ratio + 1),
+      height: parseInt(rect.height * this.ratio + 1)
+    }
+
+    const imageArray = await this.messageHandler.sendWithPromise('GetRenderAnnot', {
+      annotPtr: this.annotation.annotPtr,
+      rect: this.annotation.rect,
+      scale: this.scale * this.ratio
+    })
+
+    const canvas = document.createElement('canvas')
+    canvas.style.width = imgRect.width + 'px'
+    canvas.style.height = imgRect.height + 'px'
+    canvas.width = imgRect.width
+    canvas.height = imgRect.height
+    let drawContext = canvas.getContext("2d")
+    drawContext.clearRect(0, 0, canvas.width, canvas.height)
+    let imageData = drawContext.createImageData(imgRect.width, imgRect.height)
+    imageData.data.set(imageArray)
+    drawContext.putImageData(imageData, 0, 0)
+    const imgSrc = canvas.toDataURL("image/png", 1)
+    return imgSrc
   }
 }

+ 11 - 9
packages/core/src/index.js

@@ -425,6 +425,7 @@ class ComPDFKitViewer {
     this.distanceChangedCallback = options.distanceChangedCallback || this.distanceChangedCallback
     this.annotations = null
     annotationStore.annotationsAll = null
+    annotationStore.signatures = null
     annotationStore.selectedName = null
     this.fontFileInited = false
     this.saveAction = options.saveAction || null
@@ -1008,7 +1009,7 @@ class ComPDFKitViewer {
   }
 
   async initPage() {
-     const pagesCount = await this.messageHandler.sendWithPromise("GetPageCount", {
+    const pagesCount = await this.messageHandler.sendWithPromise("GetPageCount", {
       doc: this.doc,
     })
 
@@ -1036,6 +1037,8 @@ class ComPDFKitViewer {
   }
 
   async getAnnotations() {
+    const signaturePtrList = await this.getSignatures()
+
     const annotations = []
     const pagesPtr = this.pagesPtr
     for (let pageIndex = 0; pageIndex < this.pagesCount; pageIndex++) {
@@ -1057,7 +1060,8 @@ class ComPDFKitViewer {
             doc: this.doc,
             annotPtr: annotation.annotPtr,
             pagePtr: annotation.pagePtr,
-            typeInt
+            typeInt,
+            signaturePtrList
           })
         } else {
           attr = await this.messageHandler.sendWithPromise('GetAnnotation', {
@@ -1073,8 +1077,6 @@ class ComPDFKitViewer {
       }
     }
 
-    await this.getSignatures()
-
     this.pdfViewer.pagesPtr = this.pagesPtr
 
     return annotations
@@ -2749,7 +2751,6 @@ class ComPDFKitViewer {
 
   handleSign(data) {
     const { type = 0, flag, param } = data
-    console.log(type, flag, param)
 
     if (flag === 'create' && !this.Signatures) {
       this.Signatures = new Signatures({
@@ -3343,7 +3344,7 @@ class ComPDFKitViewer {
       }
 
       const { status } = result
- 
+
       if(!status) console.warn('move', status)
     }
 
@@ -3595,11 +3596,12 @@ class ComPDFKitViewer {
   }
 
   async getSignatures() {
-    const signatureList = await this.messageHandler.sendWithPromise('GetSignatures', {
+    const { signatures, signaturePtrList } = await this.messageHandler.sendWithPromise('GetSignatures', {
       doc: this.doc
     })
-    this.eventBus.dispatch('getSignatures', signatureList)
-    return signatureList
+    this.eventBus.dispatch('getSignatures', signatures)
+    annotationStore.signatures = signatures
+    return signaturePtrList
   }
 }
 

+ 126 - 84
packages/core/src/worker/compdfkit_worker.js

@@ -189,9 +189,9 @@ class CPDFWorker {
     })
 
     messageHandler.on('GetRenderAnnot', (data) => {
-      const { annotPtr, annotation, scale } = data
-      const width = parseInt(annotation.rect.right * scale - annotation.rect.left * scale + 1)
-      const height = parseInt(annotation.rect.bottom * scale - annotation.rect.top * scale + 1)
+      const { annotPtr, rect, scale } = data
+      const width = parseInt(rect.right * scale - rect.left * scale + 1)
+      const height = parseInt(rect.bottom * scale - rect.top * scale + 1)
       let pixelNum = width * height
 
       let imageBytes = pixelNum * 4
@@ -214,13 +214,14 @@ class CPDFWorker {
     })
 
     messageHandler.on('GetWidgetAnnotation', (data) => {
-      const { doc, pagePtr, annotPtr, typeInt } = data
+      const { doc, pagePtr, annotPtr, typeInt, signaturePtrList } = data
 
       return getWidgetAnnotation({
         doc,
         pagePtr,
         annotPtr,
-        typeInt
+        typeInt,
+        signaturePtrList
       })
     })
 
@@ -2180,7 +2181,8 @@ function getWidgetAnnotation({
   doc,
   pagePtr,
   annotPtr,
-  typeInt
+  typeInt,
+  signaturePtrList
 }) {
   // WidgetType
   let annotationAttr = null
@@ -2391,19 +2393,30 @@ function getWidgetAnnotation({
     annotation.color = hex
   }
 
+  if (type === 6) {
+    for (let i = 0; i < signaturePtrList.length; i++) {
+      const signaturePtr = signaturePtrList[i]
+      const res = Module._IsSameAnnotDict(signaturePtr, annotPtr)
+      if (res) annotation.digitalSignaturePtr = signaturePtr
+    }
+    
+  }
+
   return annotation
 }
 
 async function getSignatures({
   doc,
 }) {
-  const signatureList = []
+  const signatures = []
+  const signaturePtrList = []
   const count = Module._GetSignatureCount(doc)
 
   for (let i = 0; i < count; i++) {
     // 获取签名指针
     const signaturePtr = Module._InitSignature(doc, i)
     if (signaturePtr) {
+      signaturePtrList.push(signaturePtr)
       const signerList = []
       const signature = {
         signaturePtr,
@@ -2428,57 +2441,6 @@ async function getSignatures({
 
           const certPtr = Module._GetSignCert(signerPtr)
           if (certPtr) {
-            signer.version = Module._GetSignVersion(certPtr)
-            Module._GetSignAlgOid(certPtr)
-            signer.signAlgOid = U8StringData
-            signer.signAlgOidType = getSignatureAlgorithmType(signer.signAlgOid)
-            signer.subject = []
-            for (let i = 0; i < 7; i++) {
-              Module._GetSignSubject(certPtr, i)
-              signer.subject.push(U8StringData)
-            }
-            signer.issuer = []
-            for (let i = 0; i < 7; i++) {
-              Module._GetSignIssuer(certPtr, i)
-              signer.issuer.push(U8StringData)
-            }
-            Module._GetSignSerialNumber(certPtr)
-            signer.serialNumber = U8StringData
-            Module._GetSignValidDate(certPtr, 0)
-            signer.validDateStart = U8StringData
-            Module._GetSignValidDate(certPtr, 1)
-            signer.validDateEnd = U8StringData
-
-            AccessInfoArray = []
-            Module._GetAuthorityInfoAccess(certPtr)
-            signer.sccessInfo = AccessInfoArray
-            Module._GetSubjectKeyIdentifier(certPtr)
-            signer.subjectKeyIdentifier = U8StringData
-            signer.keyUsage = Module._GetKeyUsage(certPtr)
-            PolicyArray = []
-            Module._GetCertificatePolicies(certPtr)
-            signer.certificatePolicies = PolicyArray
-            Module._GetAuthorityKeyIdentifier(certPtr)
-            signer.authorityKeyIdentifier = U8StringData
-            CRLPointArray = []
-            Module._GetCRLDistributionPoints(certPtr)
-            signer.CRLDistributionPoints = CRLPointArray
-
-            Module._GetBasicConstraints(certPtr)
-            signer.basicConstraints = U8StringData
-            Module._GetPublicKey(certPtr)
-            signer.publicKey = U8StringData
-            Module._GetX509Data(certPtr)
-            signer.X509Data = U8StringData
-            Module._GetSHA1Digest(certPtr)
-            signer.SHA1Digest = U8StringData
-            Module._GetMD5Digest(certPtr)
-            signer.MD5Digest = U8StringData
-
-            OCSPUrlArray = []
-            Module._GetOCSPUrl(certPtr)
-            signer.ocspURL = OCSPUrlArray
-
             // TODO: 验证证书
             CertArray = []
             Module._ExportToFilePath(certPtr, 1)
@@ -2504,15 +2466,17 @@ async function getSignatures({
             }
             CertArray = []
             Module._GetSignCertChain(certPtr)
+            CertArray.push(certPtr)
 
             for (let k = 0; k < CertArray.length; k++) {
               const certPtr = CertArray[k]
+              const certData = await getSignCertData(certPtr)
+
               const certificate = {
-                certPtr
+                certPtr,
+                ...certData
               }
 
-              // TODO: 获取证书信息
-
               certificateList.push(certificate)
             }
           }
@@ -2533,31 +2497,33 @@ async function getSignatures({
       }
 
       // 获取签名信息
-      Rect = {}
-      Module._GetSignatureRect(doc, signaturePtr)
-      signature.rect = {
-        left: roundToDecimalPlaces(Rect.Left),
-        top: roundToDecimalPlaces(Rect.Top),
-        right: roundToDecimalPlaces(Rect.Right),
-        bottom: roundToDecimalPlaces(Rect.Bottom)
-      }
-      Module._GetSignatureFieldName(signaturePtr)
-      signature.fieldName = U8StringData
-      Module._GetSignatureName(signaturePtr)
-      signature.name = U8StringData
-      Module._GetSignatureTime(signaturePtr)
-      const rawDate = U8StringData
-      signature.date = parseAdobePDFTimestamp(rawDate)
-      Module._GetSignatureReason(signaturePtr)
-      signature.reason = U8StringData
-      Module._GetSignatureLocation(signaturePtr)
-      signature.location = U8StringData
-      signature.pageIndex = Module._GetSignaturePageIndex(signaturePtr)
-
-      signatureList.push(signature)
+      if (SignerArray.length) {
+        Rect = {}
+        Module._GetSignatureRect(doc, signaturePtr)
+        signature.rect = {
+          left: roundToDecimalPlaces(Rect.Left),
+          top: roundToDecimalPlaces(Rect.Top),
+          right: roundToDecimalPlaces(Rect.Right),
+          bottom: roundToDecimalPlaces(Rect.Bottom)
+        }
+        Module._GetSignatureFieldName(signaturePtr)
+        signature.fieldName = U8StringData
+        Module._GetSignatureName(signaturePtr)
+        signature.name = U8StringData
+        Module._GetSignatureTime(signaturePtr)
+        const rawDate = U8StringData
+        signature.date = parseAdobePDFTimestamp(rawDate)
+        Module._GetSignatureReason(signaturePtr)
+        signature.reason = U8StringData
+        Module._GetSignatureLocation(signaturePtr)
+        signature.location = U8StringData
+        signature.pageIndex = Module._GetSignaturePageIndex(signaturePtr)
+      }
+
+      signatures.push(signature)
     }
   }
-  return signatureList
+  return { signatures, signaturePtrList }
 }
 
 async function copyDocument(doc, password) {
@@ -3121,3 +3087,79 @@ function getSignatureAlgorithmType(signAlgOid) {
       return 'RSA_RSA';
   }
 }
+
+async function getSignCertData(certPtr) {
+  const version = Module._GetSignVersion(certPtr)
+  Module._GetSignAlgOid(certPtr)
+  const signAlgOid = U8StringData
+  const signAlgOidType = getSignatureAlgorithmType(signAlgOid)
+  const subject = []
+  for (let i = 0; i < 7; i++) {
+    Module._GetSignSubject(certPtr, i)
+    subject.push(U8StringData)
+  }
+  const issuer = []
+  for (let i = 0; i < 7; i++) {
+    Module._GetSignIssuer(certPtr, i)
+    issuer.push(U8StringData)
+  }
+  Module._GetSignSerialNumber(certPtr)
+  const serialNumber = U8StringData
+  Module._GetSignValidDate(certPtr, 0)
+  const validDateStart = U8StringData
+  Module._GetSignValidDate(certPtr, 1)
+  const validDateEnd = U8StringData
+
+  AccessInfoArray = []
+  Module._GetAuthorityInfoAccess(certPtr)
+  const sccessInfo = AccessInfoArray
+  Module._GetSubjectKeyIdentifier(certPtr)
+  const subjectKeyIdentifier = U8StringData
+  const keyUsage = Module._GetKeyUsage(certPtr)
+  PolicyArray = []
+  Module._GetCertificatePolicies(certPtr)
+  const certificatePolicies = PolicyArray
+  Module._GetAuthorityKeyIdentifier(certPtr)
+  const authorityKeyIdentifier = U8StringData
+  CRLPointArray = []
+  Module._GetCRLDistributionPoints(certPtr)
+  const CRLDistributionPoints = CRLPointArray
+
+  Module._GetBasicConstraints(certPtr)
+  const basicConstraints = U8StringData
+  Module._GetPublicKey(certPtr)
+  const publicKey = U8StringData
+  Module._GetX509Data(certPtr)
+  const X509Data = U8StringData
+  Module._GetSHA1Digest(certPtr)
+  const SHA1Digest = U8StringData
+  Module._GetMD5Digest(certPtr)
+  const MD5Digest = U8StringData
+
+  OCSPUrlArray = []
+  Module._GetOCSPUrl(certPtr)
+  const ocspURL = OCSPUrlArray
+
+  return {
+    version,
+    signAlgOid,
+    signAlgOidType,
+    subject,
+    issuer,
+    serialNumber,
+    validDateStart,
+    validDateEnd,
+    sccessInfo,
+    subjectKeyIdentifier,
+    keyUsage,
+    certificatePolicies,
+    authorityKeyIdentifier,
+    CRLDistributionPoints,
+    basicConstraints,
+    publicKey,
+    X509Data,
+    SHA1Digest,
+    MD5Digest,
+    ocspURL
+  }
+}

+ 2 - 2
packages/webview/src/components/Dialogs/CertificationViewerDialog.vue

@@ -13,7 +13,7 @@
             @focus="selectedSignerIndex = index"
             @blur="selectedSignerIndex = 0"
             tabindex="-1">
-            {{ signer.issuer[3] }}
+            {{ signer.certificateList[0].issuer[3] }}
           </p>
         </div>
 
@@ -93,7 +93,7 @@ const useDocument = useDocumentStore()
 
 const show = computed(() => useViewer.isElementOpen(dialogName))
 const signature = computed(() => useDocument.getSelectedSignature)
-const selectedSigner = computed(() => signature.value.signerList[selectedSignerIndex.value])
+const selectedSigner = computed(() => signature.value.signerList[0].certificateList[selectedSignerIndex.value])
 
 const activePanel = ref(1)
 const selectedSignerIndex = ref(0)

+ 1 - 1
packages/webview/src/components/Dialogs/SignatureDetailsDialog.vue

@@ -11,7 +11,7 @@
         <SignatureInvalid v-else-if="signature?.state === 'invalid'" />
         <SignatureUnknown v-else />
         <div>
-          <p class="title">{{ $t('signatures.detailsDialog.signBy') }} "{{ signature.signerList[0].issuer[3] }} &lt;{{ signature.signerList[0].issuer[6] }}&gt;".</p>
+          <p class="title">{{ $t('signatures.detailsDialog.signBy') }} "{{ signature.signerList[0].certificateList[0].issuer[3] }} &lt;{{ signature.signerList[0].certificateList[0].issuer[6] }}&gt;".</p>
           <p class="desc">{{ $t('signatures.detailsDialog.signingTime') }} {{ formatDate(signature.date) }}</p>
         </div>
       </div>

+ 0 - 1
packages/webview/src/components/SignatureContainer/SignatureContainer.vue

@@ -82,7 +82,6 @@ const openDialog = (name) => {
 const selectSign = (data) => {
   showPopover.value = true
   useDocument.setSelectedSignature(data)
-  console.log(data)
 }
 </script>