MCPcopy Create free account
hub / github.com/modelcontextprotocol/ext-apps / extractFormFieldInfo

Function extractFormFieldInfo

examples/pdf-server/server.ts:1079–1136  ·  view source on GitHub ↗

* Extract detailed form field info (name, type, page, bounding box, label) * from a PDF. Bounding boxes are converted to model coordinates (top-left origin).

(
  pdfDoc: PDFDocumentProxy,
)

Source from the content-addressed store, hash-verified

1077 * from a PDF. Bounding boxes are converted to model coordinates (top-left origin).
1078 */
1079async function extractFormFieldInfo(
1080 pdfDoc: PDFDocumentProxy,
1081): Promise<FormFieldInfo[]> {
1082 const fields: FormFieldInfo[] = [];
1083 for (let i = 1; i <= pdfDoc.numPages; i++) {
1084 const page = await pdfDoc.getPage(i);
1085 const pageHeight = page.getViewport({ scale: 1.0 }).height;
1086 const annotations = await page.getAnnotations();
1087 for (const ann of annotations) {
1088 // Only include form widgets (annotationType 20)
1089 if (ann.annotationType !== 20) continue;
1090 if (!ann.rect) continue;
1091
1092 const fieldName = ann.fieldName || "";
1093 const fieldType = ann.fieldType || "unknown";
1094
1095 // PDF rect is [x1, y1, x2, y2] in bottom-left origin
1096 const x1 = Math.min(ann.rect[0], ann.rect[2]);
1097 const y1 = Math.min(ann.rect[1], ann.rect[3]);
1098 const x2 = Math.max(ann.rect[0], ann.rect[2]);
1099 const y2 = Math.max(ann.rect[1], ann.rect[3]);
1100 const width = x2 - x1;
1101 const height = y2 - y1;
1102
1103 // Convert to model coords (top-left origin): modelY = pageHeight - pdfY - height
1104 const modelY = pageHeight - y2;
1105
1106 // Choice widgets (combo/listbox) carry `options` as
1107 // [{exportValue, displayValue}]. Expose export values — that's
1108 // what fill_form needs.
1109 let options: string[] | undefined;
1110 if (Array.isArray(ann.options) && ann.options.length > 0) {
1111 options = ann.options
1112 .map((o: { exportValue?: string }) => o?.exportValue)
1113 .filter((v: unknown): v is string => typeof v === "string");
1114 }
1115
1116 fields.push({
1117 name: fieldName,
1118 type: fieldType,
1119 page: i,
1120 x: Math.round(x1),
1121 y: Math.round(modelY),
1122 width: Math.round(width),
1123 height: Math.round(height),
1124 ...(ann.alternativeText ? { label: ann.alternativeText } : undefined),
1125 // Radio: buttonValue is the per-widget export value — the only
1126 // thing distinguishing three `size [Btn]` lines from each other.
1127 ...(ann.radioButton && ann.buttonValue != null
1128 ? { exportValue: String(ann.buttonValue) }
1129 : undefined),
1130 ...(options?.length ? { options } : undefined),
1131 });
1132 }
1133 }
1134
1135 return fields;
1136}

Callers 1

probeFormFieldsFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…