Hi Pete,
this is amazing! Thank you so much for you reply and this amazing script. Please DM me your paypal I would like to give you a tip.
Hi Pete,
this is amazing! Thank you so much for you reply and this amazing script. Please DM me your paypal I would like to give you a tip.
Glad it’s working! I plan to add annotations as part of another script so had to figure this out anyway. But thanks for the offer, it’s appreciated
Just wanted to give a shoutout to @pete31 for creating this script. I’ve previously looked into Skim to add annotations to PDFs, but wasn’t aware it could also be done via ObjC / Quartz. Thanks for writing this Pete!
@pete31 I’m slowly working towards integrating this script in my workflow. I’m trying to ‘reverse’ a Sheet (TSV) back into a PDF. Basically the output from “Summarize higlights as sheet”. Would it be possible to integrate the Note that goes with a highlight back into the PDF as well (I’m assuming it’s possible, but this PDF and Quartz magic is a bit above my paygrade )
It’s actually not that complicated, but the AS-ObjC-bridge makes the script very hard to read, in my opinion All these current application's something
are eating up so much space and brain power, it’s difficult to get to the bone of it.
const annotationProperties = $.NSMutableDictionary.init;
if (createAnnotation) {
const date = $.NSDate.date;
annotationProperties.setObjectForKey(date, $.PDFAnnotationKeyDate);
const annotation = $.PDFAnnotation.alloc.initWithBoundsForTypeWithProperties(...)
const quadPoints = $.NSMutableArray.init;
...
Using shorter variable names also might help to clarify the overall structure (yes, I know that these neverendingveryinformativestringsareusedeveninJava, but I never found them particularly helpful – camel case or not). The more I have to read, the more difficult it becomes to understand. That is true for normal text as well as for code. And it is of course by no means a criticism of @pete31’s script, of course.
Yes, using the script from this thread it’s
(thisAnnotation's setValue:("Hello World") forAnnotationKey:(current application's PDFAnnotationKeyContents))
This adds “Hello World” to every annotation’s content, of course this is just a demo.
-- This is a DEMO script. Do NOT use it to add annotations from Kindle MyClippings
-- Add PDF highlight annotations from Kindle MyClippings including "Hello World"
-- Note: This script adds annotations. It does not check whether annotations exist. Run it only one time.
use AppleScript version "2.4"
use framework "Foundation"
use framework "Quartz"
use scripting additions
property theHighlightColorIndex : 4 -- set a color, Preferences > Colors > Highlighting
property theDelimiter : "- Ihre Markierung bei Position" -- change to your language
set theArray to current application's NSMutableArray's new()
tell application id "DNtp"
try
set theRecords to selected records
if theRecords = {} then return
set theRecord to item 1 of theRecords
set theRecord_Text to plain text of theRecord
set theClippings to my tid(theRecord_Text, {linefeed & linefeed})
set theNames to {}
repeat with thisClipping in theClippings
try
set thisClipping to thisClipping as string
set theTextItems to my tid(thisClipping, {linefeed & "==========" & linefeed, linefeed & theDelimiter})
set thisSearchTerm to (characters 1 thru -2 in (item 1 of theTextItems)) as string
set thisName to item 2 of theTextItems
set theArray to my addSearchTerm(thisName, thisSearchTerm, theArray)
if thisName is not in theNames then set end of theNames to thisName
on error
error "Error: Parsing"
end try
end repeat
show progress indicator "Adding highlight annotations... " steps (count theNames) with cancel button
repeat with thisName in theNames
set thisName to thisName as string
set theResults to search "kind:pdf {any: name==" & thisName & space & "name==" & thisName & ".pdf}"
if theResults ≠ {} then
step progress indicator "... " & thisName
set thisResult_Path to path of item 1 of theResults
my addHighlightAnnotations(thisResult_Path, thisName, theArray)
else
log message "Script \"Add PDF highlight annotations from Kindle MyClippings\": No record with name \"" & thisName & "\""
end if
end repeat
hide progress indicator
on error error_message number error_number
hide progress indicator
if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
return
end try
end tell
on addHighlightAnnotations(thePath, theNameWithoutExtension, theArray)
try
set thePDF to current application's PDFDocument's alloc()'s initWithURL:(current application's |NSURL|'s fileURLWithPath:thePath)
set theSearchTerms to (theArray's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:("self.NameWithoutExtension = " & quoted form of theNameWithoutExtension)))'s valueForKey:"SearchTerm"
set theSearchTerms to (current application's NSOrderedSet's orderedSetWithArray:theSearchTerms)'s array()
set theSelectionsArray to current application's NSMutableArray's new()
repeat with i from 0 to ((theSearchTerms's |count|()) - 1)
set thisSearchTerm to (theSearchTerms's objectAtIndex:i)
set theResultSelections to (thePDF's findString:thisSearchTerm withOptions:0)
if theResultSelections's |count|() ≠ 0 then
set theSelectionsArray to my addSelectionToSelectionsArray(thisSearchTerm, theResultSelections, theSelectionsArray)
else
set thisSearchTerm_Components to (thisSearchTerm's componentsSeparatedByString:space)
repeat with j from 0 to ((thisSearchTerm_Components's |count|()) - 1)
set theseSearchTerm_Components_1 to (thisSearchTerm_Components's subarrayWithRange:{0, (thisSearchTerm_Components's |count|()) - j})
set thisSearchTerm_Part_1 to (theseSearchTerm_Components_1's componentsJoinedByString:space)
set theResultSelections to (thePDF's findString:thisSearchTerm_Part_1 withOptions:0)
if theResultSelections's |count|() ≠ 0 then
set theSelectionsArray to my addSelectionToSelectionsArray(thisSearchTerm_Part_1, theResultSelections, theSelectionsArray)
set thisLocation to (theseSearchTerm_Components_1's |count|())
set thisLength to (thisSearchTerm_Components's |count|()) - thisLocation
set theseSearchTerm_Components_2 to (thisSearchTerm_Components's subarrayWithRange:{thisLocation, thisLength})
set thisSearchTerm_Part_2 to (theseSearchTerm_Components_2's componentsJoinedByString:space)
set theResultSelections to (thePDF's findString:thisSearchTerm_Part_2 withOptions:0)
if theResultSelections's |count|() ≠ 0 then
set theSelectionsArray to my addSelectionToSelectionsArray(thisSearchTerm_Part_2, theResultSelections, theSelectionsArray)
end if
exit repeat
end if
end repeat
end if
end repeat
set theDeeperLookArray to current application's NSMutableArray's new()
repeat with i from 0 to ((theSearchTerms's |count|()) - 1)
set thisSearchTerm to (theSearchTerms's objectAtIndex:i)
repeat with j from 0 to ((theSearchTerms's |count|()) - 1)
set thatSearchTerm to (theSearchTerms's objectAtIndex:j)
if (thisSearchTerm's containsString:thatSearchTerm) and not (thisSearchTerm's isEqualTo:thatSearchTerm) then
(theDeeperLookArray's addObject:thatSearchTerm)
end if
end repeat
end repeat
if theHighlightColorIndex < 1 or theHighlightColorIndex > 7 then error "No valid HighlightColor index. Valid: 1-7"
if current application's id = "com.devon-technologies.think3" then
set theDefaults to current application's NSUserDefaults's standardUserDefaults()
else
set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.devon-technologies.think3"
end if
set theDictionary to (theDefaults's dictionaryRepresentation())'s dictionaryWithValuesForKeys:{"HighlightColor-0", "HighlightColor-1", "HighlightColor-2", "HighlightColor-3", "HighlightColor-4", "HighlightColor-5", "HighlightColor-6"}
set theColorDictionary to theDictionary's objectForKey:("HighlightColor-" & ((theHighlightColorIndex - 1) as string))
set theRed to current application's NSNumber's numberWithDouble:((theColorDictionary's valueForKey:"red"))
set theGreen to current application's NSNumber's numberWithDouble:((theColorDictionary's valueForKey:"green"))
set theBlue to current application's NSNumber's numberWithDouble:((theColorDictionary's valueForKey:"blue"))
set theAlpha to current application's NSNumber's numberWithDouble:((theColorDictionary's valueForKey:"alpha"))
set theHighlightColor to current application's NSColor's colorWithCalibratedRed:theRed green:theGreen blue:theBlue alpha:theAlpha
set theDocumentAuthor to (theDefaults's dictionaryRepresentation())'s stringForKey:"DocumentAuthor"
set theAnnotationSubtype to current application's PDFAnnotationSubtypeHighlight
set theAnnotationProperties to current application's NSMutableDictionary's new()
(theAnnotationProperties's setObject:theHighlightColor forKey:(current application's PDFAnnotationKeyColor))
repeat with i from 0 to ((theSelectionsArray's |count|()) - 1)
set thisItem to (theSelectionsArray's objectAtIndex:i)
set thisSearchTerm to (thisItem's valueForKey:"SearchTerm")
set thisResultSelection_BoundsForPage to (thisItem's valueForKey:"Selection_BoundsForPage")
set thisResultSelection_Lines_QuadPointsArray to (thisItem's valueForKey:"Selection_Lines_QuadPoints")
set createAnnotation to true
if (theDeeperLookArray's containsObject:thisSearchTerm) then
set thisResultSelection_Page_Label to (thisItem's valueForKey:"Selection_Page_Label")
set thisSelectionsArray_filtered to (theSelectionsArray's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:("self.Selection_Page_Label = " & quoted form of (thisResultSelection_Page_Label as string) & " AND " & "self.SearchTerm CONTAINS " & quoted form of (thisSearchTerm as string) & " AND " & "!self.SearchTerm = " & quoted form of (thisSearchTerm as string))))
repeat with j from 0 to ((thisSelectionsArray_filtered's |count|()) - 1)
set thatItem to (thisSelectionsArray_filtered's objectAtIndex:j)
set thatResultSelection_BoundsForPage to (thatItem's valueForKey:"Selection_BoundsForPage")
set thatResultSelection_Lines_QuadPointsArray to (thatItem's valueForKey:"Selection_Lines_QuadPoints")
set intersectsBoundsForPage to current application's NSIntersectsRect(thisResultSelection_BoundsForPage, thatResultSelection_BoundsForPage)
if intersectsBoundsForPage then
repeat with k from 0 to ((thisResultSelection_Lines_QuadPointsArray's |count|()) - 1) by 4
set thisResultSelection_Line_QuadPoints to (thisResultSelection_Lines_QuadPointsArray's subarrayWithRange:{k, 4})
set thisResultSelection_Line_Bounds to my makeRect(thisResultSelection_Line_QuadPoints)
repeat with l from 0 to ((thatResultSelection_Lines_QuadPointsArray's |count|()) - 1) by 4
set thatResultSelection_Line_QuadPoints to (thatResultSelection_Lines_QuadPointsArray's subarrayWithRange:{l, 4})
set thatResultSelection_Line_Bounds to my makeRect(thatResultSelection_Line_QuadPoints)
set intersectsBoundsForLine to current application's NSIntersectsRect(thisResultSelection_Line_Bounds, thatResultSelection_Line_Bounds)
if intersectsBoundsForLine then
set createAnnotation to false
exit repeat
end if
end repeat
if intersectsBoundsForLine then exit repeat
end repeat
if intersectsBoundsForLine then exit repeat
end if
end repeat
end if
if createAnnotation then
set thisDate to (current application's NSDate's |date|())
(theAnnotationProperties's setObject:thisDate forKey:(current application's PDFAnnotationKeyDate))
set thisAnnotation to (current application's PDFAnnotation's alloc()'s initWithBounds:(thisResultSelection_BoundsForPage) forType:theAnnotationSubtype withProperties:theAnnotationProperties)
set thisAnnotation_QuadPoints to current application's NSMutableArray's new()
repeat with i from 0 to ((thisResultSelection_Lines_QuadPointsArray's |count|()) - 1)
(thisAnnotation_QuadPoints's addObject:(current application's NSValue's valueWithPoint:(thisResultSelection_Lines_QuadPointsArray's objectAtIndex:i)))
end repeat
(thisAnnotation's setValue:(thisAnnotation_QuadPoints) forAnnotationKey:(current application's PDFAnnotationKeyQuadPoints))
--------------------------------------------------------------------- Add Contents ----------------------------------------------------------------------
(thisAnnotation's setValue:("Hello World") forAnnotationKey:(current application's PDFAnnotationKeyContents))
-------------------------------------------------------------------------------------------------------------------------------------------------
if not (theDocumentAuthor's isEqualTo:"") then (thisAnnotation's setUserName:theDocumentAuthor)
set thisResultSelection_Page to (thisItem's valueForKey:"Selection_Page")
(thisResultSelection_Page's addAnnotation:thisAnnotation)
end if
end repeat
thePDF's writeToFile:thePath
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"addHighlightAnnotations\"" message error_message as warning
error number -128
end try
end addHighlightAnnotations
on addSelectionToSelectionsArray(thisSearchTerm, theResultSelections, theSelectionsArray)
try
repeat with i from 0 to ((theResultSelections's |count|()) - 1)
set thisResultSelection to (theResultSelections's objectAtIndex:i)
set thisResultSelection_Pages to thisResultSelection's pages()
repeat with j from 0 to ((thisResultSelection_Pages's |count|()) - 1)
set thisResultSelection_Page to (thisResultSelection_Pages's objectAtIndex:j)
set thisResultSelection_BoundsForPage to (thisResultSelection's boundsForPage:thisResultSelection_Page)
set thisResultSelection_Lines to thisResultSelection's selectionsByLine
set thisResultSelection_Lines_QuadPointsArray to current application's NSMutableArray's new()
repeat with k from 0 to ((thisResultSelection_Lines's |count|()) - 1)
set thisResultSelection_Line to (thisResultSelection_Lines's objectAtIndex:k)
set thisResultSelection_Line_Page to (thisResultSelection_Line's pages())'s firstObject()
if (thisResultSelection_Line_Page's isEqualTo:thisResultSelection_Page) then
set thisResultSelection_Line_BoundsForPage to (thisResultSelection_Line's boundsForPage:thisResultSelection_Line_Page)
set thisResultSelection_Line_BoundsForPage to current application's NSRect's NSInsetRect(thisResultSelection_Line_BoundsForPage, -1, -1) -- DEVONthink recognizes text more reliably
set MinX to current application's NSRect's NSMinX(thisResultSelection_Line_BoundsForPage)
set MinY to current application's NSRect's NSMinY(thisResultSelection_Line_BoundsForPage)
set MaxX to current application's NSRect's NSMaxX(thisResultSelection_Line_BoundsForPage)
set MaxY to current application's NSRect's NSMaxY(thisResultSelection_Line_BoundsForPage)
(thisResultSelection_Lines_QuadPointsArray's addObject:{MinX, MaxY})
(thisResultSelection_Lines_QuadPointsArray's addObject:{MaxX, MaxY})
(thisResultSelection_Lines_QuadPointsArray's addObject:{MinX, MinY})
(thisResultSelection_Lines_QuadPointsArray's addObject:{MaxX, MinY})
end if
end repeat
set thisResultSelection_Page_Label to thisResultSelection_Page's label()
(theSelectionsArray's addObject:{Selection_Page:thisResultSelection_Page, Selection_Page_Label:thisResultSelection_Page_Label, Selection_BoundsForPage:thisResultSelection_BoundsForPage, Selection_Lines_QuadPoints:thisResultSelection_Lines_QuadPointsArray, SearchTerm:thisSearchTerm})
end repeat
end repeat
return theSelectionsArray
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"addSelectionToSelectionsArray\"" message error_message as warning
error number -128
end try
end addSelectionToSelectionsArray
on makeRect(theSelection_QuadPoints)
try
set theSelection_QuadPoints to (theSelection_QuadPoints as list)
set MinX to theSelection_QuadPoints's item 1's item 1
set MinY to theSelection_QuadPoints's item 3's item 2
set theWidth to (theSelection_QuadPoints's item 2's item 1) - MinX
set theHeight to (theSelection_QuadPoints's item 1's item 2) - MinY
set theRect to current application's NSRect's NSMakeRect(MinX, MinY, theWidth, theHeight)
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"makeRect\"" message error_message as warning
error number -128
end try
end makeRect
on addSearchTerm(theNameWithoutExtension, theSearchTerm, theArray)
try
(theArray's addObject:{NameWithoutExtension:theNameWithoutExtension, SearchTerm:theSearchTerm})
return theArray
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"addSearchTerm\"" message error_message as warning
error number -128
end try
end addSearchTerm
on tid(theInput, theDelimiter)
set d to AppleScript's text item delimiters
set AppleScript's text item delimiters to theDelimiter
if class of theInput = text then
set theOutput to text items of theInput
else if class of theInput = list then
set theOutput to theInput as text
end if
set AppleScript's text item delimiters to d
return theOutput
end tid
Thanks Pete. I can see that the note is added when I run “Summarize higlights” again (and also because “Remove note” is shown when right-clicking the highlight). There’s no visual marker for the note like when I add it manually (the little yellow block). Is there a way to create that too?
Agreed. One improvement could be to do something like this on top of the script
property ca : current application
property NSUserDefault: ca's NSUserDefault
...
Where do you see this? Couldn’t find that in the contextual menus.
Not sure what you mean. Here’s what I see after running the demo script:
@cgrunenberg a selected annotation’s contents column is hard to read in dark mode (DEVONthink 3.8.3, macOS 10.14.6)
Thanks, already fixed in the latest internal builds.
When I add a note to a highlight there’s a small yellow marker that appears:
It seems this might be a text annotation icon defined by PDFTextAnnotationIconType
(PDFAnnotation | Apple Developer Documentation) but I’m struggling a bit to find the right ASObjC syntax to try and add it.
Ah, you want to add another annotation instead of adding text to the highlight annotation.
That should be possible, but where should it be added? You placed the ones you added manually where you saw that there’s free space (i.e. no text in the PDF), so the script would need to check that in order to don’t overlap with another line. That should be possible but I can’t do that now.
I’m slowly starting to understand more PDF It seems it’s a “popup” type note with a highlight. I have not created these manually but did the following:
DT does the (auto)placement of the ‘squares’ - they’re not manual.
Definitely. Personally, I’d also get rid of all these these, those, this, that, the etc. Never got the point of them (wow, never saw a “them” actually in AS code).
Yes, that’s correct.
I love this script @pete31 - it feels like proper magic I’ve updated the script so you can give it a list containing search terms and a comment and it will add it back to the PDF like such:
property theHighlightColorIndex : 1 -- set a color, Preferences > Colors > Highlighting
tell application id "DNtp"
set thePath to path of first item of (selection as list)
set itemA to {"Something very important", "Check out these references"}
set itemB to {"A sentence to highlight", "Don't forget this"}
set theHighlightItems to {itemA, itemB}
my addHighlightAnnotations(thePath, theHighlightItems, theHighlightColorIndex)
end tell
There might be some tweaking needed at some point removing some current application
references as well as juggling lists and arrays, but it works exactly like expected for now.
use AppleScript version "2.4"
use framework "Foundation"
use framework "Quartz"
use scripting additions
on addHighlightAnnotations(thePath, theItems, theHighlightColorIndex)
try
set thePDF to current application's PDFDocument's alloc()'s initWithURL:(current application's |NSURL|'s fileURLWithPath:thePath)
set theItems to (current application's NSArray's arrayWithArray:theItems)
set theSelectionsArray to current application's NSMutableArray's new()
repeat with i from 0 to ((theItems's |count|()) - 1)
set thisItem to (theItems's objectAtIndex:i)
set thisSearchTerm to ((current application's NSArray's arrayWithArray:thisItem)'s objectAtIndex:0)
set thisComment to ((current application's NSArray's arrayWithArray:thisItem)'s objectAtIndex:1)
set theResultSelections to (thePDF's findString:thisSearchTerm withOptions:0)
if theResultSelections's |count|() ≠ 0 then
set theSelectionsArray to my addSelectionToSelectionsArray(thisSearchTerm, theResultSelections, thisComment, theSelectionsArray)
else
set thisSearchTerm_Components to (thisSearchTerm's componentsSeparatedByString:space)
repeat with j from 0 to ((thisSearchTerm_Components's |count|()) - 1)
set theseSearchTerm_Components_1 to (thisSearchTerm_Components's subarrayWithRange:{0, (thisSearchTerm_Components's |count|()) - j})
set thisSearchTerm_Part_1 to (theseSearchTerm_Components_1's componentsJoinedByString:space)
set theResultSelections to (thePDF's findString:thisSearchTerm_Part_1 withOptions:0)
if theResultSelections's |count|() ≠ 0 then
set theSelectionsArray to my addSelectionToSelectionsArray(thisSearchTerm_Part_1, theResultSelections, thisComment, theSelectionsArray)
set thisLocation to (theseSearchTerm_Components_1's |count|())
set thisLength to (thisSearchTerm_Components's |count|()) - thisLocation
set theseSearchTerm_Components_2 to (thisSearchTerm_Components's subarrayWithRange:{thisLocation, thisLength})
set thisSearchTerm_Part_2 to (theseSearchTerm_Components_2's componentsJoinedByString:space)
set theResultSelections to (thePDF's findString:thisSearchTerm_Part_2 withOptions:0)
if theResultSelections's |count|() ≠ 0 then
set theSelectionsArray to my addSelectionToSelectionsArray(thisSearchTerm_Part_2, theResultSelections, thisComment, theSelectionsArray)
end if
exit repeat
end if
end repeat
end if
end repeat
set theDeeperLookArray to current application's NSMutableArray's new()
repeat with i from 0 to ((theItems's |count|()) - 1)
set thisSearchTerm to ((current application's NSArray's arrayWithArray:(theItems's objectAtIndex:i))'s objectAtIndex:0)
repeat with j from 0 to ((theItems's |count|()) - 1)
set thatSearchTerm to ((current application's NSArray's arrayWithArray:(theItems's objectAtIndex:j))'s objectAtIndex:0)
if (thisSearchTerm's containsString:thatSearchTerm) and not (thisSearchTerm's isEqualTo:thatSearchTerm) then
(theDeeperLookArray's addObject:thatSearchTerm)
end if
end repeat
end repeat
if theHighlightColorIndex < 1 or theHighlightColorIndex > 7 then error "No valid HighlightColor index. Valid: 1-7"
if current application's id = "com.devon-technologies.think3" then
set theDefaults to current application's NSUserDefaults's standardUserDefaults()
else
set theDefaults to current application's NSUserDefaults's alloc()'s initWithSuiteName:"com.devon-technologies.think3"
end if
set theDictionary to (theDefaults's dictionaryRepresentation())'s dictionaryWithValuesForKeys:{"HighlightColor-0", "HighlightColor-1", "HighlightColor-2", "HighlightColor-3", "HighlightColor-4", "HighlightColor-5", "HighlightColor-6"}
set theColorDictionary to theDictionary's objectForKey:("HighlightColor-" & ((theHighlightColorIndex - 1) as string))
set theRed to current application's NSNumber's numberWithDouble:((theColorDictionary's valueForKey:"red"))
set theGreen to current application's NSNumber's numberWithDouble:((theColorDictionary's valueForKey:"green"))
set theBlue to current application's NSNumber's numberWithDouble:((theColorDictionary's valueForKey:"blue"))
set theAlpha to current application's NSNumber's numberWithDouble:((theColorDictionary's valueForKey:"alpha"))
set theHighlightColor to current application's NSColor's colorWithCalibratedRed:theRed green:theGreen blue:theBlue alpha:theAlpha
set theDocumentAuthor to (theDefaults's dictionaryRepresentation())'s stringForKey:"DocumentAuthor"
set theAnnotationSubtype to current application's PDFAnnotationSubtypeHighlight
set theAnnotationProperties to current application's NSMutableDictionary's new()
(theAnnotationProperties's setObject:theHighlightColor forKey:(current application's PDFAnnotationKeyColor))
repeat with i from 0 to ((theSelectionsArray's |count|()) - 1)
set thisItem to (theSelectionsArray's objectAtIndex:i)
set thisSearchTerm to (thisItem's valueForKey:"SearchTerm")
set thisComment to (thisItem's valueForKey:"Comment")
set thisResultSelection_BoundsForPage to (thisItem's valueForKey:"Selection_BoundsForPage")
set thisResultSelection_Lines_QuadPointsArray to (thisItem's valueForKey:"Selection_Lines_QuadPoints")
set createAnnotation to true
if (theDeeperLookArray's containsObject:thisSearchTerm) then
set thisResultSelection_Page_Label to (thisItem's valueForKey:"Selection_Page_Label")
set thisSelectionsArray_filtered to (theSelectionsArray's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:("self.Selection_Page_Label = " & quoted form of (thisResultSelection_Page_Label as string) & " AND " & "self.SearchTerm CONTAINS " & quoted form of (thisSearchTerm as string) & " AND " & "!self.SearchTerm = " & quoted form of (thisSearchTerm as string))))
repeat with j from 0 to ((thisSelectionsArray_filtered's |count|()) - 1)
set thatItem to (thisSelectionsArray_filtered's objectAtIndex:j)
set thatResultSelection_BoundsForPage to (thatItem's valueForKey:"Selection_BoundsForPage")
set thatResultSelection_Lines_QuadPointsArray to (thatItem's valueForKey:"Selection_Lines_QuadPoints")
set intersectsBoundsForPage to current application's NSIntersectsRect(thisResultSelection_BoundsForPage, thatResultSelection_BoundsForPage)
if intersectsBoundsForPage then
repeat with k from 0 to ((thisResultSelection_Lines_QuadPointsArray's |count|()) - 1) by 4
set thisResultSelection_Line_QuadPoints to (thisResultSelection_Lines_QuadPointsArray's subarrayWithRange:{k, 4})
set thisResultSelection_Line_Bounds to my makeRect(thisResultSelection_Line_QuadPoints)
repeat with l from 0 to ((thatResultSelection_Lines_QuadPointsArray's |count|()) - 1) by 4
set thatResultSelection_Line_QuadPoints to (thatResultSelection_Lines_QuadPointsArray's subarrayWithRange:{l, 4})
set thatResultSelection_Line_Bounds to my makeRect(thatResultSelection_Line_QuadPoints)
set intersectsBoundsForLine to current application's NSIntersectsRect(thisResultSelection_Line_Bounds, thatResultSelection_Line_Bounds)
if intersectsBoundsForLine then
set createAnnotation to false
exit repeat
end if
end repeat
if intersectsBoundsForLine then exit repeat
end repeat
if intersectsBoundsForLine then exit repeat
end if
end repeat
end if
if createAnnotation then
set thisDate to (current application's NSDate's |date|())
(theAnnotationProperties's setObject:thisDate forKey:(current application's PDFAnnotationKeyDate))
set thisAnnotation to (current application's PDFAnnotation's alloc()'s initWithBounds:(thisResultSelection_BoundsForPage) forType:theAnnotationSubtype withProperties:theAnnotationProperties)
set thisAnnotation_QuadPoints to current application's NSMutableArray's new()
repeat with i from 0 to ((thisResultSelection_Lines_QuadPointsArray's |count|()) - 1)
(thisAnnotation_QuadPoints's addObject:(current application's NSValue's valueWithPoint:(thisResultSelection_Lines_QuadPointsArray's objectAtIndex:i)))
end repeat
(thisAnnotation's setValue:(thisAnnotation_QuadPoints) forAnnotationKey:(current application's PDFAnnotationKeyQuadPoints))
if not (theDocumentAuthor's isEqualTo:"") then (thisAnnotation's setUserName:theDocumentAuthor)
set thisResultSelection_Page to (thisItem's valueForKey:"Selection_Page")
-- add popup
set popupAnnotationSubtype to current application's PDFAnnotationSubtypePopup
set popupAnnotation to (current application's PDFAnnotation's alloc()'s initWithBounds:(thisResultSelection_BoundsForPage) forType:popupAnnotationSubtype withProperties:theAnnotationProperties)
(thisAnnotation's setValue:thisComment forAnnotationKey:(current application's PDFAnnotationKeyContents))
(thisAnnotation's setValue:popupAnnotation forAnnotationKey:(current application's PDFAnnotationKeyPopup))
(thisResultSelection_Page's addAnnotation:thisAnnotation)
end if
end repeat
thePDF's writeToFile:thePath
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"addHighlightAnnotations\"" message error_message as warning
error number -128
end try
end addHighlightAnnotations
on addSelectionToSelectionsArray(thisSearchTerm, theResultSelections, theComment, theSelectionsArray)
try
repeat with i from 0 to ((theResultSelections's |count|()) - 1)
set thisResultSelection to (theResultSelections's objectAtIndex:i)
set thisResultSelection_Pages to thisResultSelection's pages()
repeat with j from 0 to ((thisResultSelection_Pages's |count|()) - 1)
set thisResultSelection_Page to (thisResultSelection_Pages's objectAtIndex:j)
set thisResultSelection_BoundsForPage to (thisResultSelection's boundsForPage:thisResultSelection_Page)
set thisResultSelection_Lines to thisResultSelection's selectionsByLine
set thisResultSelection_Lines_QuadPointsArray to current application's NSMutableArray's new()
repeat with k from 0 to ((thisResultSelection_Lines's |count|()) - 1)
set thisResultSelection_Line to (thisResultSelection_Lines's objectAtIndex:k)
set thisResultSelection_Line_Page to (thisResultSelection_Line's pages())'s firstObject()
if (thisResultSelection_Line_Page's isEqualTo:thisResultSelection_Page) then
set thisResultSelection_Line_BoundsForPage to (thisResultSelection_Line's boundsForPage:thisResultSelection_Line_Page)
set thisResultSelection_Line_BoundsForPage to current application's NSRect's NSInsetRect(thisResultSelection_Line_BoundsForPage, -1, -1) -- DEVONthink recognizes text more reliably
set MinX to current application's NSRect's NSMinX(thisResultSelection_Line_BoundsForPage)
set MinY to current application's NSRect's NSMinY(thisResultSelection_Line_BoundsForPage)
set MaxX to current application's NSRect's NSMaxX(thisResultSelection_Line_BoundsForPage)
set MaxY to current application's NSRect's NSMaxY(thisResultSelection_Line_BoundsForPage)
(thisResultSelection_Lines_QuadPointsArray's addObject:{MinX, MaxY})
(thisResultSelection_Lines_QuadPointsArray's addObject:{MaxX, MaxY})
(thisResultSelection_Lines_QuadPointsArray's addObject:{MinX, MinY})
(thisResultSelection_Lines_QuadPointsArray's addObject:{MaxX, MinY})
end if
end repeat
set thisResultSelection_Page_Label to thisResultSelection_Page's label()
(theSelectionsArray's addObject:{Selection_Page:thisResultSelection_Page, Selection_Page_Label:thisResultSelection_Page_Label, Selection_BoundsForPage:thisResultSelection_BoundsForPage, Selection_Lines_QuadPoints:thisResultSelection_Lines_QuadPointsArray, SearchTerm:thisSearchTerm, Comment:theComment})
end repeat
end repeat
return theSelectionsArray
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"addSelectionToSelectionsArray\"" message error_message as warning
error number -128
end try
end addSelectionToSelectionsArray
on makeRect(theSelection_QuadPoints)
try
set theSelection_QuadPoints to (theSelection_QuadPoints as list)
set MinX to theSelection_QuadPoints's item 1's item 1
set MinY to theSelection_QuadPoints's item 3's item 2
set theWidth to (theSelection_QuadPoints's item 2's item 1) - MinX
set theHeight to (theSelection_QuadPoints's item 1's item 2) - MinY
set theRect to current application's NSRect's NSMakeRect(MinX, MinY, theWidth, theHeight)
on error error_message number error_number
activate
if the error_number is not -128 then display alert "Error: Handler \"makeRect\"" message error_message as warning
error number -128
end try
end makeRect
on tid(theInput, theDelimiter)
set d to AppleScript's text item delimiters
set AppleScript's text item delimiters to theDelimiter
if class of theInput = text then
set theOutput to text items of theInput
else if class of theInput = list then
set theOutput to theInput as text
end if
set AppleScript's text item delimiters to d
return theOutput
end tid
Glad it’s useful. You wrote
and I’m wondering in what situation that would be necessary. Does it perhaps have something to do with PDFs that got corrupted by PDFKit (i.e. applying annotations of a corrupted PDF to a new PDF)?
I’m wondering as well, especially since you can already convert a sheet into a PDF.
Sorry this might be a bit confusing, I mean applying the individual items of the TSV (the highlights and notes) as highlights and notes back to the accompanying PDF.
No - it’s a different workflow altogether. I’m clipping everything I find for reference to PDF and automatically create annotations in Markdown. After that I most times read the PDF and highlight + take notes (in DT or on other devices). Highlights and notes get extracted to the annotation file again. That works well.
But there’s also another type of reading where after clipping I continue reading the webpage and going through it I add selection of the webpage to the annotation file (by appending them). Those annotations obviously are not present in the PDF. I’m using this script to add them afterwards as highlights so I’m keeping my annotation file and highlights in sync. Also this means PDF become portable and have all the relevant content, even without the annotation file.