Skip to content
DemoAPI 参考文档FAQ

PDF 生成模板编辑器

开源可视化 PDF 生成引擎,支持自定义模板,并提供面向开发者的 API,灵活构建文档生成流程。

查看 GitHub
Guides

创建注释

ComPDF 支持多种类型的注释,包括文本注释、链接、图形、高亮、图章、手写标注以及音频注释,全面满足不同的注释需求。

ComPDF React Native SDK 提供两种方式创建注释:

  1. 通过 CPDFReaderView 组件的注释模式交互式创建注释。
  2. 通过 API 编程方式创建注释。

交互式创建注释

通过 CPDFReaderView,用户可以进入注释模式并通过触摸操作添加注释。注释的类型通过 setAnnotationMode() 方法设置。

tsx
const pdfReaderRef = useRef<CPDFReaderView>(null);

<CPDFReaderView
  ref={pdfReaderRef}
  document={samplePDF}
  configuration={ComPDFKit.getDefaultConfig({
  })}/>

await pdfReaderRef.current?.setAnnotationMode(CPDFAnnotationType.HIGHLIGHT);

完整支持的注释类型(CPDFAnnotationType 枚举)包括:

注释类型枚举值
文本注释NOTE
高亮HIGHLIGHT
下划线UNDERLINE
波浪线SQUIGGLY
删除线STRIKEOUT
墨水INK
铅笔PENCIL
圆形CIRCLE
矩形SQUARE
箭头ARROW
线段LINE
文本FREETEXT
电子签名SIGNATURE
图章注释STAMP
图片PICTURES
链接LINK
音频SOUND
退出绘制模式UNKNOWN

退出注释创建模式

完成注释后,可调用以下方法退出注释状态:

tsx
await pdfReaderRef.current?.setAnnotationMode(CPDFAnnotationType.UNKNOWN);

获取当前绘制注释类型

可用于判断当前是否处于注释状态或获取当前选中的注释工具:

tsx
const annotationMode = await pdfReaderRef.current?.getAnnotationMode();

使用自定义 UI 创建 Note 注释

如果需要用 React Native UI 替换 SDK 默认的 Note 编辑弹窗,将 autoShowNoteEditDialog 设为 false。创建流程如下:

  1. 用户选择 Note 工具并点击页面。
  2. SDK 先将 Note 注释添加到 PDF,再通过 onAnnotationCreationPrepared 返回该注释。
  3. 应用显示自定义输入 UI。
  4. 用户确认时,调用 updateAnnotation() 写入内容。
  5. 用户取消时,调用 removeAnnotation() 删除已创建的空 Note。

以下示例包含创建、确认和取消的完整流程:

tsx
import React, { useCallback, useMemo, useRef, useState } from "react";
import { Alert, Button, Modal, TextInput, View } from "react-native";
import {
  ComPDFKit,
  CPDFAnnotation,
  CPDFAnnotationType,
  CPDFNoteAnnotation,
  CPDFReaderView,
} from "@compdfkit_pdf_sdk/react_native";

