PDF Metadata

Hi
i’m trying to set a metadata “kMDItemKeywords” of a pdf file in order to keep an specific information i would like to store.
But impossible to find how to do that with Illustrator when i save the file or via Finder and Acrobat
Any idea will be very helpfull
Regards

Hi,

the simplest way is using exiftool:


property exiftoolPath : "/usr/local/bin/exiftool"

set newMetadataValue to "This is a new metadata"
set imagePath to quoted form of (POSIX path of (choose file of type "pdf"))

-- Add new metadata "Keywords"
do shell script exiftoolPath & " -Keywords=" & quoted form of newMetadataValue & space & imagePath

-- Get all metadata
do shell script exiftoolPath & " -a -u -g1 " & imagePath

Another option to KniazidisR’s perfectly adequate solution.


use framework "Foundation"
use scripting additions

try
	set PDFDocumentPath to POSIX path of (choose file with prompt "Select a PDF Document" default location (path to documents folder) of type {"pdf"})
on error
	return -- User canceled selecting a PDF Document
end try

set PDFDocumentURL to current application's NSURL's fileURLWithPath:PDFDocumentPath
set PDFDocument to current application's PDFDocument's alloc()'s initWithURL:PDFDocumentURL

set PDFAttributes to current application's NSMutableDictionary's dictionaryWithDictionary:(PDFDocument's documentAttributes())
PDFAttributes's setValue:{"these", "are", "my", "keywords"} forKey:"Keywords"

set PDFDocument's documentAttributes to PDFAttributes

set PDFDocumentSaved to PDFDocument's writeToURL:PDFDocumentURL withOptions:(missing value) -- Could be done more safely

if PDFDocumentSaved then
	return "Success"
else
	return "Failure"
end if

The way I have saved the modified PDF Document is not the best or safest way to do it.
But only used on this occasion as a simple example.

Regards Mark

Thanks !!
Works fine. I try to adapt to have the same solution for jpg but don’t arrive to do it :frowning:

Hey Mark,
I tried with kMDItemComment (see: https://developer.apple.com/documentation/coreservices/kmditemcomment?language=objc) by using:

PDFAttributes's setValue:{"mytexthere"} forKey:"Comment"
or using  
PDFAttributes's setValue:"mytexthere" forKey:"Comment" -- without the {}

but it didn’t work. Any suggestion?
(I also tried with with kMDItemAuthors, also without success)

Thanks
L.

Apple’s PDFDocument class that I was using does not have a “Comment” attribute.
Thats not to say a PDF Document cannot have a “Comment” attribute, it just means that if your using my technique with the PPDFDocument class, you cannot set one.

Here’s the PDFDocument class’s get and set attributes.
https://developer.apple.com/documentation/pdfkit/pdfdocumentattribute

And here is an example of how you use them.


set PDFDocumentURL to current application's NSURL's fileURLWithPath:PDFDocumentPath
set PDFDocument to current application's PDFDocument's alloc()'s initWithURL:PDFDocumentURL

set myPDFDocAttributes to {Author:"me", CreationDate:missing value, Creator:"me again", Keywords:{"my", "keywords"}, ModDate:missing value, Producer:"also me", Subject:"PDF Doc's", Title:"PDF Doc Attr"}
-- A record containing all the available PDF Document key and value pairs, that you can set to your own values.
-- The CreationDate: and ModDate: keys have to be set to an NSDate class, and the Keywords: key to an array of strings.
-- If you leave the CreationDate: and ModDate: keys as missing value, the Mac's operating system will add the current date.
-- If you leave the Producer: key empty, the Mac's operating system will fill it with it's OS version.
-- If you leave any of the other string values empty, they will not appear in the saved PDF Doc's attributes.

set PDFDocument's documentAttributes to myPDFDocAttributes

Please see the comments I’ve let after the “myPDFDocAttributes” declaration.
These notes are based on my experimentation, but you may find other behaviours with further experiments.

You only have to use the “{}” braces if an array type is required, and “” if a string is required.

So if you wanted to set the CreationDate: or ModDate: attributes, you would do like this


set theDate to current application's NSDate's |date|()

set myPDFDocAttributes to {Author:"", CreationDate:theDate, Creator:"", Keywords:{}, ModDate: theDate, Producer:"", Subject:"", Title:""}

-- OR

PDFAttributes's setValue:theDate forKey:"CreationDate"

Please be aware that the documentation you link to is for Apple’s “Core Services”, which the operating system uses for all file types, certain file types can have certain attributes, but not all of them, it depends on the file type involved.
For example a “txt” file might allow a “Comments” attribute, but a “csv” file might not, I’m not sure myself what attributes are allowed for different file types, so you will have to research that subject.

So in conclusion, if you want to set a “Comment” attribute to a PDF File, and this attribute type is an allowed valid PDF type, then you will have to use KniazidisR’s example to achieve it, and not use the PDFDocument class as in my example, but check first that a “Comment” attribute is a valid attribute for PDF documents.

You could also try opening up various PDF’s sent to you from others, and downloaded off the internet, to see the typical metadata attributes applied to the majority of PDF documents.
You could try this with the first part of my code in my first solution posting like this.


use framework "Foundation"
use scripting additions

try
	set PDFDocumentPath to POSIX path of (choose file with prompt "Select a PDF Document" default location (path to documents folder) of type {"pdf"})
on error
	return -- User canceled selecting a PDF Document
end try

set PDFDocumentURL to current application's NSURL's fileURLWithPath:PDFDocumentPath
set PDFDocument to current application's PDFDocument's alloc()'s initWithURL:PDFDocumentURL

return (PDFDocument's documentAttributes() as record)

Of the few PDF files that I tried, I have yet to find one with a “Comment” metadata attribute.
Which says a lot about common or valid PDF document metadata attributes.

Regards Mark

Thanks Mark! This is really helpful.
Is there a way to change only one attribute of the list myPDFDocAttributes ?

If I want to leave the title unchanged, Creator unchanged etc… and only “update” the Creator?

I know I could read all this values with ‘mdls’ or with ‘mdimport -t -d2’ , and then fill the list, but if there is a way to re-write only one value will make the process simpler.

Thanks again.
L.

I’m not sure I understand your question really, as the “myPDFDocAttributes” variable is not a AS list, but is an AS record.
So you could change the “Creator” key value like you would with any other AppleScript record key value.


set myPDFDocAttributes to {Author:"", CreationDate:missing value, Creator:"", Keywords:{}, ModDate:missing value, Producer:"", Subject:"", Title:""}

set Creator of myPDFDocAttributes to "Mark FX"

return myPDFDocAttributes

AppleScript records are the equivalent of an NSDictionary, although AS records are not as versatile as the Dictionary, but you can coerce back and forward between them.

If you want to check or loop through the keys of a PDF document attributes dictionary, then simply use conditionals or a repeat loop.


use framework "Foundation"
use scripting additions

try
	set PDFDocumentPath to POSIX path of (choose file with prompt "Select a PDF Document" default location (path to documents folder) of type {"pdf"})
on error
	return -- User canceled selecting a PDF Document
end try

set PDFDocumentURL to current application's NSURL's fileURLWithPath:PDFDocumentPath
set PDFDocument to current application's PDFDocument's alloc()'s initWithURL:PDFDocumentURL

set PDFAttributes to current application's NSMutableDictionary's dictionaryWithDictionary:(PDFDocument's documentAttributes()) -- This is a mutable NSDictionary

set PDFAttributeKeys to PDFAttributes's allKeys() as list -- Returns all of the keys

repeat with attribute in PDFAttributeKeys
	log attribute
end repeat

-- OR

if PDFAttributeKeys contains "Creator" then
	return true
else
	return false
end if

It does not matter if the “Creator:” key is in the PDF document attributes dictionary / record.


PDFAttributes's setValue:"Mark FX" forKey:"Creator"

Because the above will change it’s value if it exists, or add it to the dictionary / record if it does not.

I would recommend you read up on the NSDictionary class to learn more about working with the contained keys and values.
As you can also change and modify multiple key and value pairs simultaneously, which is not possible with AppleScript records.

Hope that helps

Regards Mark

Thanks Mark. Indeed I intended to say “record” and not “list”. I always think the the “record” is a sub-type of “list” … which maybe it is … Anyway. Thanks a lot !
I also realized that in your script that you first import all attributes with the command into a record:

set PDFAttributes to current application's NSMutableDictionary's dictionaryWithDictionary:(PDFDocument's documentAttributes())

and then change one (or more), with:

PDFAttributes's setValue:"Mark FX" forKey:"Creator"

consolidate the changes:

set PDFDocument's documentAttributes to PDFAttributes

finally save the changes.

set PDFDocumentSaved to PDFDocument's writeToURL:PDFDocumentURL withOptions:(missing value)

I have it clear now. At least it worked … :wink:
Thanks again.
L

Hi ldicroce

I’m pleased it all made sense to you in the end, as it can be confusing when mixing AppleScript code and class types, in the same code as AppleScriptObjC using Cocoa framework class types.

As powerful and welcomed as the AppleScriptObjC bridge is, it can make for unreadable code on occasions, and sometimes means reading Apple’s developer documentation to understand the framework classes, and how to use them.
But understanding that certain AppleScript class types are interchangeable with Foundation framework class types is necessary.

AppleScript list’s are interchangeable with NSArray’s, and AppleScript record’s are interchangeable with NSDictionary’s, although unlike AppleScript list’s and record’s which are editable, to make an NSArray and NSDictionary editable, you have to use the mutable types, NSMutableArray and NSMutableDictionary respectively.

Good luck with it.

Regards Mark