import PDFDocument from 'src/api/PDFDocument' ; import PDFPage from 'src/api/PDFPage' ; import { AppearanceProviderFor , normalizeAppearance , defaultCheckBoxAppearanceProvider , } from 'src/api/form/appearances' ; import { rgb } from 'src/api/colors' ; import { degrees } from 'src/api/rotations' ; import PDFField , { FieldAppearanceOptions , assertFieldAppearanceOptions , } from 'src/api/form/PDFField' ; import { PDFName , PDFRef , PDFDict , PDFAcroCheckBox , PDFWidgetAnnotation , } from 'src/core' ; import { assertIs , assertOrUndefined } from 'src/utils' ; /**
 * Represents a check box field of a [[PDFForm]].
 *
 * [[PDFCheckBox]] fields are interactive boxes that users can click with their
 * mouse. This type of [[PDFField]] has two states: `on` and `off`. The purpose
 * of a check box is to enable users to select from one or more options, where
 * each option is represented by a single check box. Check boxes are typically
 * square in shape and display a check mark when they are in the `on` state.
 */ export default class PDFCheckBox extends PDFField { param acroCheckBox param ref param doc static of = ( acroCheckBox , ref , doc ) => new PDFCheckBox ( acroCheckBox , ref , doc ) ; /** The low-level PDFAcroCheckBox wrapped by this check box. */ readonly acroField : PDFAcroCheckBox ; private constructor ( acroCheckBox , ref , doc ) { super ( acroCheckBox , ref , doc ) ; assertIs ( acroCheckBox , 'acroCheckBox' , [ [ PDFAcroCheckBox , 'PDFAcroCheckBox' ] , ] ) ; this . acroField = acroCheckBox ; } /**
     * Mark this check box. This operation is analogous to a human user clicking
     * a check box to fill it in a PDF reader. This method will update the
     * underlying state of the check box field to indicate it has been selected.
     * PDF libraries and readers will be able to extract this value from the
     * saved document and determine that it was selected.
     *
     * For example:
     * ```js
     * const checkBox = form.getCheckBox('some.checkBox.field')
     * checkBox.check()
     * ```
     *
     * This method will mark this check box as dirty, causing its appearance
     * streams to be updated when either [[PDFDocument.save]] or
     * [[PDFForm.updateFieldAppearances]] is called. The updated appearance
     * streams will display a check mark inside the widgets of this check box
     * field.
     */ check ( ) { const onValue = this . acroField . getOnValue ( ) ?? PDFName . of ( 'Yes' ) ; this . markAsDirty ( ) ; this . acroField . setValue ( onValue ) ; } /**
     * Clears this check box. This operation is analogous to a human user clicking
     * a check box to unmark it in a PDF reader. This method will update the
     * underlying state of the check box field to indicate it has been deselected.
     * PDF libraries and readers will be able to extract this value from the
     * saved document and determine that it was not selected.
     *
     * For example:
     * ```js
     * const checkBox = form.getCheckBox('some.checkBox.field')
     * checkBox.uncheck()
     * ```
     *
     * This method will mark this check box as dirty. See [[PDFCheckBox.check]]
     * for more details about what this means.
     */ uncheck ( ) { this . markAsDirty ( ) ; this . acroField . setValue ( PDFName . of ( 'Off' ) ) ; } returns isChecked ( ) { const onValue = this . acroField . getOnValue ( ) ; return ! ! onValue && onValue === this . acroField . getValue ( ) ; } param page param options addToPage ( page , options ? ) { assertIs ( page , 'page' , [ [ PDFPage , 'PDFPage' ] ] ) ; assertFieldAppearanceOptions ( options ) ; if ( ! options ) options = { } ; if ( ! ( 'textColor' in options ) ) options . textColor = rgb ( 0 , 0 , 0 ) ; if ( ! ( 'backgroundColor' in options ) ) options . backgroundColor = rgb ( 1 , 1 , 1 ) ; if ( ! ( 'borderColor' in options ) ) options . borderColor = rgb ( 0 , 0 , 0 ) ; if ( ! ( 'borderWidth' in options ) ) options . borderWidth = 1 ; const widget = this . createWidget ( { x : options . x ?? 0 , y : options . y ?? 0 , width : options . width ?? 50 , height : options . height ?? 50 , textColor : options . textColor , backgroundColor : options . backgroundColor , borderColor : options . borderColor , borderWidth : options . borderWidth ?? 0 , rotate : options . rotate ?? degrees ( 0 ) , hidden : options . hidden , page : page . ref , } ) ; const widgetRef = this . doc . context . register ( widget . dict ) ; this . acroField . addWidget ( widgetRef ) ; widget . setAppearanceState ( PDFName . of ( 'Off' ) ) ; this . updateWidgetAppearance ( widget , PDFName . of ( 'Yes' ) ) ; page . node . addAnnot ( widgetRef ) ; } returns needsAppearancesUpdate ( ) { const widgets = this . acroField . getWidgets ( ) ; for ( let idx = 0 , len = widgets . length ; idx < len ; idx ++ ) { const widget = widgets [ idx ] ; const state = widget . getAppearanceState ( ) ; const normal = widget . getAppearances ( ) ?. normal ; if ( ! ( normal instanceof PDFDict ) ) return true ; if ( state && ! normal . has ( state ) ) return true ; } return false ; } /**
     * Update the appearance streams for each of this check box's widgets using
     * the default appearance provider for check boxes. For example:
     * ```js
     * const checkBox = form.getCheckBox('some.checkBox.field')
     * checkBox.defaultUpdateAppearances()
     * ```
     */ defaultUpdateAppearances ( ) { this . updateAppearances ( ) ; } param provider updateAppearances ( provider ? ) { assertOrUndefined ( provider , 'provider' , [ Function ] ) ; const widgets = this . acroField . getWidgets ( ) ; for ( let idx = 0 , len = widgets . length ; idx < len ; idx ++ ) { const widget = widgets [ idx ] ; const onValue = widget . getOnValue ( ) ?? PDFName . of ( 'Yes' ) ; if ( ! onValue ) continue ; this . updateWidgetAppearance ( widget , onValue , provider ) ; } this . markAsClean ( ) ; } private updateWidgetAppearance ( widget , onValue , provider ? ) { const apProvider = provider ?? defaultCheckBoxAppearanceProvider ; const appearances = normalizeAppearance ( apProvider ( this , widget ) ) ; this . updateOnOffWidgetAppearance ( widget , onValue , appearances ) ; } }