Subversion Repositories filter_foundry

Rev

Rev 536 | 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.net
  4.     Copyright (C) 2018-2023 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.         size_t n;
  51.         Ptr p;
  52.         char* str = NULL;
  53.         Handle h;
  54.         OSErr e = PIGetText(token, &h);
  55.  
  56.         if ((e == noErr) && 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->parm.standalone ? &gdata->parm : NULL)) {
  127.                                         char *tmp = get_cstring(token);
  128.                                         strcpy(gdata->parm.szFormula[0], tmp);
  129.                                         free(tmp);
  130.                                 }
  131.                                 else if (key == getAeteKey('G', gdata->parm.standalone ? &gdata->parm : NULL)) {
  132.                                         char* tmp = get_cstring(token);
  133.                                         strcpy(gdata->parm.szFormula[1], tmp);
  134.                                         free(tmp);
  135.                                 }
  136.                                 else if (key == getAeteKey('B', gdata->parm.standalone ? &gdata->parm : NULL)) {
  137.                                         char* tmp = get_cstring(token);
  138.                                         strcpy(gdata->parm.szFormula[2], tmp);
  139.                                         free(tmp);
  140.                                 }
  141.                                 else if (key == getAeteKey('A', gdata->parm.standalone ? &gdata->parm : NULL)) {
  142.                                         char* tmp = get_cstring(token);
  143.                                         strcpy(gdata->parm.szFormula[3], tmp);
  144.                                         free(tmp);
  145.                                 }
  146.                                 else {
  147.                                         int i;
  148.                                         for (i = 0; i <= 7; ++i) {
  149.                                                 if (key == getAeteKey((char)('0'+i), gdata->parm.standalone ? &gdata->parm : NULL)) {
  150.                                                         PIGetInt(token, &v);
  151.                                                         if (v < 0) v = 0;
  152.                                                         else if (v > 255) v = 255;
  153.                                                         gdata->parm.val[i] = (uint8_t)v;
  154.                                                 }
  155.                                         }
  156.                                 }
  157.                         }
  158.  
  159.                         /*stickyError =*/ CloseReader(&token); // closes & disposes.
  160.  
  161.                         // all Filter Foundry parameters are optional,
  162.                         // so we needn't worry if any are missing
  163.                 }
  164.  
  165.                 return gpb->descriptorParameters->playInfo == plugInDialogDisplay ? SCR_SHOW_DIALOG : SCR_HIDE_DIALOG;
  166.         }
  167.         else {
  168.                 return SCR_NO_SCRIPT;
  169.         }
  170. }
  171.  
  172. OSErr WriteScriptParamsOnRead(void)
  173. {
  174.         PIWriteDescriptor token;
  175.         OSErr gotErr = noErr;
  176.         extern int nplanes;
  177.         int i, allctls;
  178.  
  179.         if (DescriptorAvailable(NULL)) { /* recording.  Do our thing. */
  180.                 // 1. Call openWriteDescriptorProc which will return a PIWriteDescriptor token, such as writeToken.
  181.                 token = OpenWriter();
  182.                 if (token) {
  183.                         // 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.
  184.  
  185.                         // write keys here
  186.                         if (!gdata->parm.standalone) {
  187.                                 if (nplanes > 0) put_cstring(token, getAeteKey('R', gdata->parm.standalone ? &gdata->parm : NULL), gdata->parm.szFormula[0]);
  188.                                 if (nplanes > 1) put_cstring(token, getAeteKey('G', gdata->parm.standalone ? &gdata->parm : NULL), gdata->parm.szFormula[1]);
  189.                                 if (nplanes > 2) put_cstring(token, getAeteKey('B', gdata->parm.standalone ? &gdata->parm : NULL), gdata->parm.szFormula[2]);
  190.                                 if (nplanes > 3) put_cstring(token, getAeteKey('A', gdata->parm.standalone ? &gdata->parm : NULL), gdata->parm.szFormula[3]);
  191.                         }
  192.  
  193.                         /* only write values for the sliders that are actually used! */
  194.                         allctls = checksliders(4);
  195.                         for (i = 0; i < 8; ++i) {
  196.                                 if (allctls || gdata->parm.ctl_used[i]) {
  197.                                         PIPutInt(token, getAeteKey((char)('0'+i), gdata->parm.standalone ? &gdata->parm : NULL), gdata->parm.val[i]);
  198.                                 }
  199.                         }
  200.  
  201.                         gotErr = CloseWriter(&token); /* closes and sets dialog optional */
  202.                         /* done.  Now pass handle on to Photoshop */
  203.                 }
  204.         }
  205.         return gotErr;
  206. }
  207.  
  208.  
  209. //-------------------------------------------------------------------------------
  210. //
  211. //      HostDescriptorAvailable
  212. //
  213. //      Determines whether the PIDescriptorParameters callback is available.
  214. //
  215. //      Check for valid suite version, routine suite version, and routine count.
  216. //      Also check that the subset of routines we actually use is actually present.
  217. //
  218. //-------------------------------------------------------------------------------
  219.  
  220. Boolean HostDescriptorAvailable(PIDescriptorParameters* procs, Boolean* outNewerVersion)
  221. {
  222.         if (procs == NULL) return FALSE; // Photoshop < 4.0 don't has scripting
  223.  
  224.         if (outNewerVersion)
  225.                 *outNewerVersion = procs->descriptorParametersVersion > kCurrentDescriptorParametersVersion
  226.                 || procs->readDescriptorProcs->readDescriptorProcsVersion > kCurrentReadDescriptorProcsVersion
  227.                 || procs->writeDescriptorProcs->writeDescriptorProcsVersion > kCurrentWriteDescriptorProcsVersion;
  228.  
  229.         return procs != NULL
  230.                 && procs->descriptorParametersVersion == kCurrentDescriptorParametersVersion
  231.  
  232.                 && procs->readDescriptorProcs != NULL
  233.                 && procs->readDescriptorProcs->readDescriptorProcsVersion == kCurrentReadDescriptorProcsVersion
  234.                 && (unsigned int)(procs->readDescriptorProcs->numReadDescriptorProcs) >= kCurrentReadDescriptorProcsCount
  235.                 && procs->readDescriptorProcs->openReadDescriptorProc != NULL
  236.                 && procs->readDescriptorProcs->closeReadDescriptorProc != NULL
  237.                 && procs->readDescriptorProcs->getKeyProc != NULL
  238.                 && procs->readDescriptorProcs->getTextProc != NULL
  239.                 && procs->readDescriptorProcs->getIntegerProc != NULL
  240.  
  241.                 && procs->writeDescriptorProcs != NULL
  242.                 && procs->writeDescriptorProcs->writeDescriptorProcsVersion == kCurrentWriteDescriptorProcsVersion
  243.                 && (unsigned int)(procs->writeDescriptorProcs->numWriteDescriptorProcs) >= kCurrentWriteDescriptorProcsCount
  244.                 && procs->writeDescriptorProcs->openWriteDescriptorProc != NULL
  245.                 && procs->writeDescriptorProcs->closeWriteDescriptorProc != NULL
  246.                 && procs->writeDescriptorProcs->putTextProc != NULL
  247.                 && procs->writeDescriptorProcs->putIntegerProc != NULL;
  248. }
  249.  
  250.  
  251. //-------------------------------------------------------------------------------
  252. //
  253. //      HostCloseReader
  254. //
  255. //      Closes a read token, disposes its handle, sets the token to NULL, and
  256. //      sets the parameter blocks' descriptor to NULL.
  257. //
  258. //      The Descriptor Parameters suite are callbacks designed for
  259. //      scripting and automation.  See PIActions.h.
  260. //
  261. //      Inputs:
  262. //              PIDescriptorParameters *procs   Pointer to Descriptor Parameters suite.
  263. //
  264. //              HandleProcs *hProcs                             Pointer to HandleProcs callback.
  265. //
  266. //              PIReadDescriptor *token                 Pointer to token to close.
  267. //
  268. //              procs->descriptor                               Pointer to original read handle.
  269. //
  270. //      Outputs:
  271. //              PIReadDescriptor *token                 Set to NULL.
  272. //
  273. //              procs->descriptor                               Disposed then set to NULL.
  274. //
  275. //              returns OSErr                                   noErr or error if one occurred.
  276. //
  277. //-------------------------------------------------------------------------------
  278.  
  279. OSErr HostCloseReader(PIDescriptorParameters* procs,
  280.         HandleProcs* hProcs,
  281.         PIReadDescriptor* token)
  282. {
  283.         // Close token:
  284.         OSErr err = procs->readDescriptorProcs->closeReadDescriptorProc(*token);
  285.  
  286.         // Dispose the parameter block descriptor:
  287.         hProcs->disposeProc(procs->descriptor);
  288.  
  289.         // Set the descriptor and the read token to NULL:
  290.         procs->descriptor = NULL;
  291.         *token = NULL;
  292.  
  293.         return err;
  294.  
  295. } // end HostCloseReader
  296.  
  297. //-------------------------------------------------------------------------------
  298. //
  299. //      HostCloseWriter
  300. //
  301. //      Closes a write token, stores its handle in the global parameter block for
  302. //      the host to use, sets the token to NULL, and sets the recordInfo to
  303. //      plugInDialogOptional (the default).
  304. //
  305. //      The Descriptor Parameters suite are callbacks designed for
  306. //      scripting and automation.  See PIActions.h.
  307. //
  308. //      Inputs:
  309. //              PIDescriptorParameters *procs   Pointer to Descriptor Parameters suite.
  310. //
  311. //              HandleProcs *hProcs                             Pointer to HandleProcs callback.
  312. //
  313. //              PIWriteDescriptor *token                Pointer to token to close and pass on.
  314. //
  315. //              procs->descriptor                               Should be NULL.  If not, its contents
  316. //                                                                              will be disposed and replaced.
  317. //
  318. //      Outputs:
  319. //              PIWriteDescriptor *token                Set to NULL.
  320. //
  321. //              procs->descriptor                               Set to descriptor handle.
  322. //
  323. //              returns OSErr                                   noErr or error if one occurred.
  324. //
  325. //-------------------------------------------------------------------------------
  326.  
  327. OSErr   HostCloseWriter(PIDescriptorParameters* procs,
  328.         HandleProcs* hProcs,
  329.         PIWriteDescriptor* token)
  330. {
  331.         OSErr err = noErr; // assume no error
  332.         PIDescriptorHandle h = NULL;
  333.  
  334.         if (procs->descriptor != NULL) // don't need descriptor passed to us
  335.                 hProcs->disposeProc(procs->descriptor); // dispose.
  336.  
  337.         // 3. Call CloseWriteDescriptorProc with writeToken, which will create a PIDescriptorHandle.
  338.         procs->writeDescriptorProcs->closeWriteDescriptorProc(*token, &h);
  339.  
  340.         // 4. Place the PIDescriptorHandle into the descriptor field. The host will dispose of it when finished.
  341.         procs->descriptor = h;
  342.  
  343.         // 5. Set recordInfo.  Options are: plugInDialogOptional,
  344.         // plugInDialogRequire, plugInDialogNone:
  345.         procs->recordInfo = plugInDialogOptional;
  346.  
  347.         *token = NULL;
  348.  
  349.         return err;
  350.  
  351. } // end HostCloseWriter
  352.