Subversion Repositories filter_foundry

Rev

Rev 503 | 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-2022 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->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((char)('0'+i), gdata->standalone ? &gdata->parm : NULL)) {
  146.                                                         PIGetInt(token, &v);
  147.                                                         if (v < 0) v = 0;
  148.                                                         else if (v > 255) v = 255;
  149.                                                         slider[i] = (uint8_t)v;
  150.                                                 }
  151.                                         }
  152.                                 }
  153.                         }
  154.  
  155.                         /*stickyError =*/ CloseReader(&token); // closes & disposes.
  156.  
  157.                         // all Filter Foundry parameters are optional,
  158.                         // so we needn't worry if any are missing
  159.                 }
  160.  
  161.                 return gpb->descriptorParameters->playInfo == plugInDialogDisplay ? SCR_SHOW_DIALOG : SCR_HIDE_DIALOG;
  162.         }
  163.         else {
  164.                 return SCR_NO_SCRIPT;
  165.         }
  166. }
  167.  
  168. OSErr WriteScriptParamsOnRead(void)
  169. {
  170.         PIWriteDescriptor token;
  171.         OSErr gotErr = noErr;
  172.         extern int ctls[], maps[], nplanes;
  173.         int i, allctls;
  174.  
  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.
  180.  
  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.                         }
  188.  
  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]) {
  193.                                         PIPutInt(token, getAeteKey((char)('0'+i), gdata->standalone ? &gdata->parm : NULL), slider[i]);
  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;
  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.  
  216. Boolean HostDescriptorAvailable(PIDescriptorParameters* procs, Boolean* outNewerVersion)
  217. {
  218.         if (procs == NULL) return FALSE; // Photoshop < 4.0 don't has scripting
  219.  
  220.         if (outNewerVersion)
  221.                 *outNewerVersion = procs->descriptorParametersVersion > kCurrentDescriptorParametersVersion
  222.                 || procs->readDescriptorProcs->readDescriptorProcsVersion > kCurrentReadDescriptorProcsVersion
  223.                 || procs->writeDescriptorProcs->writeDescriptorProcsVersion > kCurrentWriteDescriptorProcsVersion;
  224.  
  225.         return procs != NULL
  226.                 && procs->descriptorParametersVersion == kCurrentDescriptorParametersVersion
  227.  
  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
  236.  
  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;
  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.  
  275. OSErr HostCloseReader(PIDescriptorParameters* procs,
  276.         HandleProcs* hProcs,
  277.         PIReadDescriptor* token)
  278. {
  279.         // Close token:
  280.         OSErr err = procs->readDescriptorProcs->closeReadDescriptorProc(*token);
  281.  
  282.         // Dispose the parameter block descriptor:
  283.         hProcs->disposeProc(procs->descriptor);
  284.  
  285.         // Set the descriptor and the read token to NULL:
  286.         procs->descriptor = NULL;
  287.         *token = NULL;
  288.  
  289.         return err;
  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.  
  323. OSErr   HostCloseWriter(PIDescriptorParameters* procs,
  324.         HandleProcs* hProcs,
  325.         PIWriteDescriptor* token)
  326. {
  327.         OSErr err = noErr; // assume no error
  328.         PIDescriptorHandle h = NULL;
  329.  
  330.         if (procs->descriptor != NULL) // don't need descriptor passed to us
  331.                 hProcs->disposeProc(procs->descriptor); // dispose.
  332.  
  333.         // 3. Call CloseWriteDescriptorProc with writeToken, which will create a PIDescriptorHandle.
  334.         procs->writeDescriptorProcs->closeWriteDescriptorProc(*token, &h);
  335.  
  336.         // 4. Place the PIDescriptorHandle into the descriptor field. The host will dispose of it when finished.
  337.         procs->descriptor = h;
  338.  
  339.         // 5. Set recordInfo.  Options are: plugInDialogOptional,
  340.         // plugInDialogRequire, plugInDialogNone:
  341.         procs->recordInfo = plugInDialogOptional;
  342.  
  343.         *token = NULL;
  344.  
  345.         return err;
  346.  
  347. } // end HostCloseWriter
  348.