export function CustomNoteReader({ document }: { document: string }) {
  const pdfReaderRef = useRef<CPDFReaderView>(null);
  const [pendingNote, setPendingNote] = useState<CPDFNoteAnnotation | null>(null);
  const [draftContent, setDraftContent] = useState("");

  const configuration = useMemo(
    () =>
      ComPDFKit.getDefaultConfig({
        annotationsConfig: {
          autoShowNoteEditDialog: false,
        },
      }),
    []
  );

  const closeNoteEditor = useCallback(() => {
    setPendingNote(null);
    setDraftContent("");
  }, []);

  const handleAnnotationCreationPrepared = useCallback(
    (type: CPDFAnnotationType, annotation: CPDFAnnotation | null) => {
      if (
        type === CPDFAnnotationType.NOTE &&
        annotation instanceof CPDFNoteAnnotation
      ) {
        setPendingNote(annotation);
        setDraftContent(annotation.content);
      }
    },
    []
  );

  const startCreatingNote = useCallback(async () => {
    await pdfReaderRef.current?.setAnnotationMode(CPDFAnnotationType.NOTE);
  }, []);

  const confirmNote = useCallback(async () => {
    const reader = pdfReaderRef.current;
    if (!reader || !pendingNote) {
      return;
    }

    try {
      pendingNote.update({ content: draftContent });
      await reader._pdfDocument.updateAnnotation(pendingNote);
      closeNoteEditor();
    } catch (error) {
      Alert.alert("保存失败", String(error));
    }
  }, [closeNoteEditor, draftContent, pendingNote]);

  const cancelNote = useCallback(async () => {
    const reader = pdfReaderRef.current;
    if (!reader || !pendingNote) {
      return;
    }

    try {
      const removed = await reader._pdfDocument.removeAnnotation(pendingNote);
      if (!removed) {
        Alert.alert("取消失败", "SDK 未能删除已创建的 Note 注释。");
        return;
      }
      closeNoteEditor();
    } catch (error) {
      Alert.alert("取消失败", String(error));
    }
  }, [closeNoteEditor, pendingNote]);

  return (
    <View style={{ flex: 1 }}>
      <Button
        title="创建 Note"
        onPress={() => void startCreatingNote()}
      />
      <CPDFReaderView
        ref={pdfReaderRef}
        document={document}
        configuration={configuration}
        style={{ flex: 1 }}
        onAnnotationCreationPrepared={handleAnnotationCreationPrepared}
      />

      <Modal
        visible={pendingNote !== null}
        transparent
        animationType="fade"
        onRequestClose={() => void cancelNote()}
      >
        <View style={{ flex: 1, justifyContent: "center", padding: 24 }}>
          <View style={{ padding: 16, backgroundColor: "white" }}>
            <TextInput
              value={draftContent}
              onChangeText={setDraftContent}
              placeholder="输入 Note 内容"
              multiline
            />
            <Button title="取消" onPress={() => void cancelNote()} />
            <Button title="保存" onPress={() => void confirmNote()} />
          </View>
        </View>
      </Modal>
    </View>
  );
}

注意: autoShowNoteEditDialog 只接管“新建 Note”流程。interceptNoteAction 用于拦截“点击已有 Note”的默认编辑行为,两者不能互相替代。

编程创建注释

ComPDF 还支持通过 API 编程方式创建注释。以下示例展示了如何在指定页面上创建各种类型注释。

注意: rect 参数定义了注释在页面上的位置和大小,坐标系的原点位于页面的左下角。

  • 创建便签注释

tsx
const annotations = [
  new CPDFNoteAnnotation({
    page: 0,
    createDate: new Date(),
    title: "ComPDF",
    content: "This is Note Annotation",
    rect: { left: 260, top: 740, right: 300, bottom: 700 },
  })
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);
  • 创建标记注释

标记注释包含高亮下划线波浪线删除线四种类型。

tsx
const annotations = [
  new CPDFMarkupAnnotation({
    type: CPDFAnnotationType.HIGHLIGHT,
    page: 1,
    createDate: new Date(),
    title: "ComPDF",
    content: "This is Highlight Annotation",
    rect: { left: 55, top: 800, right: 180, bottom: 770 },
    markedText: "Annotations",
    color: "#00aa00",
    alpha: 200,
  })
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);
  • 创建墨水注释(Ink)

tsx
const annotations = [
  new CPDFInkAnnotation({
    page: 0,
    createDate: new Date(),
    type: CPDFAnnotationType.INK,
    color: "#ff7043",
    borderWidth: 10,
    inkPath: [
      [
        [176.43, 72.22],
        [206.94, 78.95],
        [217.57, 82.21],
        [227.0, 85.49],
        [232.42, 87.92],
        [243.73, 91.83]
      ],
    ],
  })
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);
  • 创建图形注释

形状注释包括正方形、圆形、线条和箭头类型。

tsx
const annotations = [
  new CPDFSquareAnnotation({
    page: 0,
    title: "Title",
    content: "This is a square annotation with long content.",
    createDate: new Date(),
    rect: { left: 20, top: 200, right: 200, bottom: 100 },
    borderWidth: 5,
    borderColor: "#ff5722",
    fillColor: "#8bc34a",
    bordEffectType: CPDFBorderEffectType.SOLID,
    borderAlpha: 200,
    dashGap: 0,
    fillAlpha: 100,
  }),
  new CPDFCircleAnnotation({
    page: 0,
    title: "Title",
    content: "This is a circle annotation.",
    createDate: new Date(),
    rect: { left: 220, top: 200, right: 360, bottom: 100 },
    borderWidth: 5,
    borderColor: "#448aff",
    fillColor: "#ffeb3b",
    bordEffectType: CPDFBorderEffectType.SOLID,
    borderAlpha: 255,
    fillAlpha: 120,
    dashGap: 0,
  }),
  new CPDFLineAnnotation({                    // 线段注释示例, 线段类型注释无需设置rect参数,通过points确定位置
    title: "Title",
    page: 1,
    content: "This is a line annotation.",
    createDate: new Date(),
    borderWidth: 6,
    borderColor: "#55FF26",
    borderAlpha: 255,
    fillColor: "#000000",
    fillAlpha: 255,
    points: [
      [504, 219],                             // 线段的起点坐标
      [320, 88],                              // 线段的终点坐标
    ],
  }),
  new CPDFLineAnnotation({
    title: "Title",
    page: 1,
    content: "This is an arrow annotation.",
    createDate: new Date(),
    points: [
      [288, 342],
      [159, 209],
    ],
    borderWidth: 6,
    borderColor: "#009688",
    borderAlpha: 255,
    fillColor: "#009688",
    fillAlpha: 255,
    lineHeadType: CPDFLineType.SQUARE,
    lineTailType: CPDFLineType.OPEN_ARROW,
    dashGap: 0,
  })
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);

