如何为多个PDF页面同时添加注释?

如果您需要为一个在编辑器上已经打开的PDF的多个页面添加注释, 需要注意的事,开发包示例中的接口为FRPageViewAddAnnot(),只能对已加载过视图的(用户浏览过的)页面添加注释。如果要对还未加载的页面添加注释,可以使用FRDocAddAnnot()接口添加注释。

示例代码如下:

void CreateAnnot()
{
FS_FloatPoint pointLeftTop, pointRightBottom;
pointLeftTop.m_PointX = 100;
pointRightBottom.m_PointX = 400;
pointLeftTop.m_PointY = 200;
pointRightBottom.m_PointY=100;

FR_Document frDocument = FRAppGetActiveDocOfPDDoc();
FPD_Document fpdDocument = FRDocGetPDDoc(frDocument);
FR_DocView frDocView = FRDocGetCurrentDocView(frDocument);
FR_PageView frPageView = FRDocViewGetCurrentPageView(frDocView);

for (int i = 0; i < FPDDocGetPageCount(fpdDocument); i++)
{
FS_FloatRect rectFirst;
rectFirst.left = pointLeftTop.m_PointX;
rectFirst.right = pointRightBottom.m_PointX;;
rectFirst.bottom = pointRightBottom.m_PointY;
rectFirst.top = pointLeftTop.m_PointY;
FR_Annot frAnnot = FRDocAddAnnot(frDocument, i, "Stamp", rectFirst);
FPD_Annot fpdAnnot = FRAnnotGetPDFAnnot(frAnnot);

FR_Page frPage = FRDocGetPage(frDocument, i);

FPD_Page fpdPage = FPDPageNew();

FPD_Object pPageDict = FPDDocGetPage(fpdDocument, i);
FPDPageLoad(fpdPage, fpdDocument, pPageDict, TRUE);

FPD_Object fpdObject =
FPDAnnotGetAnnotDict(fpdAnnot);// FPDDictionaryNew();
//set subtype of the annot
FPD_Object fpdfstringAnnot = FPDNameNew("Annot");
FPDDictionaryAddValue(fpdObject, "Type", fpdfstringAnnot);
FPDDictionaryAddValue(fpdObject, "Subtype", FPDNameNew("Stamp"));
FPDDictionaryAddValue(fpdObject, "Subj", FPDStringNew(FSByteStringNew3("Stamp", -1), 0));


//set quadpoints of the annot
FPD_Object quad = FPDArrayNew(); //{x1, y1, x2, y2, x3, y3, x4, y5}
FPDArrayAddNumber(quad, rectFirst.left); //x1
FPDArrayAddNumber(quad, rectFirst.top);//y1
FPDArrayAddNumber(quad, rectFirst.right);//x2
FPDArrayAddNumber(quad, rectFirst.top);//y2
FPDArrayAddNumber(quad, rectFirst.left);//x3
FPDArrayAddNumber(quad, rectFirst.bottom);//y3
FPDArrayAddNumber(quad, rectFirst.right);//x4
FPDArrayAddNumber(quad, rectFirst.bottom);//y4
FPDDictionaryAddValue(fpdObject, "QuadPoints", quad);
FPDDictionaryAddValue(fpdObject, "NM", FPDNameNew("TextName"));

FPDDictionaryAddValue(fpdObject, "T", FPDNameNew("AuthorTest"));

FPD_Object quadColor = FPDArrayNew();
FS_COLORREF color = RGB(255, 215, 0);
//set color of the annot
FPDArrayAddNumber(quadColor, (FS_FLOAT)GetRValue(color) / 255.0f); //1 means RGB Color
FPDArrayAddNumber(quadColor, (FS_FLOAT)GetGValue(color) / 255.0f); //Defines the color
FPDArrayAddNumber(quadColor, (FS_FLOAT)GetBValue(color) / 255.0f); //Defines the color
FPDDictionaryAddValue(fpdObject, "C", quadColor);

FS_LPCWSTR ws = (FS_LPCWSTR)L"This is initial text";
FPD_Object fpdfstringPopout = FPDStringNewW(ws);
//set comment info of the annot
FPDDictionaryAddValue(fpdObject, "Contents", fpdfstringPopout);
//set BBox of the annot
FPDDictionarySetAtRect(fpdObject, "Rect", rectFirst);
auto pAPDict = FPDDictionaryGetDict(fpdObject, "AP");
if (pAPDict == nullptr)
{
pAPDict = FPDDictionarySetNewAt(fpdObject, "AP", FPD_OBJ_DICTIONARY);
}
FS_DWORD dwApObjNum = 0;
FS_DIBitmap pBitmap = FSDIBitmapLoadFromPNGIcon(L"D:\\test\\thumbnail_image001.png");
FPD_Object pObj = CreateAppearanceDict(fpdDocument, pBitmap, 0, &dwApObjNum);
FPDDictionarySetAtReferenceToDoc(pAPDict, "N", fpdDocument, dwApObjNum);
FPDDictionaryAddValue(fpdObject, "AP", pAPDict);

//将新增注释添加到侧边栏的注释列表中
if (frAnnot != NULL)
{
FR_MarkupPanel panel = FRMarkupPanelGetMarkupPanel();
if (panel)
{
FRMarkupPanelAddAnnot(panel, frAnnot, TRUE, TRUE);
}
}
}
//刷新当前页面,让注释显示
FRDocReloadPage(frDocument, FRPageViewGetPageIndex(FRDocViewGetCurrentPageView(frDocView)), FALSE);
}

