Subversion Repositories filter_foundry

Rev

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