创建文本注释

tsx
const annotations = [
  new CPDFFreeTextAnnotation({
    title: "Freetext",
    page: 0,
    content: "Hello, ComPDF!",
    createDate: new Date(),
    rect: { left: 30, top: 750, right: 230, bottom: 700 },
    textAttribute: {
      color: "#000000",
      familyName: "Times",
      styleName: "Bold",
      fontSize: 20,
    },
    alpha: 255,
    alignment: CPDFAlignment.LEFT,
  })
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);

familyName 和 styleName 可选,若不指定则使用系统默认字体。可使用ComPDFKit.getFonts() 方法获取系统支持的字体列表。

创建图章注释

tsx
const annotations = [
  new CPDFStampAnnotation({                                     // 标准图章注释
    page: 0,
    title: "Stamp",
    content: "Approved",
    createDate: new Date(),
    rect: { left: 20, top: 300, right: 200, bottom: 260 },
    stampType: CPDFStampType.STANDARD,
    standardStamp: CPDFStandardStamp.COMPLETED,
  }),
  new CPDFStampAnnotation({                               // 自定义文字图章注释
    page: 0,
    title: "Stamp",
    content: "Custom Text Stamp",
    createDate: new Date(),
    rect: { left: 220, top: 300, right: 350, bottom: 260 },
    stampType: CPDFStampType.TEXT,
    textStamp: new CPDFTextStamp({
      content: "Test Text",
      date: textStampDate,
      shape: CPDFTextStampShape.rightTriangle,
      color: CPDFTextStampColor.red,
    }),
  })
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);

创建图片注释

tsx
const annotations = [
  new CPDFImageAnnotation({
    page: 0,
    title: "Stamp-Image",
    content: "Custom Image Stamp",
    createDate: new Date(),
    rect: { left: 380, top: 420, right: 550, bottom: 260 },
    image: "iVBORw0KGgoAAAANSUhEUgAAAgIAAABz...",
  }),
]
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);
  • 创建签名注释

tsx
const annotations = [
  new CPDFSignatureAnnotation({
    page: 1,
    title: "Stamp-Image",
    content: "Signature",
    createDate,
    rect: { left: 380, top: 420, right: 550, bottom: 260 },
    image: "iVBORw0KGgoAAAANSUhEUgAAAgIAAABz...",
  }),
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);
  • 创建链接注释

tsx
const annotations = [
  new CPDFLinkAnnotation({
    title: "ComPDF",
    page: 0,
    createDate,
    content: "Link Annotation",
    rect: { left: 248, top: 799, right: 407, bottom: 732 },
    action: CPDFUriAction.createWeb("https://www.compdf.com"),
  }),

  new CPDFLinkAnnotation({
    title: "ComPDF",
    page: 0,
    createDate,
    content: "Link Annotation",
    rect: { left: 374, top: 304, right: 530, bottom: 236 },
    action: CPDFGoToAction.toPage(2),
  }),

  new CPDFLinkAnnotation({
    title: "ComPDF",
    page: 0,
    content: "Link Annotation",
    createDate,
    rect: { left: 374, top: 199, right: 529, bottom: 121 },
    action: CPDFUriAction.createEmail("[email protected]"),
  }),
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);
  • 创建音频注释

tsx
const annotations = [
  new CPDFSoundAnnotation({
    title: "ComPDF",
    page: 0,
    content: "Sound Annotation",
    createDate,
    rect: { left: 75, top: 607, right: 119, bottom: 563 },
    soundPath,
  })
];
const document = pdfReaderRef?.current?._pdfDocument;
await document.addAnnotations(annotations);