Subversion Repositories filter_foundry

Rev

Rev 424 | Rev 453 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.     This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.     Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
  4.     Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
  5.  
  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.
  10.  
  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.
  15.  
  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
  19. */
  20.  
  21. /* Portions Copyright 1996 - 1999 Adobe Systems Incorporated */
  22. /* All Rights Reserved.                                      */
  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.  
  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;
  47. }
  48.  
  49. char* get_cstring(PIReadDescriptor token) {
  50.         int n;
  51.         Ptr p;
  52.         char* str = NULL;
  53.         Handle h;
  54.         OSErr e = PIGetText(token, &h);
  55.  
  56.         if (!e && h) {
  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;
  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) {
  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.
  74.  
  75.         if (parm != NULL) {
  76.                 unsigned long hash;
  77.                 char* data;
  78.                 // char* debug = (char*)malloc(2000);
  79.                 // sprintf(debug, "getAeteKey %c with title %s/%s in STANDALONE PLUGIN", c, parm->szTitle, parm->szCategory);
  80.                 // simplealert(debug);
  81.                 // free(debug);
  82.  
  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",
  88.                         parm->szCategory,
  89.                         parm->szTitle,
  90.                         c);
  91.                 hash = printablehash(djb2(data));
  92.                 free(data);
  93.                 return hash;
  94.         }
  95.         else {
  96.                 // char* debug = (char*)malloc(2000);
  97.                 // sprintf(debug, "getAeteKey %c in MAIN PLUGIN", c);
  98.                 // simplealert(debug);
  99.                 // free(debug);
  100.  
  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.         }
  109. }
  110.  
  111. /* return true if dialog should be shown */
  112. enum ScriptingShowDialog ReadScriptParamsOnRead(void)
  113. {
  114.         PIReadDescriptor token;
  115.         DescriptorKeyID key;
  116.         DescriptorTypeID type;
  117.         DescriptorKeyIDArray array = { NULLID };
  118.         int32 flags;
  119.         //OSErr stickyError;
  120.         int32 v;
  121.  
  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)) {
  127.                                         if (expr[0]) free(expr[0]);
  128.                                         expr[0] = get_cstring(token);
  129.                                 }
  130.                                 else if (key == getAeteKey('G', gdata->standalone ? &gdata->parm : NULL)) {
  131.                                         if (expr[1]) free(expr[1]);
  132.                                         expr[1] = get_cstring(token);
  133.                                 }
  134.                                 else if (key == getAeteKey('B', gdata->standalone ? &gdata->parm : NULL)) {
  135.                                         if (expr[2]) free(expr[2]);
  136.                                         expr[2] = get_cstring(token);
  137.                                 }
  138.                                 else if (key == getAeteKey('A', gdata->standalone ? &gdata->parm : NULL)) {
  139.                                         if (expr[3]) free(expr[3]);
  140.                                         expr[3] = get_cstring(token);
  141.                                 }
  142.                                 else {
  143.                                         int i;
  144.                                         for (i = 0; i <= 7; ++i) {
  145.                                                 if (key == getAeteKey('0' + i, gdata->standalone ? &gdata->parm : NULL)) {
  146.                                                         PIGetInt(token, &v);
  147.                                                         slider[i] = v;
  148.                                                 }
  149.                                         }
  150.                                 }
  151.                         }
  152.  
  153.                         /*stickyError =*/ CloseReader(&token); // closes & disposes.
  154.  
  155.                         // all Filter Foundry parameters are optional,
  156.                         // so we needn't worry if any are missing
  157.                 }
  158.  
  159.                 return gpb->descriptorParameters->playInfo == plugInDialogDisplay ? SCR_SHOW_DIALOG : SCR_HIDE_DIALOG;
  160.         }
  161.         else {
  162.                 return SCR_NO_SCRIPT;
  163.         }
  164. }
  165.  
  166. OSErr WriteScriptParamsOnRead(void)
  167. {
  168.         PIWriteDescriptor token;
  169.         OSErr gotErr = noErr;
  170.         extern int ctls[], maps[], nplanes;
  171.         int i, allctls;
  172.  
  173.         if (DescriptorAvailable(NULL)) { /* recording.  Do our thing. */
  174.                 // 1. Call openWriteDescriptorProc which will return a PIWriteDescriptor token, such as writeToken.
  175.                 token = OpenWriter();
  176.                 if (token) {
  177.                         // 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.
  178.  
  179.                         // write keys here
  180.                         if (!gdata->standalone) {
  181.                                 if (nplanes > 0) put_cstring(token, getAeteKey('R', gdata->standalone ? &gdata->parm : NULL), expr[0]);
  182.                                 if (nplanes > 1) put_cstring(token, getAeteKey('G', gdata->standalone ? &gdata->parm : NULL), expr[1]);
  183.                                 if (nplanes > 2) put_cstring(token, getAeteKey('B', gdata->standalone ? &gdata->parm : NULL), expr[2]);
  184.                                 if (nplanes > 3) put_cstring(token, getAeteKey('A', gdata->standalone ? &gdata->parm : NULL), expr[3]);
  185.                         }
  186.  
  187.                         /* only write values for the sliders that are actually used! */
  188.                         allctls = checksliders(4, ctls, maps);
  189.                         for (i = 0; i <= 7; ++i) {
  190.                                 if (allctls || ctls[i]) {
  191.                                         PIPutInt(token, getAeteKey('0' + i, gdata->standalone ? &gdata->parm : NULL), slider[i]);
  192.                                 }
  193.                         }
  194.  
  195.                         gotErr = CloseWriter(&token); /* closes and sets dialog optional */
  196.                         /* done.  Now pass handle on to Photoshop */
  197.                 }
  198.         }
  199.         return gotErr;
  200. }
  201.  
  202.  
  203. //-------------------------------------------------------------------------------
  204. //
  205. //      HostDescriptorAvailable
  206. //
  207. //      Determines whether the PIDescriptorParameters callback is available.
  208. //
  209. //      Check for valid suite version, routine suite version, and routine count.
  210. //      Also check that the subset of routines we actually use is actually present.
  211. //
  212. //-------------------------------------------------------------------------------
  213.  
  214. Boolean HostDescriptorAvailable(PIDescriptorParameters* procs, Boolean* outNewerVersion)
  215. {
  216.         if (procs == NULL) return FALSE; // Photoshop < 4.0 don't has scripting
  217.  
  218.         if (outNewerVersion)
  219.                 *outNewerVersion = procs->descriptorParametersVersion > kCurrentDescriptorParametersVersion
  220.                 || procs->readDescriptorProcs->readDescriptorProcsVersion > kCurrentReadDescriptorProcsVersion
  221.                 || procs->writeDescriptorProcs->writeDescriptorProcsVersion > kCurrentWriteDescriptorProcsVersion;
  222.  
  223.         return procs != NULL
  224.                 && procs->descriptorParametersVersion == kCurrentDescriptorParametersVersion
  225.  
  226.                 && procs->readDescriptorProcs != NULL
  227.                 && procs->readDescriptorProcs->readDescriptorProcsVersion == kCurrentReadDescriptorProcsVersion
  228.                 && (unsigned int)(procs->readDescriptorProcs->numReadDescriptorProcs) >= kCurrentReadDescriptorProcsCount
  229.                 && procs->readDescriptorProcs->openReadDescriptorProc != NULL
  230.                 && procs->readDescriptorProcs->closeReadDescriptorProc != NULL
  231.                 && procs->readDescriptorProcs->getKeyProc != NULL
  232.                 && procs->readDescriptorProcs->getTextProc != NULL
  233.                 && procs->readDescriptorProcs->getIntegerProc != NULL
  234.  
  235.                 && procs->writeDescriptorProcs != NULL
  236.                 && procs->writeDescriptorProcs->writeDescriptorProcsVersion == kCurrentWriteDescriptorProcsVersion
  237.                 && (unsigned int)(procs->writeDescriptorProcs->numWriteDescriptorProcs) >= kCurrentWriteDescriptorProcsCount
  238.                 && procs->writeDescriptorProcs->openWriteDescriptorProc != NULL
  239.                 && procs->writeDescriptorProcs->closeWriteDescriptorProc != NULL
  240.                 && procs->writeDescriptorProcs->putTextProc != NULL
  241.                 && procs->writeDescriptorProcs->putIntegerProc != NULL;
  242. }
  243.  
  244.  
  245. //-------------------------------------------------------------------------------
  246. //
  247. //      HostCloseReader
  248. //
  249. //      Closes a read token, disposes its handle, sets the token to NULL, and
  250. //      sets the parameter blocks' descriptor to NULL.
  251. //
  252. //      The Descriptor Parameters suite are callbacks designed for
  253. //      scripting and automation.  See PIActions.h.
  254. //
  255. //      Inputs:
  256. //              PIDescriptorParameters *procs   Pointer to Descriptor Parameters suite.
  257. //
  258. //              HandleProcs *hProcs                             Pointer to HandleProcs callback.
  259. //
  260. //              PIReadDescriptor *token                 Pointer to token to close.
  261. //
  262. //              procs->descriptor                               Pointer to original read handle.
  263. //
  264. //      Outputs:
  265. //              PIReadDescriptor *token                 Set to NULL.
  266. //
  267. //              procs->descriptor                               Disposed then set to NULL.
  268. //
  269. //              returns OSErr                                   noErr or error if one occurred.
  270. //
  271. //-------------------------------------------------------------------------------
  272.  
  273. OSErr HostCloseReader(PIDescriptorParameters* procs,
  274.         HandleProcs* hProcs,
  275.         PIReadDescriptor* token)
  276. {
  277.         // Close token:
  278.         OSErr err = procs->readDescriptorProcs->closeReadDescriptorProc(*token);
  279.  
  280.         // Dispose the parameter block descriptor:
  281.         hProcs->disposeProc(procs->descriptor);
  282.  
  283.         // Set the descriptor and the read token to NULL:
  284.         procs->descriptor = NULL;
  285.         *token = NULL;
  286.  
  287.         return err;
  288.  
  289. } // end HostCloseReader
  290.  
  291. //-------------------------------------------------------------------------------
  292. //
  293. //      HostCloseWriter
  294. //
  295. //      Closes a write token, stores its handle in the global parameter block for
  296. //      the host to use, sets the token to NULL, and sets the recordInfo to
  297. //      plugInDialogOptional (the default).
  298. //
  299. //      The Descriptor Parameters suite are callbacks designed for
  300. //      scripting and automation.  See PIActions.h.
  301. //
  302. //      Inputs:
  303. //              PIDescriptorParameters *procs   Pointer to Descriptor Parameters suite.
  304. //
  305. //              HandleProcs *hProcs                             Pointer to HandleProcs callback.
  306. //
  307. //              PIWriteDescriptor *token                Pointer to token to close and pass on.
  308. //
  309. //              procs->descriptor                               Should be NULL.  If not, its contents
  310. //                                                                              will be disposed and replaced.
  311. //
  312. //      Outputs:
  313. //              PIWriteDescriptor *token                Set to NULL.
  314. //
  315. //              procs->descriptor                               Set to descriptor handle.
  316. //
  317. //              returns OSErr                                   noErr or error if one occurred.
  318. //
  319. //-------------------------------------------------------------------------------
  320.  
  321. OSErr   HostCloseWriter(PIDescriptorParameters* procs,
  322.         HandleProcs* hProcs,
  323.         PIWriteDescriptor* token)
  324. {
  325.         OSErr err = noErr; // assume no error
  326.         PIDescriptorHandle h = NULL;
  327.  
  328.         if (procs->descriptor != NULL) // don't need descriptor passed to us
  329.                 hProcs->disposeProc(procs->descriptor); // dispose.
  330.  
  331.         // 3. Call CloseWriteDescriptorProc with writeToken, which will create a PIDescriptorHandle.
  332.         procs->writeDescriptorProcs->closeWriteDescriptorProc(*token, &h);
  333.  
  334.         // 4. Place the PIDescriptorHandle into the descriptor field. The host will dispose of it when finished.
  335.         procs->descriptor = h;
  336.  
  337.         // 5. Set recordInfo.  Options are: plugInDialogOptional,
  338.         // plugInDialogRequire, plugInDialogNone:
  339.         procs->recordInfo = plugInDialogOptional;
  340.  
  341.         *token = NULL;
  342.  
  343.         return err;
  344.  
  345. } // end HostCloseWriter
  346.