上面这个示例是添加的”图章”注释,所以会用到。如果是其他类型注释例如”高亮”不一定需要下面的代码

//添加注释外观
FPD_Object CreateAppearanceDict(FPD_Document pdfDoc, FS_DIBitmap bitmap, int nRotate, FS_DWORD* pObjNum)
{
	if (!pdfDoc || !bitmap)
		return nullptr;
	FS_DWORD dwNewObjNumber = 0;
	FPD_Object apperenceDict = FPDDictionaryNew();

	FS_AffineMatrix streamMatrix;
	switch (nRotate)
	{
	case 0:
	{
		streamMatrix.a = 1.0f;
		streamMatrix.b = 0.0f;
		streamMatrix.c = 0.0f;
		streamMatrix.d = 1.0f;
	}
	break;
	case 90:
	{
		streamMatrix.a = 0.0f;
		streamMatrix.b = 1.0f;
		streamMatrix.c = -1.0f;
		streamMatrix.d = 0.0f;
	}
	break;
	case 180:
	{
		streamMatrix.a = -1.0f;
		streamMatrix.b = 0.0f;
		streamMatrix.c = 0.0f;
		streamMatrix.d = -1.0f;
	}
	break;
	case 270:
	{
		streamMatrix.a = 0.0f;
		streamMatrix.b = -1.0f;
		streamMatrix.c = 1.0f;
		streamMatrix.d = 0.0f;
	}
	break;
	default:
		break;
	}
	streamMatrix.e = 0;
	streamMatrix.f = 0;
	FPDDictionarySetAtMatrix(apperenceDict, "Matrix", streamMatrix);
	FPD_Object resourcesDict = FPDDictionaryNew();
	FPD_Object xObject = FPDDictionaryNew();

	FPD_Image image = FPDImageNew(pdfDoc);
	//ON_SCOPE_EXIT([&] {

	//});
	FPDImageSetImage(image, bitmap, FALSE, nullptr);
	FPD_Object imgStream = FPDImageGetStream(image);
	if (imgStream)
	{
		dwNewObjNumber = FPDDocAddIndirectObject(pdfDoc, imgStream);
		FPDDictionarySetAtReferenceToDoc(xObject, "ImgSignature", pdfDoc, dwNewObjNumber);
	}
	FPDDictionarySetAt(resourcesDict, "XObject", xObject, nullptr);

	FPD_Object extGStateDict = FPDDictionaryNew();
	FPDDictionarySetAtNumber(extGStateDict, "CA", 1);
	FPDDictionarySetAtNumber(extGStateDict, "ca", 1);
	FS_DWORD dwNewExtGStateObjNumber = FPDDocAddIndirectObject(pdfDoc, extGStateDict);
	FPD_Object extGStateDictRef = FPDDictionaryNew();
	FPDDictionarySetAtReferenceToDoc(extGStateDictRef, "FXE1", pdfDoc, dwNewExtGStateObjNumber);
	FPDDictionarySetAt(resourcesDict, "ExtGState", extGStateDictRef, nullptr);

	FPDDictionarySetAt(apperenceDict, "Resources", resourcesDict, nullptr);

	int bmpWidth = FSDIBitmapGetWidth(bitmap);
	int bmpHeight = FSDIBitmapGetHeight(bitmap);

	FPD_Object streamBBox = FPDArrayNew();
	FPDArrayAddNumber(streamBBox, 0);
	FPDArrayAddNumber(streamBBox, 0);
	FPDArrayAddNumber(streamBBox, bmpWidth);
	FPDArrayAddNumber(streamBBox, bmpHeight);


	FPDDictionarySetAt(apperenceDict, "BBox", streamBBox, nullptr);
	FPDDictionarySetAtName(apperenceDict, "Type", "XObject");
	FPDDictionarySetAtName(apperenceDict, "Subtype", "Form");

	FS_ByteString apStreamData = FSByteStringNew();

	FSByteStringFormat(apStreamData, "q\n/FXE1 gs\n%d 0 0 %d 0 0 cm\n/ImgSignature Do\nQ", bmpWidth, bmpHeight);

	auto pNewContents = FPDStreamNew();
	FPDStreamInitStream(pNewContents, NULL, 0, apperenceDict);
	FPDStreamSetData(pNewContents, (FS_LPBYTE)FSByteStringCastToLPCBYTE(apStreamData),
		FSByteStringGetLength(apStreamData), FALSE, FALSE);
	auto dwObjNum = FPDDocAddIndirectObject(pdfDoc, pNewContents);
	if (pObjNum)
		*pObjNum = dwObjNum;

	FSByteStringDestroy(apStreamData);
	FPDImageDestroy(image);
	return pNewContents;
}

效果如下: