@@ -3349,7 +3349,13 @@ export class PdfiumNative implements IPdfiumExecutor {
33493349 annotation : PdfFreeTextAnnoObject ,
33503350 ) {
33513351 // Type-specific properties
3352- if ( ! this . setBorderStyle ( annotationPtr , PdfAnnotationBorderStyle . SOLID , 0 ) ) {
3352+ if (
3353+ ! this . setBorderStyle (
3354+ annotationPtr ,
3355+ PdfAnnotationBorderStyle . SOLID ,
3356+ annotation . strokeWidth ?? 0 ,
3357+ )
3358+ ) {
33533359 return false ;
33543360 }
33553361 if ( ! this . setAnnotationOpacity ( annotationPtr , annotation . opacity ?? 1 ) ) {
@@ -3361,21 +3367,42 @@ export class PdfiumNative implements IPdfiumExecutor {
33613367 if ( ! this . setAnnotationVerticalAlignment ( annotationPtr , annotation . verticalAlign ) ) {
33623368 return false ;
33633369 }
3370+ const daColor = annotation . strokeColor ?? annotation . fontColor ;
33643371 if (
33653372 ! this . setAnnotationDefaultAppearance (
33663373 annotationPtr ,
33673374 annotation . fontFamily === PdfStandardFont . Unknown
33683375 ? PdfStandardFont . Helvetica
33693376 : annotation . fontFamily ,
33703377 annotation . fontSize ,
3371- annotation . fontColor ,
3378+ daColor ,
33723379 )
33733380 ) {
33743381 return false ;
33753382 }
3383+ if ( annotation . strokeColor && annotation . strokeColor !== annotation . fontColor ) {
3384+ this . setAnnotationColor (
3385+ annotationPtr ,
3386+ annotation . fontColor ,
3387+ PdfAnnotationColorType . TextColor ,
3388+ ) ;
3389+ }
33763390 if ( annotation . intent && ! this . setAnnotIntent ( annotationPtr , annotation . intent ) ) {
33773391 return false ;
33783392 }
3393+ if (
3394+ annotation . calloutLine &&
3395+ annotation . calloutLine . length >= 2 &&
3396+ ! this . setCalloutLine ( doc , page , annotationPtr , annotation . calloutLine )
3397+ ) {
3398+ return false ;
3399+ }
3400+ if (
3401+ annotation . lineEnding !== undefined &&
3402+ ! this . setLineEndings ( annotationPtr , PdfAnnotationLineEnding . None , annotation . lineEnding )
3403+ ) {
3404+ return false ;
3405+ }
33793406 // Prefer color, fall back to deprecated backgroundColor
33803407 const bgColor = annotation . color ?? annotation . backgroundColor ;
33813408 if ( ! bgColor || bgColor === 'transparent' ) {
@@ -6463,6 +6490,9 @@ export class PdfiumNative implements IPdfiumExecutor {
64636490 * @returns `{ ok, left, top, right, bottom }`
64646491 * • `ok` – `true` when the annotation *has* an /RD entry
64656492 * • the four floats are 0 when `ok` is false
6493+ *
6494+ * Native PDFium exposes /RD as [left, bottom, right, top]. We remap it here
6495+ * to the model's stable { left, top, right, bottom } shape.
64666496 */
64676497 private getRectangleDifferences ( annotationPtr : number ) : {
64686498 ok : boolean ;
@@ -6473,29 +6503,29 @@ export class PdfiumNative implements IPdfiumExecutor {
64736503 } {
64746504 /* tmp storage ─────────────────────────────────────────── */
64756505 const lPtr = this . memoryManager . malloc ( 4 ) ;
6476- const tPtr = this . memoryManager . malloc ( 4 ) ;
6477- const rPtr = this . memoryManager . malloc ( 4 ) ;
64786506 const bPtr = this . memoryManager . malloc ( 4 ) ;
6507+ const rPtr = this . memoryManager . malloc ( 4 ) ;
6508+ const tPtr = this . memoryManager . malloc ( 4 ) ;
64796509
64806510 const ok = ! ! this . pdfiumModule . EPDFAnnot_GetRectangleDifferences (
64816511 annotationPtr ,
64826512 lPtr ,
6483- tPtr ,
6484- rPtr ,
64856513 bPtr ,
6514+ rPtr ,
6515+ tPtr ,
64866516 ) ;
64876517
64886518 const pdf = this . pdfiumModule . pdfium ;
64896519 const left = pdf . getValue ( lPtr , 'float' ) ;
6490- const top = pdf . getValue ( tPtr , 'float' ) ;
6491- const right = pdf . getValue ( rPtr , 'float' ) ;
64926520 const bottom = pdf . getValue ( bPtr , 'float' ) ;
6521+ const right = pdf . getValue ( rPtr , 'float' ) ;
6522+ const top = pdf . getValue ( tPtr , 'float' ) ;
64936523
64946524 /* cleanup ─────────────────────────────────────────────── */
64956525 this . memoryManager . free ( lPtr ) ;
6496- this . memoryManager . free ( tPtr ) ;
6497- this . memoryManager . free ( rPtr ) ;
64986526 this . memoryManager . free ( bPtr ) ;
6527+ this . memoryManager . free ( rPtr ) ;
6528+ this . memoryManager . free ( tPtr ) ;
64996529
65006530 return { ok, left, top, right, bottom } ;
65016531 }
@@ -6517,9 +6547,9 @@ export class PdfiumNative implements IPdfiumExecutor {
65176547 return this . pdfiumModule . EPDFAnnot_SetRectangleDifferences (
65186548 annotationPtr ,
65196549 rd . left ,
6520- rd . top ,
6521- rd . right ,
65226550 rd . bottom ,
6551+ rd . right ,
6552+ rd . top ,
65236553 ) ;
65246554 }
65256555
@@ -7503,11 +7533,16 @@ export class PdfiumNative implements IPdfiumExecutor {
75037533 const defaultStyle = this . getAnnotString ( annotationPtr , 'DS' ) ;
75047534 const da = this . getAnnotationDefaultAppearance ( annotationPtr ) ;
75057535 const bgColor = this . getAnnotationColor ( annotationPtr ) ;
7536+ const textColor = this . getAnnotationColor ( annotationPtr , PdfAnnotationColorType . TextColor ) ;
7537+ const borderStyle = this . getBorderStyle ( annotationPtr ) ;
75067538 const textAlign = this . getAnnotationTextAlignment ( annotationPtr ) ;
75077539 const verticalAlign = this . getAnnotationVerticalAlignment ( annotationPtr ) ;
75087540 const opacity = this . getAnnotationOpacity ( annotationPtr ) ;
75097541 const richContent = this . getAnnotRichContent ( annotationPtr ) ;
75107542 const rd = this . getRectangleDifferences ( annotationPtr ) ;
7543+ const intent = this . getAnnotIntent ( annotationPtr ) ;
7544+ const calloutLine = this . getCalloutLine ( doc , page , annotationPtr ) ;
7545+ const lineEndings = this . getLineEndings ( annotationPtr ) ;
75117546
75127547 return {
75137548 pageIndex : page . index ,
@@ -7516,10 +7551,10 @@ export class PdfiumNative implements IPdfiumExecutor {
75167551 rect,
75177552 fontFamily : da ?. fontFamily ?? PdfStandardFont . Unknown ,
75187553 fontSize : da ?. fontSize ?? 12 ,
7519- fontColor : da ?. fontColor ?? '#000000' ,
7554+ fontColor : textColor ?? da ?. fontColor ?? '#000000' ,
75207555 verticalAlign,
7521- color : bgColor , // fill color (matches shape convention)
7522- backgroundColor : bgColor , // deprecated alias
7556+ color : bgColor ,
7557+ backgroundColor : bgColor ,
75237558 opacity,
75247559 textAlign,
75257560 defaultStyle,
@@ -7532,6 +7567,14 @@ export class PdfiumNative implements IPdfiumExecutor {
75327567 bottom : rd . bottom ,
75337568 } ,
75347569 } ) ,
7570+ ...( intent && { intent } ) ,
7571+ ...( calloutLine && { calloutLine } ) ,
7572+ ...( lineEndings && { lineEnding : lineEndings . end } ) ,
7573+ ...( borderStyle . width > 0
7574+ ? { strokeWidth : borderStyle . width , strokeColor : da ?. fontColor ?? '#000000' }
7575+ : intent === 'FreeTextCallout'
7576+ ? { strokeWidth : 1 , strokeColor : da ?. fontColor ?? '#000000' }
7577+ : { } ) ,
75357578 ...this . readBaseAnnotationProperties ( doc , page , annotationPtr ) ,
75367579 } ;
75377580 }
@@ -9178,6 +9221,67 @@ export class PdfiumNative implements IPdfiumExecutor {
91789221 return ok ;
91799222 }
91809223
9224+ /**
9225+ * Read the callout line points (/CL) from a FreeText annotation.
9226+ * Returns an array of 2 or 3 Position points in device coords, or undefined.
9227+ *
9228+ * @private
9229+ */
9230+ private getCalloutLine (
9231+ doc : PdfDocumentObject ,
9232+ page : PdfPageObject ,
9233+ annotationPtr : number ,
9234+ ) : Position [ ] | undefined {
9235+ const count = this . pdfiumModule . EPDFAnnot_GetCalloutLineCount ( annotationPtr ) ;
9236+ if ( count === 0 ) {
9237+ return undefined ;
9238+ }
9239+
9240+ const FS_POINTF_SIZE = 8 ;
9241+ const pointsPtr = this . memoryManager . malloc ( count * FS_POINTF_SIZE ) ;
9242+ const result = this . pdfiumModule . EPDFAnnot_GetCalloutLine ( annotationPtr , pointsPtr , count ) ;
9243+ if ( result === 0 ) {
9244+ this . memoryManager . free ( pointsPtr ) ;
9245+ return undefined ;
9246+ }
9247+
9248+ const points : Position [ ] = [ ] ;
9249+ for ( let i = 0 ; i < count ; i ++ ) {
9250+ const px = this . pdfiumModule . pdfium . getValue ( pointsPtr + i * FS_POINTF_SIZE , 'float' ) ;
9251+ const py = this . pdfiumModule . pdfium . getValue ( pointsPtr + i * FS_POINTF_SIZE + 4 , 'float' ) ;
9252+ points . push ( this . convertPagePointToDevicePoint ( doc , page , { x : px , y : py } ) ) ;
9253+ }
9254+ this . memoryManager . free ( pointsPtr ) ;
9255+ return points ;
9256+ }
9257+
9258+ /**
9259+ * Set the callout line points (/CL) on a FreeText annotation.
9260+ * Converts from device coords to page coords before writing.
9261+ *
9262+ * @private
9263+ */
9264+ private setCalloutLine (
9265+ doc : PdfDocumentObject ,
9266+ page : PdfPageObject ,
9267+ annotPtr : number ,
9268+ points : Position [ ] ,
9269+ ) : boolean {
9270+ const pdf = this . pdfiumModule . pdfium ;
9271+ const FS_POINTF_SIZE = 8 ;
9272+
9273+ const buf = this . memoryManager . malloc ( FS_POINTF_SIZE * points . length ) ;
9274+ points . forEach ( ( v , i ) => {
9275+ const pagePt = this . convertDevicePointToPagePoint ( doc , page , v ) ;
9276+ pdf . setValue ( buf + i * FS_POINTF_SIZE + 0 , pagePt . x , 'float' ) ;
9277+ pdf . setValue ( buf + i * FS_POINTF_SIZE + 4 , pagePt . y , 'float' ) ;
9278+ } ) ;
9279+
9280+ const ok = this . pdfiumModule . EPDFAnnot_SetCalloutLine ( annotPtr , buf , points . length ) ;
9281+ this . memoryManager . free ( buf ) ;
9282+ return ok ;
9283+ }
9284+
91819285 /**
91829286 * Read the target of pdf bookmark
91839287 * @param docPtr - pointer to pdf document object
0 commit comments