Rev 505 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
210 | daniel-mar | 1 | /* |
268 | daniel-mar | 2 | This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop |
536 | daniel-mar | 3 | Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.net |
503 | daniel-mar | 4 | Copyright (C) 2018-2022 Daniel Marschall, ViaThinkSoft |
210 | daniel-mar | 5 | |
312 | daniel-mar | 6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
||
8 | the Free Software Foundation; either version 2 of the License, or |
||
9 | (at your option) any later version. |
||
210 | daniel-mar | 10 | |
312 | daniel-mar | 11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
14 | GNU General Public License for more details. |
||
210 | daniel-mar | 15 | |
312 | daniel-mar | 16 | You should have received a copy of the GNU General Public License |
17 | along with this program; if not, write to the Free Software |
||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
210 | daniel-mar | 19 | */ |
20 | |||
334 | daniel-mar | 21 | /* Portions Copyright 1996 - 1999 Adobe Systems Incorporated */ |
22 | /* All Rights Reserved. */ |
||
210 | daniel-mar | 23 | |
24 | //#include <stdio.h> |
||
25 | |||
26 | //#include "world.h" // must come before Photoshop includes |
||
27 | |||
28 | #include "ff.h" |
||
29 | |||
30 | #include "scripting.h" |
||
31 | //#include "ui.h" |
||
32 | #include "dbg.h" |
||
33 | |||
34 | //extern FilterRecordPtr gpb; |
||
35 | |||
217 | daniel-mar | 36 | OSErr put_cstring(PIWriteDescriptor token, DescriptorKeyID key, char* s) { |
37 | OSErr e; |
||
38 | size_t n = strlen(s); |
||
39 | Ptr p; |
||
40 | Handle h = PINEWHANDLE((int32)n); |
||
41 | p = PILOCKHANDLE(h, false); |
||
42 | memcpy(p, s, n); |
||
43 | PIUNLOCKHANDLE(h); |
||
44 | e = PIPutText(token, key, h); |
||
45 | PIDISPOSEHANDLE(h); /* Not 100% sure if we are supposed to dispose of handle. It doesn't crash though */ |
||
46 | return e; |
||
210 | daniel-mar | 47 | } |
48 | |||
217 | daniel-mar | 49 | char* get_cstring(PIReadDescriptor token) { |
505 | daniel-mar | 50 | size_t n; |
217 | daniel-mar | 51 | Ptr p; |
52 | char* str = NULL; |
||
53 | Handle h; |
||
54 | OSErr e = PIGetText(token, &h); |
||
210 | daniel-mar | 55 | |
482 | daniel-mar | 56 | if ((e == noErr) && h) { |
217 | daniel-mar | 57 | n = PIGETHANDLESIZE(h); |
58 | p = PILOCKHANDLE(h, false); |
||
59 | if ((str = (char*)malloc(n + 1))) { |
||
60 | memcpy(str, p, n); |
||
61 | str[n] = 0; |
||
62 | } |
||
63 | PIUNLOCKHANDLE(h); |
||
64 | PIDISPOSEHANDLE(h); /* Not 100% sure if we are supposed to dispose of handle. It doesn't crash though */ |
||
65 | } |
||
66 | return str; |
||
210 | daniel-mar | 67 | } |
68 | |||
69 | // If parm is NULL, then it is standalone, otherwise it is the main plugin |
||
70 | OSType getAeteKey(char c, PARM_T* parm) { |
||
217 | daniel-mar | 71 | // To make our plugin compatible with AppleScript, each key must |
72 | // be unique, since the namespace is global! |
||
73 | // Furthermore, the "uniqueID/scope" hstm-field in the PIPL must be empty. |
||
210 | daniel-mar | 74 | |
217 | daniel-mar | 75 | if (parm != NULL) { |
76 | unsigned long hash; |
||
77 | char* data; |
||
444 | daniel-mar | 78 | // char* debug = (char*)malloc(2000); |
393 | daniel-mar | 79 | // sprintf(debug, "getAeteKey %c with title %s/%s in STANDALONE PLUGIN", c, parm->szTitle, parm->szCategory); |
217 | daniel-mar | 80 | // simplealert(debug); |
424 | daniel-mar | 81 | // free(debug); |
210 | daniel-mar | 82 | |
217 | daniel-mar | 83 | // Use random AETE keys, because AppleScript has a global namespace |
84 | // and therefore requires unique AETE keys |
||
85 | data = (char*)malloc(0x300); |
||
86 | if (!data) return 0; |
||
87 | sprintf(data, "%s %s %c", |
||
393 | daniel-mar | 88 | parm->szCategory, |
89 | parm->szTitle, |
||
217 | daniel-mar | 90 | c); |
91 | hash = printablehash(djb2(data)); |
||
92 | free(data); |
||
93 | return hash; |
||
94 | } |
||
95 | else { |
||
444 | daniel-mar | 96 | // char* debug = (char*)malloc(2000); |
217 | daniel-mar | 97 | // sprintf(debug, "getAeteKey %c in MAIN PLUGIN", c); |
98 | // simplealert(debug); |
||
424 | daniel-mar | 99 | // free(debug); |
210 | daniel-mar | 100 | |
217 | daniel-mar | 101 | // Attention: AETE keys (xpr#, cTl#) must be equal in scripting.r, scripting.rc and scripting.c(getAeteKey)! |
102 | if (c == 'R') return 'xprR'; |
||
103 | if (c == 'G') return 'xprG'; |
||
104 | if (c == 'B') return 'xprB'; |
||
105 | if (c == 'A') return 'xprA'; |
||
106 | if ((c >= '0') && (c <= '9')) return 'cTl0' + (c - '0'); |
||
107 | return 0; |
||
108 | } |
||
210 | daniel-mar | 109 | } |
110 | |||
111 | /* return true if dialog should be shown */ |
||
112 | enum ScriptingShowDialog ReadScriptParamsOnRead(void) |
||
113 | { |
||
217 | daniel-mar | 114 | PIReadDescriptor token; |
115 | DescriptorKeyID key; |
||
116 | DescriptorTypeID type; |
||
117 | DescriptorKeyIDArray array = { NULLID }; |
||
118 | int32 flags; |
||
119 | //OSErr stickyError; |
||
120 | int32 v; |
||
210 | daniel-mar | 121 | |
217 | daniel-mar | 122 | if (DescriptorAvailable(NULL)) { /* playing back. Do our thing. */ |
123 | token = OpenReader(array); |
||
124 | if (token) { |
||
125 | while (PIGetKey(token, &key, &type, &flags)) { |
||
126 | if (key == getAeteKey('R', gdata->standalone ? &gdata->parm : NULL)) { |
||
424 | daniel-mar | 127 | if (expr[0]) free(expr[0]); |
217 | daniel-mar | 128 | expr[0] = get_cstring(token); |
129 | } |
||
130 | else if (key == getAeteKey('G', gdata->standalone ? &gdata->parm : NULL)) { |
||
424 | daniel-mar | 131 | if (expr[1]) free(expr[1]); |
217 | daniel-mar | 132 | expr[1] = get_cstring(token); |
133 | } |
||
134 | else if (key == getAeteKey('B', gdata->standalone ? &gdata->parm : NULL)) { |
||
424 | daniel-mar | 135 | if (expr[2]) free(expr[2]); |
217 | daniel-mar | 136 | expr[2] = get_cstring(token); |
137 | } |
||
138 | else if (key == getAeteKey('A', gdata->standalone ? &gdata->parm : NULL)) { |
||
424 | daniel-mar | 139 | if (expr[3]) free(expr[3]); |
217 | daniel-mar | 140 | expr[3] = get_cstring(token); |
141 | } |
||
142 | else { |
||
143 | int i; |
||
144 | for (i = 0; i <= 7; ++i) { |
||
456 | daniel-mar | 145 | if (key == getAeteKey((char)('0'+i), gdata->standalone ? &gdata->parm : NULL)) { |
217 | daniel-mar | 146 | PIGetInt(token, &v); |
453 | daniel-mar | 147 | if (v < 0) v = 0; |
456 | daniel-mar | 148 | else if (v > 255) v = 255; |
149 | slider[i] = (uint8_t)v; |
||
217 | daniel-mar | 150 | } |
151 | } |
||
152 | } |
||
153 | } |
||
210 | daniel-mar | 154 | |
217 | daniel-mar | 155 | /*stickyError =*/ CloseReader(&token); // closes & disposes. |
210 | daniel-mar | 156 | |
217 | daniel-mar | 157 | // all Filter Foundry parameters are optional, |
158 | // so we needn't worry if any are missing |
||
159 | } |
||
210 | daniel-mar | 160 | |
217 | daniel-mar | 161 | return gpb->descriptorParameters->playInfo == plugInDialogDisplay ? SCR_SHOW_DIALOG : SCR_HIDE_DIALOG; |
162 | } |
||
163 | else { |
||
164 | return SCR_NO_SCRIPT; |
||
165 | } |
||
210 | daniel-mar | 166 | } |
167 | |||
168 | OSErr WriteScriptParamsOnRead(void) |
||
169 | { |
||
217 | daniel-mar | 170 | PIWriteDescriptor token; |
171 | OSErr gotErr = noErr; |
||
172 | extern int ctls[], maps[], nplanes; |
||
173 | int i, allctls; |
||
210 | daniel-mar | 174 | |
217 | daniel-mar | 175 | if (DescriptorAvailable(NULL)) { /* recording. Do our thing. */ |
176 | // 1. Call openWriteDescriptorProc which will return a PIWriteDescriptor token, such as writeToken. |
||
177 | token = OpenWriter(); |
||
178 | if (token) { |
||
179 | // 2. Call various Put routines such as PutIntegerProc, PutFloatProc, etc., to add key/value pairs to writeToken. The keys and value types must correspond to those in your terminology resource. |
||
210 | daniel-mar | 180 | |
217 | daniel-mar | 181 | // write keys here |
182 | if (!gdata->standalone) { |
||
183 | if (nplanes > 0) put_cstring(token, getAeteKey('R', gdata->standalone ? &gdata->parm : NULL), expr[0]); |
||
184 | if (nplanes > 1) put_cstring(token, getAeteKey('G', gdata->standalone ? &gdata->parm : NULL), expr[1]); |
||
185 | if (nplanes > 2) put_cstring(token, getAeteKey('B', gdata->standalone ? &gdata->parm : NULL), expr[2]); |
||
186 | if (nplanes > 3) put_cstring(token, getAeteKey('A', gdata->standalone ? &gdata->parm : NULL), expr[3]); |
||
187 | } |
||
210 | daniel-mar | 188 | |
217 | daniel-mar | 189 | /* only write values for the sliders that are actually used! */ |
190 | allctls = checksliders(4, ctls, maps); |
||
191 | for (i = 0; i <= 7; ++i) { |
||
192 | if (allctls || ctls[i]) { |
||
456 | daniel-mar | 193 | PIPutInt(token, getAeteKey((char)('0'+i), gdata->standalone ? &gdata->parm : NULL), slider[i]); |
217 | daniel-mar | 194 | } |
195 | } |
||
196 | |||
197 | gotErr = CloseWriter(&token); /* closes and sets dialog optional */ |
||
198 | /* done. Now pass handle on to Photoshop */ |
||
199 | } |
||
200 | } |
||
201 | return gotErr; |
||
210 | daniel-mar | 202 | } |
203 | |||
204 | |||
205 | //------------------------------------------------------------------------------- |
||
206 | // |
||
207 | // HostDescriptorAvailable |
||
208 | // |
||
209 | // Determines whether the PIDescriptorParameters callback is available. |
||
210 | // |
||
211 | // Check for valid suite version, routine suite version, and routine count. |
||
212 | // Also check that the subset of routines we actually use is actually present. |
||
213 | // |
||
214 | //------------------------------------------------------------------------------- |
||
215 | |||
403 | daniel-mar | 216 | Boolean HostDescriptorAvailable(PIDescriptorParameters* procs, Boolean* outNewerVersion) |
210 | daniel-mar | 217 | { |
403 | daniel-mar | 218 | if (procs == NULL) return FALSE; // Photoshop < 4.0 don't has scripting |
219 | |||
217 | daniel-mar | 220 | if (outNewerVersion) |
221 | *outNewerVersion = procs->descriptorParametersVersion > kCurrentDescriptorParametersVersion |
||
222 | || procs->readDescriptorProcs->readDescriptorProcsVersion > kCurrentReadDescriptorProcsVersion |
||
223 | || procs->writeDescriptorProcs->writeDescriptorProcsVersion > kCurrentWriteDescriptorProcsVersion; |
||
210 | daniel-mar | 224 | |
217 | daniel-mar | 225 | return procs != NULL |
226 | && procs->descriptorParametersVersion == kCurrentDescriptorParametersVersion |
||
210 | daniel-mar | 227 | |
217 | daniel-mar | 228 | && procs->readDescriptorProcs != NULL |
229 | && procs->readDescriptorProcs->readDescriptorProcsVersion == kCurrentReadDescriptorProcsVersion |
||
230 | && (unsigned int)(procs->readDescriptorProcs->numReadDescriptorProcs) >= kCurrentReadDescriptorProcsCount |
||
231 | && procs->readDescriptorProcs->openReadDescriptorProc != NULL |
||
232 | && procs->readDescriptorProcs->closeReadDescriptorProc != NULL |
||
233 | && procs->readDescriptorProcs->getKeyProc != NULL |
||
234 | && procs->readDescriptorProcs->getTextProc != NULL |
||
235 | && procs->readDescriptorProcs->getIntegerProc != NULL |
||
210 | daniel-mar | 236 | |
217 | daniel-mar | 237 | && procs->writeDescriptorProcs != NULL |
238 | && procs->writeDescriptorProcs->writeDescriptorProcsVersion == kCurrentWriteDescriptorProcsVersion |
||
239 | && (unsigned int)(procs->writeDescriptorProcs->numWriteDescriptorProcs) >= kCurrentWriteDescriptorProcsCount |
||
240 | && procs->writeDescriptorProcs->openWriteDescriptorProc != NULL |
||
241 | && procs->writeDescriptorProcs->closeWriteDescriptorProc != NULL |
||
242 | && procs->writeDescriptorProcs->putTextProc != NULL |
||
243 | && procs->writeDescriptorProcs->putIntegerProc != NULL; |
||
210 | daniel-mar | 244 | } |
245 | |||
246 | |||
247 | //------------------------------------------------------------------------------- |
||
248 | // |
||
249 | // HostCloseReader |
||
250 | // |
||
251 | // Closes a read token, disposes its handle, sets the token to NULL, and |
||
252 | // sets the parameter blocks' descriptor to NULL. |
||
253 | // |
||
254 | // The Descriptor Parameters suite are callbacks designed for |
||
255 | // scripting and automation. See PIActions.h. |
||
256 | // |
||
257 | // Inputs: |
||
258 | // PIDescriptorParameters *procs Pointer to Descriptor Parameters suite. |
||
259 | // |
||
260 | // HandleProcs *hProcs Pointer to HandleProcs callback. |
||
261 | // |
||
262 | // PIReadDescriptor *token Pointer to token to close. |
||
263 | // |
||
264 | // procs->descriptor Pointer to original read handle. |
||
265 | // |
||
266 | // Outputs: |
||
267 | // PIReadDescriptor *token Set to NULL. |
||
268 | // |
||
269 | // procs->descriptor Disposed then set to NULL. |
||
270 | // |
||
271 | // returns OSErr noErr or error if one occurred. |
||
272 | // |
||
273 | //------------------------------------------------------------------------------- |
||
274 | |||
217 | daniel-mar | 275 | OSErr HostCloseReader(PIDescriptorParameters* procs, |
276 | HandleProcs* hProcs, |
||
277 | PIReadDescriptor* token) |
||
210 | daniel-mar | 278 | { |
217 | daniel-mar | 279 | // Close token: |
280 | OSErr err = procs->readDescriptorProcs->closeReadDescriptorProc(*token); |
||
210 | daniel-mar | 281 | |
217 | daniel-mar | 282 | // Dispose the parameter block descriptor: |
283 | hProcs->disposeProc(procs->descriptor); |
||
210 | daniel-mar | 284 | |
217 | daniel-mar | 285 | // Set the descriptor and the read token to NULL: |
286 | procs->descriptor = NULL; |
||
287 | *token = NULL; |
||
210 | daniel-mar | 288 | |
217 | daniel-mar | 289 | return err; |
210 | daniel-mar | 290 | |
291 | } // end HostCloseReader |
||
292 | |||
293 | //------------------------------------------------------------------------------- |
||
294 | // |
||
295 | // HostCloseWriter |
||
296 | // |
||
297 | // Closes a write token, stores its handle in the global parameter block for |
||
298 | // the host to use, sets the token to NULL, and sets the recordInfo to |
||
299 | // plugInDialogOptional (the default). |
||
300 | // |
||
301 | // The Descriptor Parameters suite are callbacks designed for |
||
302 | // scripting and automation. See PIActions.h. |
||
303 | // |
||
304 | // Inputs: |
||
305 | // PIDescriptorParameters *procs Pointer to Descriptor Parameters suite. |
||
306 | // |
||
307 | // HandleProcs *hProcs Pointer to HandleProcs callback. |
||
308 | // |
||
309 | // PIWriteDescriptor *token Pointer to token to close and pass on. |
||
310 | // |
||
311 | // procs->descriptor Should be NULL. If not, its contents |
||
312 | // will be disposed and replaced. |
||
313 | // |
||
314 | // Outputs: |
||
315 | // PIWriteDescriptor *token Set to NULL. |
||
316 | // |
||
317 | // procs->descriptor Set to descriptor handle. |
||
318 | // |
||
319 | // returns OSErr noErr or error if one occurred. |
||
320 | // |
||
321 | //------------------------------------------------------------------------------- |
||
322 | |||
217 | daniel-mar | 323 | OSErr HostCloseWriter(PIDescriptorParameters* procs, |
324 | HandleProcs* hProcs, |
||
325 | PIWriteDescriptor* token) |
||
210 | daniel-mar | 326 | { |
217 | daniel-mar | 327 | OSErr err = noErr; // assume no error |
328 | PIDescriptorHandle h = NULL; |
||
210 | daniel-mar | 329 | |
217 | daniel-mar | 330 | if (procs->descriptor != NULL) // don't need descriptor passed to us |
331 | hProcs->disposeProc(procs->descriptor); // dispose. |
||
210 | daniel-mar | 332 | |
217 | daniel-mar | 333 | // 3. Call CloseWriteDescriptorProc with writeToken, which will create a PIDescriptorHandle. |
334 | procs->writeDescriptorProcs->closeWriteDescriptorProc(*token, &h); |
||
210 | daniel-mar | 335 | |
217 | daniel-mar | 336 | // 4. Place the PIDescriptorHandle into the descriptor field. The host will dispose of it when finished. |
337 | procs->descriptor = h; |
||
210 | daniel-mar | 338 | |
217 | daniel-mar | 339 | // 5. Set recordInfo. Options are: plugInDialogOptional, |
340 | // plugInDialogRequire, plugInDialogNone: |
||
341 | procs->recordInfo = plugInDialogOptional; |
||
210 | daniel-mar | 342 | |
217 | daniel-mar | 343 | *token = NULL; |
344 | |||
345 | return err; |
||
346 | |||
210 | daniel-mar | 347 | } // end HostCloseWriter |