Copy link to clipboard
Copied
Hello,
I am trying to create highlight annotation for the selected text over multiple line.
For example, see in the below image:
This is my selected text. Now when I apply the annotation to this text, it looks like below:
That means selection is getting extended while applying the annotation.
Here is my code:
I have used
ACCB1 void ACCB2 createRequirement(char *sectionName) {
AVDoc avDoc = AVAppGetActiveDoc();
if (avDoc == NULL) {
AVAlertNote("Please open the document first.");
return;
}
PDDoc pdDoc = AVDocGetPDDoc(avDoc);
ASFixedRect boundingRect;
PDPage page = NULL;
PDAnnot annot, hilightAnnot;
LPCWSTR secName = convertCharArrayToLPCWSTR(sectionName);
LPCWSTR arg = L"value";
DWORD size = 1024;
LPCWSTR filePath = convertCharArrayToLPCWSTR(iniFilePath);
PDTextSelect pdtext =static_cast<PDTextSelect>(AVDocGetSelection(avDoc));
char reqId[2048];
char ident[2048];
int numPages = PDDocGetNumPages(pdDoc);
//Check if text is not selected
if (pdtext == NULL) {
AVAlertNote("Please select the text first.");
if (sectionName != NULL) {
WritePrivateProfileString(_T(sectionName), _T("selectedText"), _T(""), _T(iniFilePath));
}
return;
}
if (sectionName != NULL) {
//Create requirement from Reqtify
GetPrivateProfileString(sectionName, "value", NULL, reqId, size, iniFilePath);
strcpy(ident,reqId);
}
else {
//Input box to create requirement manually
createInputDialogBox(0, NULL, L"Requirement creation", L"Requirement ID:", L"REQ");
if (TheText[0] == 0) {
return;
}
wstring reqIdent(TheText);
string str(reqIdent.begin(), reqIdent.end());
strcpy(ident, str.c_str());
}
//Get selected text
AVDocCopySelection(avDoc);
wchar_t* selectedText = getClipboardText();
if (selectedText == NULL) {
AVAlertNote("Could not copy to clipboard.");
return;
}
// Get the bounding box for the selection
PDTextSelectGetBoundingRect(pdtext, &boundingRect);
//Create a PDPage object
AVPageView currentPageView = AVDocGetPageView(avDoc);
ASInt32 pageNum = AVPageViewGetPageNum(currentPageView);
page = PDDocAcquirePage(pdDoc, pageNum);
PDColorValueRec yellow;
yellow.space = PDDeviceRGB;
yellow.value[0] = ASInt32ToFixed(1);
yellow.value[1] = ASInt32ToFixed(1);
yellow.value[2] = ASInt32ToFixed(0);
//Use the bbox to create a highight annotation QuadPoints
CosObj ArrayObj, RecObj;
CosDoc cd = PDDocGetCosDoc(pdDoc);
CosObj cosPage = PDPageGetCosObj(page);
ArrayObj = CosNewArray(cd, false, 8);
CosArrayPut(ArrayObj, 0, CosNewFixed(cd, false, boundingRect.right));
CosArrayPut(ArrayObj, 1, CosNewFixed(cd, false, boundingRect.bottom));
CosArrayPut(ArrayObj, 2, CosNewFixed(cd, false, boundingRect.left));
CosArrayPut(ArrayObj, 3, CosNewFixed(cd, false, boundingRect.bottom));
CosArrayPut(ArrayObj, 4, CosNewFixed(cd, false, boundingRect.right));
CosArrayPut(ArrayObj, 5, CosNewFixed(cd, false, boundingRect.top));
CosArrayPut(ArrayObj, 6, CosNewFixed(cd, false, boundingRect.left));
CosArrayPut(ArrayObj, 7, CosNewFixed(cd, false, boundingRect.top));
// for the Rect. Highlight annotations don't require, but API call to create annotation requires this key
RecObj = CosNewArray(cd, false, 4);
CosArrayPut(RecObj, 0, CosNewFixed(cd, false, boundingRect.left));
CosArrayPut(RecObj, 1, CosNewFixed(cd, false, boundingRect.right));
CosArrayPut(RecObj, 2, CosNewFixed(cd, false, boundingRect.bottom));
CosArrayPut(RecObj, 3, CosNewFixed(cd, false, boundingRect.top));
CosObj cosDict = CosNewDict(cd, true, 4);
CosDictPutKeyString(cosDict, "Subtype", CosNewNameFromString(cd, false, "Highlight"));
CosDictPutKeyString(cosDict, "QuadPoints", ArrayObj);
CosDictPutKeyString(cosDict, "Rect", RecObj);
annot = PDAnnotFromCosObj(cosDict);
hilightAnnot = CastToPDTextAnnot(annot);
//Open the annotation, set the text, and add it to a page
PDTextAnnotSetOpen(hilightAnnot, true);
PDTextAnnotSetContents(hilightAnnot, ident, strlen(ident));
//Fix 197842 starts
//Adds logged in Username as a Annotation title
char username[UNLEN + 1];
DWORD username_len = UNLEN + 1;
GetUserName(username, &username_len);
PDAnnotSetTitle(hilightAnnot, username, strlen(username));
//Fix 197842 ends
PDPageAddAnnot(page, -2, annot);
PDPageNotifyContentsDidChange(page);
PDAnnotSetColor(annot, &yellow);
AVPageViewDrawNow(currentPageView);
if (ASAtomFromString("Highlight") == PDAnnotGetSubtype(annot) && sectionName != NULL)
{
std::wstring text;
std::wstring str;
std::wstringstream stringStream;
stringStream << selectedText;
while (stringStream >> text)
{
str.append(text);
str.append(L" ");
}
trim(str);
LPCWSTR secName = convertCharArrayToLPCWSTR(sectionName);
LPCWSTR arg = L"selectedText";
LPCWSTR reqText = str.c_str();
LPCWSTR filePath = convertCharArrayToLPCWSTR(iniFilePath);
WritePrivateProfileStringW(secName, arg, reqText, filePath);
}
PDPageRelease(page);
}
I have used PDTextSelect to select the text and PDTextSelectGetBoundingRect to get the bounding rect of selected text.
Can you please tell me what is missing or wrong in this code?
Thank you in advance!!
Copy link to clipboard
Copied
You make only one quad point, the enclosing rectangle. The highlight correctly shows this. There is no magic to adjust the highlight to actual text. Normally there is a quad per selected line.
Copy link to clipboard
Copied
Okay. So, how can I get the quad for per selected line?
Copy link to clipboard
Copied
I believe there is a method to list or enumerate the quads for a PDTextSelect.
Copy link to clipboard
Copied
Hello,
As you said, I used PDTextSelectEnumQuads method to enumerate the quads and apply the annotation.
But this method returns quads to every word inside the selection text and hence, highlight annotation is getting applied to every word.
So now there are multiple annotations to selected text whereas my intention is to have only a single annotation.
How to merge these annotations into single one.
Any example or method names will be helpful.
Thanks.
Copy link to clipboard
Copied
It sounds as if you are making a new annotation for each quad that is enumerated. No. Collect all of the quads and make ONE annotation with all of the quads. No other methods are needed.
Copy link to clipboard
Copied
OK. But how to put those quads in Cos object? And to create annotation we need a Cos Dictionary with three keys as below:
How can I map those quad with my code?
Copy link to clipboard
Copied
Did you read the specification of QuadPoints in the PDF Reference?
Copy link to clipboard
Copied
Hello,
Yes, I read the PDF reference.
According to them, I created 8 X n array of quads where n is the number of quads.
Here is my code:
arr = CosNewArray(cd, false, quadCount);
for (int i = 0; i < quadCount; i++) {
ArrayObj = CosNewArray(cd, false, 8);
boundingRect = rects;
CosArrayPut(ArrayObj, 0, CosNewFixed(cd, false, boundingRect.right));
CosArrayPut(ArrayObj, 1, CosNewFixed(cd, false, boundingRect.bottom));
CosArrayPut(ArrayObj, 2, CosNewFixed(cd, false, boundingRect.left));
CosArrayPut(ArrayObj, 3, CosNewFixed(cd, false, boundingRect.bottom));
CosArrayPut(ArrayObj, 4, CosNewFixed(cd, false, boundingRect.right));
CosArrayPut(ArrayObj, 5, CosNewFixed(cd, false, boundingRect.top));
CosArrayPut(ArrayObj, 6, CosNewFixed(cd, false, boundingRect.left));
CosArrayPut(ArrayObj, 7, CosNewFixed(cd, false, boundingRect.top));
CosArrayPut(arr, i, ArrayObj);
}
CosObj cosDict = CosNewDict(cd, true, 4);
CosDictPutKeyString(cosDict, "Subtype", CosNewNameFromString(cd, false, "Highlight"));
CosDictPutKeyString(cosDict, "QuadPoints", arr);
annot = PDAnnotFromCosObj(cosDict);
But at line 28, I am receiving "Invalid annotation object" error.
Please help.
Copy link to clipboard
Copied
Ah, I see the problem. You are not creating an array of 8 x "n" numbers. Rather you are creating an array of "n" arrays. If your two quads were [a b c d e f g h] and [p q r s t u v w], you create [ [a b c d e f g h] [p q r s t u v w] ] but what is needed is [ a b c d e f g h p q r s t u v w ], just 16 numbers in 1 array.
Copy link to clipboard
Copied
Hello,
Thank you for this additional information.
Now I am able to create annotation. But the problem is when I select the annotation, selection border does not seem good.
Here is the snapshot when I select my highlighted annotation:
And here is my latest code:
ArrayObj = CosNewArray(cd, false, 8*quadCount);
RecObj = CosNewArray(cd, false, 4);
for (int i = 0; i < quadCount; i++) {
boundingRect = rects;
CosArrayPut(ArrayObj, index++, CosNewFixed(cd, false, boundingRect.right));
CosArrayPut(ArrayObj, index++, CosNewFixed(cd, false, boundingRect.bottom));
CosArrayPut(ArrayObj, index++, CosNewFixed(cd, false, boundingRect.left));
CosArrayPut(ArrayObj, index++, CosNewFixed(cd, false, boundingRect.bottom));
CosArrayPut(ArrayObj, index++, CosNewFixed(cd, false, boundingRect.right));
CosArrayPut(ArrayObj, index++, CosNewFixed(cd, false, boundingRect.top));
CosArrayPut(ArrayObj, index++, CosNewFixed(cd, false, boundingRect.left));
CosArrayPut(ArrayObj, index++, CosNewFixed(cd, false, boundingRect.top));
}
ASFixedRect annotLoc = rects[quadCount-1];
CosArrayPut(RecObj, 0, CosNewFixed(cd, false, annotLoc.left));
CosArrayPut(RecObj, 1, CosNewFixed(cd, false, annotLoc.right));
CosArrayPut(RecObj, 2, CosNewFixed(cd, false, annotLoc.bottom));
CosArrayPut(RecObj, 3, CosNewFixed(cd, false, annotLoc.top));
CosObj cosDict = CosNewDict(cd, true, 2);
CosDictPutKeyString(cosDict, "Subtype", CosNewNameFromString(cd, false, "Highlight"));
CosDictPutKeyString(cosDict, "QuadPoints", ArrayObj);
CosDictPutKeyString(cosDict, "Rect", RecObj);
annot = PDAnnotFromCosObj(cosDict);
Selection border should look like below:
What am I missing or doing wrong here?
Thanks.
Copy link to clipboard
Copied
Ah, this was not what I expected but I understand it. The selection gives you a quad for each word. But when you make a highlight in Acrobat I believe it stores a quad for each line.
You should examine existing annotations made by Acrobat to confirm this. (By examine, I mean look at PDF internals).
It it will be up to you to transform this information. Print out the selection quads and look for a pattern you can match. Do they have the same baseline? Or do you need to use more complex fuzzy logic? Interesting problem.
Copy link to clipboard
Copied
>>Print out the selection quads and look for a pattern you can match. Do they have the same baseline?
I did understand this statement. How to print out the selection quads and which matching pattern do you mean?
Copy link to clipboard
Copied
You must write code that analyses the quads (one per word), and derives a new list of quads (one per line). Your first step is to look in detail at the input, so you can start to derive an algorithm, to make your output.
Copy link to clipboard
Copied
But even if I make a list of quads for per line and make annotation, then when that annotation is selected, selection border will appear for each line. I want the border as I mentioned below image:
Copy link to clipboard
Copied
What set of quads is used in the example? It is time for detailed analysis of what you hope to copy.
Copy link to clipboard
Copied
Oh, that isn't what I said. I did NOT say to make a list of quads per line.
You need to make ONE annotation. If the selection has three lines it needs THREE sets of quads. Your difficult task is to work out the coordinates of the three quads you must make, from the many quads from each word.
Copy link to clipboard
Copied
@kundan24352562 do you have example code to PDTextSelectEnumQuads?