I've ran into a problem - I need to add a custom stamp (type of annotation) to a number of .pdf files. I can do it through Actions for Acrobat X Pro, but my clients do not have that license and they still need to do it. The list of files is stored in Excel spreadsheet, so ideally I am looking for a VBA solution. I have came up with the following code :
Option Explicit
Sub code1()
Dim app As Acrobat.AcroApp
Dim pdDoc As Acrobat.CAcroPDDoc
Dim page As Acrobat.CAcroPDPage
Dim recter(3) As Integer 'Array defining the rectangle of the stamp - in real code wil be calculated, simplified for ease of reading
Dim jso As Object
Dim annot As Object
Dim props As Object
Set pdDoc = Nothing
Set app = CreateObject("AcroExch.App")
Set pdDoc = CreateObject("AcroExch.PDDoc")
recter(0) = 100
recter(1) = 100
recter(2) = 350
recter(3) = 350
pdDoc.Open ("C:\Users\maxim_s\Desktop\Code_1\test1.pdf")
Set jso = pdDoc.GetJSObject
If Not jso Is Nothing Then
Set page = pdDoc.AcquirePage(0)
Set annot = jso.AddAnnot
Set props = annot.getprops
props.page = 0
props.Type = "Stamp"
props.AP = "#eIXuM60ZXCv0sI-vxFqvlD" 'this line throws an error. The string is correct name of the stamp I want to add
props.rect = recter
annot.setProps props
If pdDoc.Save(PDSaveFull, "C:\Users\maxim_s\Desktop\Code_1\test123.pdf") = False Then
MsgBox "fail"
pdDoc.Close
Else
MsgBox "success"
pdDoc.Close
End If
End If
End Sub
The problem is with the setprops and getprops procedures - it seems that at the moment when annotation is created (jso.AddAnnot) it does not posses the AP property, which is the name of the stamp I want to add. If I set the property Type= "Stamp" first and then try to specify the AP, the result is that one of the default stamps is added and it's AP is renamed to my custom stamps' AP. Also note, that if I launch acrobat and use the code below, the proper stamp is added:
this.addAnnot({page:0,type:"Stamp",rect:[100,100,350,350],AP:"#eIXuM60ZXCv0sI-vxFqvlD"})
If there is a way to execute this Javascript from VBA inside of the PDDoc object, that will solve the problem, but so far I have failed.
You can use "ExecuteThisJavaScript" from the AForm Api. Short example:
Set AForm = CreateObject("AFormAut.App")
AForm.Fields.ExecuteThisJavaScript "var x = this.numPages; app.alert(x);"
It has the advantage that you don't need to translate the js examples into jso code. If you search for ExecuteThisJavaScript you will get some more and longer examples.
Good luck, reinhard
In...
props.Type = "Stamp"
The type should be lower case. But if the pure JavaScript is working from the console, you might consider just executing the string using the jso.
Related
I try to write a mod for a game. This is totally new territory for me, so I might be on the wrong track here.
The game is written in Unity and you are able to add a .script file to your mod. The .script file can contain javascript that is parsed by Jint.
I tried to output a simple string from one of the game DLLs:
var UnityEngine = importNamespace("UnityEngine");
var IceEngine = importNamespace("IceEngine");
var GameMain = importNamespace("GameMain");
var output = GameMain.Game.ModPath;
UnityEngine.Debug.Log("----- Testmod Output Start-----");
UnityEngine.Debug.Log(output);
UnityEngine.Debug.Log("----- Testmod Output End-----");
In the GameMain.dll it says:
public class Game : MonoBehaviour, IUserManagerListener, IAccountMsg, IMsg, IRenderListener
{
private static string modPath = Game.userPath + "/Mods";
// lots of other code...
public static string ModPath
{
get
{
return Game.modPath;
}
}
My understanding is that GameMain.Game.ModPath should give me a string. But instead the output in the log file is this:
----- Testmod Output Start-----
System.Dynamic.ExpandoObject
----- Testmod Output End-----
No matter wehat I try to output, I get a System.Dynamic.ExpandoObject and don't know what to do with it.
Maybe someone can give me tips/resources to help. :)
The ExpandoObject is the nearest equivalent that .Net has for a JavaScript Object - that is an object to which members can be added or removed on-the-fly.
This suggests to me that the underlying JavaScript method is actually returning an object rather than a string.
You can use Newtonsoft.Json to serialize the object:
var json = (string)JsonConvert.SerializeObject(GameMain.Game.ModPath);
Which will allow you to see if there's a property you should be using. So let's say this gives you {"modPath":"..."}, you should access that property directly like this:
var modPath = (string)GameMain.Game.ModPath.modPath;
Body content is null in document properties showing this sign ""[] instead of content.
Also messsage box lotus script is showing null with getItemValue("Body").
How to resolve this ?
Sub Click(Source As Button)
Dim s As NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim col As NotesDocumentCollection
Set s = New NotesSession
Set db = s.CurrentDatabase
Set col = db.UnprocessedDocuments
Print "Collection Size:"& col.Count
Set doc = col.GetFirstDocument
If doc.HasItem("Body") Then
While Not doc Is Nothing
Dim body As Variant
body = doc.GetItemValue("Body")
Msgbox (body(0))
Set doc = col.GetNextDocument(doc)
Wend
End If
End Sub
Because (usually) Body is a Rich Text field, and these fields are treated differently. See the NotesRichTextItem in the Designer Help.
Starting from your code:
Set s = New NotesSession
Set db = s.CurrentDatabase
Set col = db.UnprocessedDocuments
Print "Collection Size:"& col.Count
Set doc = col.GetFirstDocument
While Not doc Is Nothing
Dim body As Variant
If doc.HasItem("Body") Then
Set body = doc.GetFirstItem("Body") ' now body contains the richtext item'
Msgbox body.UnformattedText
End If
Set doc = col.GetNextDocument(doc)
Wend
Notes should convert the MIME item to rich text for you. If you want to deal with the MIME type, you have to use the NotesMimeHeader and NotesMimeEntity classes. See the Help database, especially the examples on these classes are interesting.
You cannot just reference a NotesRichtTextItem the same way you reference an ordinary NotesItem. A rich text field can contain graphics, tables, fonts, colors, and other things that are not text. It does not matter if it actually does contain those things; it is never a simple array of strings, so Body(0) is not defined. Look up the methods of the NotesRichTextItem class. You will find one called getUnformattedText which will return a simple text representation of the field value.
(There are options for getting the field value as HTML so that you get all the formatting tags, too, but only if the field is really stored as MIME instead of Notes rich text.)
Background
I have a load of Applescripts(AS) which designers use with InDesign that help process the workflow for production. There is a great deal of OS interaction that the AS does that the JavaScript can not, so moving away from AS is not possible.
Due restrictions I am unable to install pretty much anything.
I am unable to update anything. Script Editor and ExtendScript Tool Kit are what I have to work with.
Operating Environment:
OS X 10.8.5 &
Adobe CS6
How it works
User preferences are saved as Properties in local Applescripts saved in the user's documents folder.
###property grabber.scpt
set mypath to path to documents folder
set mypropertiesfile to ((mypath & "myproperties.scpt") as string)
set thePropertyScript to load script file mypropertiesfile
set designerinitials to (designerinitials of thePropertyScript) ETC...
Some of the properties are AS lists.
Why I need JS?
I'm making palettes and would prefer to use the ScriptUI rather than do it all in AS like this:
set dlgRef to make dialog with properties {name:"User Settings", can cancel:true, label:"Dialog Label"}
The string the AS hands off to the JS is this:
{"myname",{firstvalue:"test", secondvalue:"val2", thirdvalue: "val3"},{firstvalue:"test2", secondvalue:"val2", thirdvalue: "val3"}}
These are not lists, but text...
The JS
myAppleScript = new File("valid_path_to/property grabber.scpt");
var myreturn = app.doScript(myAppleScript, ScriptLanguage.applescriptLanguage);
var myname = myreturn[0];
var firstlist = myreturn[1];
var secondlist = myreturn[2];
ExtendScript data browser shows:
firstlist = {firstvalue:"test", secondvalue:"val2", thirdvalue: "val3"}
It is not an array...
I have tried using https://github.com/KAYLukas/applescript-json
to json encode the lists, but the same result.
firstlist = [{firstvalue:"test", secondvalue:"val2", thirdvalue: "val3"}]
I have also made it much simpler with just
firstlist = {"test","val2","val3"}
Still the JS treats it as a string and not an array.
Any ideas what I need to do or am doing wrong? I hope it simple and I feel stupid if I get an answer...
Glad you have something that works, but if you're passing text to ExtendScript, why not format it on the AS side to be ExtendScript-friendly, like ['firstvalue', 'secondvalue', 'thirdvalue"'] --but this would be a string in AS, like
--in AS:
"['firstvalue', 'secondvalue', 'thirdvalue"']"
Then, in ExtendScript, if that's in a variable, like, myData, you can do (as I just did in ExtendScript Toolkit):
//in JS:
myArray = eval(myData);
I know using eval() is evil in web work, but for ExtendScript stuff, it can be very useful.
I hate finding an answer after I take the time to post an elaborate question.
https://stackoverflow.com/a/14689556/1204387
var path = ((File($.fileName)).path); // this is the path of the script
// now build a path to another js file
// e.g. json lib https://github.com/douglascrockford/JSON-js
var libfile = File(path +'/_libs/json2.js');
if(libfile.exists)
$.evalFile(libfile);
Like Neo learning Kung Fu, it suddenly went, "Whoa, I know JSON!"
var firstlist = JSON.parse(myresult[1]);
Gives me workable objects
doScript can pass script args to one language to another. Here is a snippet inspired from the doc:
var aps = "tell application \"Adobe InDesign CC 2014\"\
tell script args\
set user to item 1 of {\"John\", \"Mike\", \"Brenda\"}\
set value name \"user\" value user\
\"This is the firest AppleScript script argument value.\"\
end tell\
end tell"
app.doScript(aps, ScriptLanguage.applescriptLanguage);
var user = app.scriptArgs.getValue("user");
alert( user+ "from JS" );
I don't think script args would return anything else than strings even if those could represent any kind of value. However a string can be easily turned into an array with a split method like this :
var aps = "set ls to {\"john\", \"mark\"}\
set n to count of items of ls\
set str to \"\"\
repeat with i from 1 to n\
set str to str & item i of ls\
if i < n then\
set str to str & \",\"\
end if\
end repeat\
tell application \"Adobe InDesign CC 2014\"\
tell script args\
set value name \"str\" value str\
end tell\
end tell";
app.doScript(aps, ScriptLanguage.applescriptLanguage);
var str = app.scriptArgs.getValue("str");
var arr = str.split(",");
alert( "Item 1 of APS list is \""+arr[0]+ "\" in the JS context" );
The idea is to flatten the APS list into a comma separated string that will be later splitted in the javascript context to turn it into an array.
In an application I am working on I need to get a list of the names of all applicationScope variable then I need to cycle through them and filter out the ones starting with a know string say $xyx. I thought that the applicationScope.keySet().
I'm using this code for starter:
var col = applicationScope.keySet();
var itr:java.util.Iterator = col.iterator();
if (itr.hasNext()){
var str:String = itr.next();
dBar.info(str,"Value = ");
}
if I put the variable col in a viewScope it shows a list of all the keys. but when I run the script the values displayed in the dBar info are not the keys but some other information that I'm not sure where it comes from.
I should just be able to iterat through the list of keys, am I missing something?
This code is in the before page loads event
After some poking around and experimenting I got this to work:
var col = applicationScope.keySet();
var itr:java.util.Iterator = col.iterator();
while (itr.hasNext()){
var str:Map.Entry = itr.next();
if (str.substring(0,9) == "$wfsLock_"){
//do stuff
}
}
so I'm now a happy camper.
Although your code works in SSJS, it is not correct (and that's why I don't like SSJS...).
The applicationScope is an implementation of the java.util.Map interface and the keySet() method returns a Set containing the keys in that Map. Every entry is (probably) a String (other data types like integers are actually also valid). The line
var str:Map.Entry = itr.next();
doesn't cast it to a Map.Entry: it doesn't really do anything: str remains a string.
The Map interface also has an entrySet() method that returns the entries (Map.Entry). You can use that to retrieve the key as well as the value:
var it = applicationScope.entrySet().iterator();
while (it.hasNext()) {
var entry = it.next();
print( entry.getKey() + " = " + entry.getValue() );
}
(in this code the print() line will use the toString() method of the key as well as the value to send information to the console)
I see from your code that you've installed my XPages Debug Toolbar. You can also use that to quickly check what's in the scopes and what the actual datatype is.
First time on StackOverFlow!
I am working on building an app that takes in a value through a UI Form TextBox. Once that form is submitted it calls a method that then appends a "/" to the value. The problem is that .append() is not available, because getElementById() returns a GenericWidget object and thus cannot be operated on as if it were a string. I have tried type casting it use .toString() in the var userinput = app.getElementById('input').toString; call and afterward using userinput = userinput.toString.
I have been working with Apps Script for about a month and a few days now and I think that casting to a different type other than GenericWidget would be helpful for anyone who wants to modify a value in a type specific way after passing the value to another method.
I have also done a good bit of research trying to find a solutiong for my problem but like a couple times in the past working with Apps Script I find that since it is a younger language there isn't as much helpful information as there is with languages like Javascript, HTML, and XML. Any help is appreciated.
You have to get the textBox value using e.parameter.textBoxName an then re-assign a value to the textBox. A short example will be more explicit
function doGet(){
var app = UiApp.createApplication();
var textbox = app.createTextBox().setName('txt').setId('txt')
// add other elements, handlers, callBackElements, etc...
}
function changetext(e){
var app = UiApp.getActiveApplication();
var textBoxValue = e.parameter.txt ; // get the value in the text box
var txtBoxWidget = app.getElementById('txt') ; get the widget by its ID
txtBoxWidget.setText(textBoxValue+'/'):// assign the modified value
return app ;// update the UI with new value
}