Subversion Repositories filter_foundry

Rev

Rev 256 | Rev 264 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 256 Rev 259
Line 1... Line 1...
1
/*
1
/*
2
        This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
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
3
        Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
4
        Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
4
        Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
5
 
5
 
6
        This program is free software; you can redistribute it and/or modify
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
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
8
        the Free Software Foundation; either version 2 of the License, or
9
        (at your option) any later version.
9
        (at your option) any later version.
10
 
10
 
11
        This program is distributed in the hope that it will be useful,
11
        This program is distributed in the hope that it will be useful,
12
        but WITHOUT ANY WARRANTY; without even the implied warranty of
12
        but WITHOUT ANY WARRANTY; without even the implied warranty of
13
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
        GNU General Public License for more details.
14
        GNU General Public License for more details.
15
 
15
 
16
        You should have received a copy of the GNU General Public License
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
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
18
        Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
*/
19
*/
20
 
20
 
21
//#include <stdio.h>
21
//#include <stdio.h>
22
//#include <sound.h>
22
//#include <sound.h>
23
 
23
 
24
#include "ff.h"
24
#include "ff.h"
25
 
25
 
26
#include "node.h"
26
#include "node.h"
27
#include "funcs.h"
27
#include "funcs.h"
28
#include "y.tab.h"
28
#include "y.tab.h"
29
#include "scripting.h"
29
#include "scripting.h"
30
#include <math.h>
30
#include <math.h>
31
#include "PIBufferSuite.h"
31
#include "PIBufferSuite.h"
32
 
32
 
33
// GIMP (PSPI) and IrfanView preserve neither *data(gdata), nor pb->parameters between invocations!
33
// GIMP (PSPI) and IrfanView preserve neither *data(gdata), nor pb->parameters between invocations!
34
// For debugging, we can simulate it here
34
// For debugging, we can simulate it here
35
//#define DEBUG_SIMULATE_GIMP
35
//#define DEBUG_SIMULATE_GIMP
36
 
36
 
37
struct node *tree[4];
37
struct node *tree[4];
38
char *err[4];
38
char *err[4];
39
int errpos[4],errstart[4],nplanes,cnvused,chunksize,toprow;
39
int errpos[4],errstart[4],nplanes,cnvused,chunksize,toprow;
40
value_type slider[8],cell[NUM_CELLS],map[4][0x100];
40
value_type slider[8],cell[NUM_CELLS],map[4][0x100];
41
char *expr[4];
41
char *expr[4];
42
// long maxSpace;
42
// long maxSpace;
43
globals_t *gdata;
43
globals_t *gdata;
44
FilterRecordPtr gpb;
44
FilterRecordPtr gpb;
45
 
45
 
46
#ifdef MAC_ENV
46
#ifdef MAC_ENV
47
        #define HINSTANCE HANDLE
47
        #define HINSTANCE HANDLE
48
        #define hDllInstance NULL /* fake this Windows-only global */
48
        #define hDllInstance NULL /* fake this Windows-only global */
49
#endif
49
#endif
50
 
50
 
51
#ifdef WIN_ENV
51
#ifdef WIN_ENV
52
#include "manifest.h"
52
#include "manifest.h"
53
#endif
53
#endif
54
 
54
 
55
extern struct sym_rec predefs[];
55
extern struct sym_rec predefs[];
56
extern int nplanes,varused[];
56
extern int nplanes,varused[];
57
 
57
 
58
int checkandinitparams(Handle params);
58
int checkandinitparams(Handle params);
59
 
59
 
60
// MPW MrC requires prototype
60
// MPW MrC requires prototype
61
DLLEXPORT MACPASCAL
61
DLLEXPORT MACPASCAL
62
void ENTRYPOINT(short selector,FilterRecordPtr pb,intptr_t *data,short *result);
62
void ENTRYPOINT(short selector,FilterRecordPtr pb,intptr_t *data,short *result);
63
 
63
 
64
unsigned long get_parm_hash(PARM_T parm) {
64
unsigned long get_parm_hash(PARM_T parm) {
65
        unsigned long hash;
65
        unsigned long hash;
66
        int i;
66
        int i;
67
 
67
 
68
        hash = djb2((char*)parm.category);
68
        hash = djb2((char*)parm.category);
69
        hash += djb2((char*)parm.title);
69
        hash += djb2((char*)parm.title);
70
        hash += djb2((char*)parm.copyright);
70
        hash += djb2((char*)parm.copyright);
71
        hash += djb2((char*)parm.author);
71
        hash += djb2((char*)parm.author);
72
        for (i = 0; i < 4; i++) hash += hash += djb2((char*)parm.map[i]);
72
        for (i = 0; i < 4; i++) hash += hash += djb2((char*)parm.map[i]);
73
        for (i = 0; i < 8; i++) hash += hash += djb2((char*)parm.ctl[i]);
73
        for (i = 0; i < 8; i++) hash += hash += djb2((char*)parm.ctl[i]);
74
        for (i = 0; i < 4; i++) hash += hash += djb2((char*)parm.formula[i]);
74
        for (i = 0; i < 4; i++) hash += hash += djb2((char*)parm.formula[i]);
75
 
75
 
76
        return hash;
76
        return hash;
77
}
77
}
78
 
78
 
79
DLLEXPORT MACPASCAL
79
DLLEXPORT MACPASCAL
80
void ENTRYPOINT(short selector, FilterRecordPtr pb, intptr_t *data, short *result){
80
void ENTRYPOINT(short selector, FilterRecordPtr pb, intptr_t *data, short *result){
81
        static Boolean wantdialog = false;
81
        static Boolean wantdialog = false;
82
        static Boolean premiereWarnedOnce = false;
82
        static Boolean premiereWarnedOnce = false;
83
        OSErr e = noErr;
83
        OSErr e = noErr;
84
        char *reason;
84
        char *reason;
85
#ifdef WIN_ENV
85
#ifdef WIN_ENV
86
        // For Windows, we use an activation context to enforce that our Manifest resource will
86
        // For Windows, we use an activation context to enforce that our Manifest resource will
87
        // be used. This allows us to use Visual Styles, even if the host application does not
87
        // be used. This allows us to use Visual Styles, even if the host application does not
88
        // support it.
88
        // support it.
89
        ManifestActivationCtx manifestVars;
89
        ManifestActivationCtx manifestVars;
90
        BOOL activationContextUsed;
90
        BOOL activationContextUsed;
91
#endif
91
#endif
92
 
92
 
93
        EnterCodeResource();
93
        EnterCodeResource();
94
 
94
 
95
        /*
95
        /*
96
        char* s = (char*)malloc(512);
96
        char* s = (char*)malloc(512);
97
        sprintf(s, "Host signature: '%c%c%c%c' (%d)\nMaxSpace32 = %d\nMaxSpace64 = %lld\nNum buffer procs: %d", (pb->hostSig >> 24) & 0xFF, (pb->hostSig >> 16) & 0xFF, (pb->hostSig >> 8) & 0xFF, pb->hostSig & 0xFF, pb->hostSig, pb->maxSpace, pb->maxSpace64, pb->bufferProcs->numBufferProcs);
97
        sprintf(s, "Host signature: '%c%c%c%c' (%d)\nMaxSpace32 = %d\nMaxSpace64 = %lld\nNum buffer procs: %d", (pb->hostSig >> 24) & 0xFF, (pb->hostSig >> 16) & 0xFF, (pb->hostSig >> 8) & 0xFF, pb->hostSig & 0xFF, pb->hostSig, pb->maxSpace, pb->maxSpace64, pb->bufferProcs->numBufferProcs);
98
        simplealert(s);
98
        simplealert(s);
99
        */
99
        */
100
 
100
 
101
        if (pb->hostSig == HOSTSIG_ADOBE_PREMIERE) {
101
        if (pb->hostSig == HOSTSIG_ADOBE_PREMIERE) {
102
                // DM 19.07.2021 : Tried running the 8BF file in Adobe Premiere 5 (yes, that's possible,
102
                // DM 19.07.2021 : Tried running the 8BF file in Adobe Premiere 5 (yes, that's possible,
103
                // and there is even a FilterFactory for Premeire!),
103
                // and there is even a FilterFactory for Premeire!),
104
                // but it crashes in evalpixel() where there is write-access to the "outp".
104
                // but it crashes in evalpixel() where there is write-access to the "outp".
105
                // Probably the canvas structure is different (maybe it contains frames to achieve transitions?)
105
                // Probably the canvas structure is different (maybe it contains frames to achieve transitions?)
106
                if (!premiereWarnedOnce) {
106
                if (!premiereWarnedOnce) {
107
                        simplealert(_strdup("This version of Filter Foundry is not compatible with Adobe Premiere!"));
107
                        simplealert(_strdup("This version of Filter Foundry is not compatible with Adobe Premiere!"));
108
                }
108
                }
109
                premiereWarnedOnce = true;
109
                premiereWarnedOnce = true;
110
                *result = errPlugInHostInsufficient;
110
                *result = errPlugInHostInsufficient;
111
                return;
111
                return;
112
        }
112
        }
113
 
113
 
114
        #ifdef DEBUG_SIMULATE_GIMP
114
        #ifdef DEBUG_SIMULATE_GIMP
115
        *data = 0;
115
        *data = 0;
116
        pb->parameters = pb->handleProcs->newProc(1);
116
        pb->parameters = pb->handleProcs->newProc(1);
117
        #endif
117
        #endif
118
 
118
 
119
        // Register "gdata" that contains the PARM information and other things which need to be persistant
119
        // Register "gdata" that contains the PARM information and other things which need to be persistant
120
        // and preserve then in *data
120
        // and preserve then in *data
121
        // TODO: memory leak? where is the stuff freed?
121
        // TODO: memory leak? where is the stuff freed?
122
        if (selector != filterSelectorAbout && !*data) {
122
        if (selector != filterSelectorAbout && !*data) {
123
                /*
123
                /*
124
                PSBufferSuite1* pSBufferSuite32 = NULL;
124
                PSBufferSuite1* pSBufferSuite32 = NULL;
125
 
125
 
126
                if ((pb->sSPBasic == 0) ||
126
                if ((pb->sSPBasic == 0) ||
127
                        (pb->sSPBasic->AcquireSuite(kPSBufferSuite, kPSBufferSuiteVersion1, (const void**)&pSBufferSuite32)) ||
127
                        (pb->sSPBasic->AcquireSuite(kPSBufferSuite, kPSBufferSuiteVersion1, (const void**)&pSBufferSuite32)) ||
128
                        (pSBufferSuite32 == NULL))
128
                        (pSBufferSuite32 == NULL))
129
                {
129
                {
130
                                // Old deprecated buffer suite
130
                                // Old deprecated buffer suite
131
                                BufferID tempId;
131
                                BufferID tempId;
132
                                if ((*result = pb->bufferProcs->allocateProc(sizeof(globals_t), &tempId))) return;
132
                                if ((*result = pb->bufferProcs->allocateProc(sizeof(globals_t), &tempId))) return;
133
                                *data = (intptr_t)pb->bufferProcs->lockProc(tempId, true);
133
                                *data = (intptr_t)pb->bufferProcs->lockProc(tempId, true);
134
                                gdata = (globals_t*)*data;
134
                                gdata = (globals_t*)*data;
135
                }
135
                }
136
                else
136
                else
137
                {
137
                {
138
                                // New buffer suite (but only 32-bit version 1, because version 2 has problems with old Photoshop versions)
138
                                // New buffer suite (but only 32-bit version 1, because version 2 has problems with old Photoshop versions)
139
                                // Windows Photoshop 7 and CS 2 accepts kPSBufferSuiteVersion2, but doesn't correctly implement it:
139
                                // Windows Photoshop 7 and CS 2 accepts kPSBufferSuiteVersion2, but doesn't correctly implement it:
140
                                // The symbols "New" and "GetSpace64" point to memory memory addresses outside the Photoshop.exe address range.
140
                                // The symbols "New" and "GetSpace64" point to memory memory addresses outside the Photoshop.exe address range.
141
                                // (Other Photoshop versions were not tested.)
141
                                // (Other Photoshop versions were not tested.)
142
                                // 64-bit support for Windows was established in Photoshop CS 4,
142
                                // 64-bit support for Windows was established in Photoshop CS 4,
143
                                // and PSBufferSuite2 was first documented in SDK CS 6.
143
                                // and PSBufferSuite2 was first documented in SDK CS 6.
144
                                // So, kPSBufferSuiteVersion2 probably was partically implemented as hidden "Work in progress" version
144
                                // So, kPSBufferSuiteVersion2 probably was partically implemented as hidden "Work in progress" version
145
                                // before it was publicly documented.
145
                                // before it was publicly documented.
146
                                // Side note:  pb->bufferSpace64/pb->maxSpace64 was documented in SDK CC 2017.
146
                                // Side note:  pb->bufferSpace64/pb->maxSpace64 was documented in SDK CC 2017.
147
                                //             pb->bufferProcs->allocateProc64/spaceProc64 was documented in SDK CS 6.
147
                                //             pb->bufferProcs->allocateProc64/spaceProc64 was documented in SDK CS 6.
148
                                unsigned32 siz = sizeof(globals_t);
148
                                unsigned32 siz = sizeof(globals_t);
149
                                *data = (intptr_t)pSBufferSuite32->New(&siz, siz);
149
                                *data = (intptr_t)pSBufferSuite32->New(&siz, siz);
150
                                if ((*data == 0) || (siz == 0)) {
150
                                if ((*data == 0) || (siz == 0)) {
151
                                                *result = errPlugInHostInsufficient; // TODO: what is the correct error code for "out of memory"?
151
                                                *result = errPlugInHostInsufficient; // TODO: what is the correct error code for "out of memory"?
152
                                                return;
152
                                                return;
153
                                }
153
                                }
154
                                gdata = (globals_t*)*data;
154
                                gdata = (globals_t*)*data;
155
                                pb->sSPBasic->ReleaseSuite(kPSBufferSuite, kPSBufferSuiteVersion1);
155
                                pb->sSPBasic->ReleaseSuite(kPSBufferSuite, kPSBufferSuiteVersion1);
156
                }
156
                }
157
                gdata->standalone = gdata->parmloaded = false;
157
                gdata->standalone = gdata->parmloaded = false;
158
                */
158
                */
159
 
159
 
160
                // We have 3 options:
160
                // We have 3 options:
161
                // - The deprecated buffer suite (pb->bufferProcs), works fine
161
                // - The deprecated buffer suite (pb->bufferProcs), works fine
162
                // - The recommended buffer suite (kPSBufferSuite), does NOT work (causes memory corruption?) and is not available on some hosts!
162
                // - The recommended buffer suite (kPSBufferSuite), does NOT work (causes memory corruption?) and is not available on some hosts!
163
                //   Either I do something wrong, or maybe it cannot be used to store data between invocations?
163
                //   Either I do something wrong, or maybe it cannot be used to store data between invocations?
164
                // - Using malloc(), which works also fine and is more independent from the host and easier
164
                // - Using malloc(), which works also fine and is more independent from the host and easier
165
                *data = (intptr_t)malloc(sizeof(globals_t));
165
                *data = (intptr_t)malloc(sizeof(globals_t));
166
                if (*data == 0) return;
166
                if (*data == 0) return;
167
                gdata = (globals_t*)*data;
167
                gdata = (globals_t*)*data;
168
                gdata->standalone = gdata->parmloaded = false; // they will be set later
168
                gdata->standalone = gdata->parmloaded = false; // they will be set later
169
        }
169
        }
170
        else {
170
        else {
171
                // We have data from the previous invocation. Use it instead
171
                // We have data from the previous invocation. Use it instead
172
                gdata = (globals_t*)*data;
172
                gdata = (globals_t*)*data;
173
        }
173
        }
174
 
174
 
175
        #ifdef WIN_ENV
175
        #ifdef WIN_ENV
176
        activationContextUsed = ActivateManifest((HMODULE)hDllInstance, 1, &manifestVars);
176
        activationContextUsed = ActivateManifest((HMODULE)hDllInstance, 1, &manifestVars);
177
        #endif
177
        #endif
178
 
178
 
179
        gpb = pb;
179
        gpb = pb;
180
 
180
 
181
        nplanes = MIN(pb->planes,4);
181
        nplanes = MIN(pb->planes,4);
182
 
182
 
183
        switch (selector){
183
        switch (selector){
184
        case filterSelectorAbout:
184
        case filterSelectorAbout:
185
                if (!gdata) {
185
                if (!gdata) {
186
                        gdata = (globals_t*)malloc(sizeof(globals_t));
186
                        gdata = (globals_t*)malloc(sizeof(globals_t));
187
                        if (!gdata) break;
187
                        if (!gdata) break;
188
                        gdata->standalone = gdata->parmloaded = readPARMresource((HMODULE)hDllInstance,&reason,READ_OBFUSC);
188
                        gdata->standalone = gdata->parmloaded = readPARMresource((HMODULE)hDllInstance,&reason,READ_OBFUSC);
189
                        DoAbout((AboutRecordPtr)pb);
189
                        DoAbout((AboutRecordPtr)pb);
190
                        free(gdata);
190
                        free(gdata);
191
                        gdata = NULL;
191
                        gdata = NULL;
192
                } else {
192
                } else {
193
                        DoAbout((AboutRecordPtr)pb);
193
                        DoAbout((AboutRecordPtr)pb);
194
                }
194
                }
195
                break;
195
                break;
196
        case filterSelectorParameters:
196
        case filterSelectorParameters:
197
                wantdialog = true;
197
                wantdialog = true;
198
                break;
198
                break;
199
        case filterSelectorPrepare:
199
        case filterSelectorPrepare:
200
                DoPrepare(pb);
200
                DoPrepare(pb);
201
                init_symtab(predefs); // ready for parser calls
201
                init_symtab(predefs); // ready for parser calls
202
                init_trigtab();
202
                init_trigtab();
203
                break;
203
                break;
204
        case filterSelectorStart:
204
        case filterSelectorStart:
205
                if (HAS_BIG_DOC(pb)) {
205
                if (HAS_BIG_DOC(pb)) {
206
                        // The BigDocument structure is required if the document is larger than 30,000 pixels
206
                        // The BigDocument structure is required if the document is larger than 30,000 pixels
207
                        // It deprecates imageSize, filterRect, inRect, outRect, maskRect, floatCoord, and wholeSize.
207
                        // It deprecates imageSize, filterRect, inRect, outRect, maskRect, floatCoord, and wholeSize.
208
                        // By setting it to nonzero, we communicate to Photoshop that we support the BigDocument structure.
208
                        // By setting it to nonzero, we communicate to Photoshop that we support the BigDocument structure.
209
                        pb->bigDocumentData->PluginUsing32BitCoordinates = true;
209
                        pb->bigDocumentData->PluginUsing32BitCoordinates = true;
210
                }
210
                }
211
 
211
 
212
                /* initialise the parameter handle that Photoshop keeps for us */
212
                /* initialise the parameter handle that Photoshop keeps for us */
213
                if(!pb->parameters)
213
                if(!pb->parameters)
214
                        pb->parameters = PINEWHANDLE(1); // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
214
                        pb->parameters = PINEWHANDLE(1); // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
215
 
215
 
216
                wantdialog |= checkandinitparams(pb->parameters);
216
                wantdialog |= checkandinitparams(pb->parameters);
217
 
217
 
218
                /* wantdialog = false means that we never got a Parameters call, so we're not supposed to ask user */
218
                /* wantdialog = false means that we never got a Parameters call, so we're not supposed to ask user */
219
                if( wantdialog && (!gdata->standalone || gdata->parm.popDialog) ){
219
                if( wantdialog && (!gdata->standalone || gdata->parm.popDialog) ){
220
                        if( maindialog(pb) ){
220
                        if( maindialog(pb) ){
221
                                if (!host_preserves_parameters()) {
221
                                if (!host_preserves_parameters()) {
222
                                        if (!gdata->obfusc) { // If the filter is obfuscated, we may not save the formula to the .afs (TODO: just save the ctl/map, but not the r/g/b/a-formulas!)
222
                                        if (!gdata->obfusc) { // If the filter is obfuscated, we may not save the formula to the .afs (TODO: just save the ctl/map, but not the r/g/b/a-formulas!)
223
                                                /* Workaround for GIMP/PSPI, to avoid that formulas vanish when you re-open the main window.
223
                                                /* Workaround for GIMP/PSPI, to avoid that formulas vanish when you re-open the main window.
224
                                                   The reason is a bug in PSPI: The host should preserve the value of pb->parameters, which PSPI does not do.
224
                                                   The reason is a bug in PSPI: The host should preserve the value of pb->parameters, which PSPI does not do.
225
                                                   Also, all global variables are unloaded, so the plugin cannot preserve any data.
225
                                                   Also, all global variables are unloaded, so the plugin cannot preserve any data.
226
                                                   Workaround in FF 1.7: If the host GIMP is detected, then a special mode will be activated.
226
                                                   Workaround in FF 1.7: If the host GIMP is detected, then a special mode will be activated.
227
                                                   This mode saves the filter data into a temporary file "FilterFoundryXX.afs" and loads it
227
                                                   This mode saves the filter data into a temporary file "FilterFoundryXX.afs" and loads it
228
                                                   when the window is opened again. */
228
                                                   when the window is opened again. */
229
                                                // Workaround: Save settings in "FilterFoundryXX.afs" if the host does not preserve pb->parameters
229
                                                // Workaround: Save settings in "FilterFoundryXX.afs" if the host does not preserve pb->parameters
230
                                                char outfilename[255];
230
                                                char outfilename[255];
231
                                                char* tempdir;
231
                                                char* tempdir;
232
                                                int hash;
232
                                                int hash;
233
                                                StandardFileReply sfr;
233
                                                StandardFileReply sfr;
234
                                                sfr.sfGood = true;
234
                                                sfr.sfGood = true;
235
                                                sfr.sfReplacing = true;
235
                                                sfr.sfReplacing = true;
236
                                                sfr.sfType = PS_FILTER_FILETYPE;
236
                                                sfr.sfType = PS_FILTER_FILETYPE;
237
 
237
 
238
                                                tempdir = getenv("TMP");
238
                                                tempdir = getenv("TMP");
239
                                                #ifdef WIN_ENV
239
                                                #ifdef WIN_ENV
240
                                                if (strlen(tempdir) > 0) strcat(tempdir, "\\");
240
                                                if (strlen(tempdir) > 0) strcat(tempdir, "\\");
241
                                                #else
241
                                                #else
242
                                                if (strlen(tempdir) > 0) strcat(tempdir, "/");
242
                                                if (strlen(tempdir) > 0) strcat(tempdir, "/");
243
                                                #endif
243
                                                #endif
244
 
244
 
245
                                                hash = (gdata->standalone) ? get_parm_hash(gdata->parm) : 0;
245
                                                hash = (gdata->standalone) ? get_parm_hash(gdata->parm) : 0;
246
                                                sprintf(outfilename, "%sFilterFoundry%d.afs", tempdir, hash);
246
                                                sprintf(outfilename, "%sFilterFoundry%d.afs", tempdir, hash);
247
 
247
 
248
                                                myc2pstrcpy(sfr.sfFile.name, outfilename);
248
                                                myc2pstrcpy(sfr.sfFile.name, outfilename);
249
                                                #ifdef WIN_ENV
249
                                                #ifdef WIN_ENV
250
                                                sfr.nFileExtension = (WORD)(strlen(outfilename) - strlen(".afs"));
250
                                                sfr.nFileExtension = (WORD)(strlen(outfilename) - strlen(".afs"));
251
                                                #endif
251
                                                #endif
252
                                                sfr.sfScript = 0; // FIXME: is that ok?
252
                                                sfr.sfScript = 0; // FIXME: is that ok?
253
                                                savefile(&sfr);
253
                                                savefile(&sfr);
254
                                        }
254
                                        }
255
                                }
255
                                }
256
 
256
 
257
                                /* update stored parameters from new user settings */
257
                                /* update stored parameters from new user settings */
258
                                saveparams(pb->parameters);
258
                                saveparams(pb->parameters);
259
                        }else
259
                        }else
260
                                e = userCanceledErr;
260
                                e = userCanceledErr;
261
                }
261
                }
262
                wantdialog = false;
262
                wantdialog = false;
263
 
263
 
264
                if(!e){
264
                if(!e){
265
                        if(setup(pb)){
265
                        if(setup(pb)){
266
                                DoStart(pb);
266
                                DoStart(pb);
267
                        }else{
267
                        }else{
268
                                SYSBEEP(1);
268
                                SYSBEEP(1);
269
                                e = filterBadParameters;
269
                                e = filterBadParameters;
270
                        }
270
                        }
271
                }
271
                }
272
                break;
272
                break;
273
        case filterSelectorContinue:
273
        case filterSelectorContinue:
274
                e = DoContinue(pb);
274
                e = DoContinue(pb);
275
                break;
275
                break;
276
        case filterSelectorFinish:
276
        case filterSelectorFinish:
277
                DoFinish(pb);
277
                DoFinish(pb);
278
                break;
278
                break;
279
        default:
279
        default:
280
                e = filterBadParameters;
280
                e = filterBadParameters;
281
        }
281
        }
282
 
282
 
283
        *result = e;
283
        *result = e;
284
 
284
 
285
        #ifdef WIN_ENV
285
        #ifdef WIN_ENV
286
        if (activationContextUsed) DeactivateManifest(&manifestVars);
286
        if (activationContextUsed) DeactivateManifest(&manifestVars);
287
        #endif
287
        #endif
288
 
288
 
289
        ExitCodeResource();
289
        ExitCodeResource();
290
}
290
}
291
 
291
 
292
int checkandinitparams(Handle params){
292
int checkandinitparams(Handle params){
293
        char *reasonstr,*reason;
293
        char *reasonstr,*reason;
294
        int i,bUninitializedParams;
294
        int i,bUninitializedParams;
295
        Boolean showdialog;
295
        Boolean showdialog;
296
 
296
 
297
        if (!host_preserves_parameters()) {
297
        if (!host_preserves_parameters()) {
298
                // Workaround: Load settings in "FilterFoundryXX.afs" if host does not preserve pb->parameters
298
                // Workaround: Load settings in "FilterFoundryXX.afs" if host does not preserve pb->parameters
299
                char outfilename[255];
299
                char outfilename[255];
300
                char* tempdir;
300
                char* tempdir;
301
                int hash;
301
                int hash;
302
                Boolean isStandalone;
302
                Boolean isStandalone;
303
                StandardFileReply sfr;
303
                StandardFileReply sfr;
304
                sfr.sfGood = true;
304
                sfr.sfGood = true;
305
                sfr.sfReplacing = true;
305
                sfr.sfReplacing = true;
306
                sfr.sfType = PS_FILTER_FILETYPE;
306
                sfr.sfType = PS_FILTER_FILETYPE;
307
 
307
 
308
                // We need to set gdata->standalone after loadfile(), but we must call readPARMresource() before loadfile()
308
                // We need to set gdata->standalone after loadfile(), but we must call readPARMresource() before loadfile()
309
                // Reason: readPARMresource() reads parameters from the DLL while loadfile() reads parameters from the AFS file
309
                // Reason: readPARMresource() reads parameters from the DLL while loadfile() reads parameters from the AFS file
310
                // But loadfile() will reset gdata->standalone ...
310
                // But loadfile() will reset gdata->standalone ...
311
                isStandalone = readPARMresource((HMODULE)hDllInstance, &reason, READ_OBFUSC);
311
                isStandalone = readPARMresource((HMODULE)hDllInstance, &reason, READ_OBFUSC);
312
 
312
 
313
                if (!gdata->obfusc) { // If the filter is obfuscated, we may not save the formula to the .afs (TODO: just save the ctl/map, but not the r/g/b/a-formulas!)
313
                if (!gdata->obfusc) { // If the filter is obfuscated, we may not save the formula to the .afs (TODO: just save the ctl/map, but not the r/g/b/a-formulas!)
314
                        tempdir = getenv("TMP");
314
                        tempdir = getenv("TMP");
315
                        #ifdef WIN_ENV
315
                        #ifdef WIN_ENV
316
                        if (strlen(tempdir) > 0) strcat(tempdir, "\\");
316
                        if (strlen(tempdir) > 0) strcat(tempdir, "\\");
317
                        #else
317
                        #else
318
                        if (strlen(tempdir) > 0) strcat(tempdir, "/");
318
                        if (strlen(tempdir) > 0) strcat(tempdir, "/");
319
                        #endif
319
                        #endif
320
 
320
 
321
                        hash = (isStandalone) ? get_parm_hash(gdata->parm) : 0;
321
                        hash = (isStandalone) ? get_parm_hash(gdata->parm) : 0;
322
                        sprintf(outfilename, "%sFilterFoundry%d.afs", tempdir, hash);
322
                        sprintf(outfilename, "%sFilterFoundry%d.afs", tempdir, hash);
323
 
323
 
324
                        myc2pstrcpy(sfr.sfFile.name, outfilename);
324
                        myc2pstrcpy(sfr.sfFile.name, outfilename);
325
                        #ifdef WIN_ENV
325
                        #ifdef WIN_ENV
326
                        sfr.nFileExtension = (WORD)(strlen(outfilename) - strlen(".afs"));
326
                        sfr.nFileExtension = (WORD)(strlen(outfilename) - strlen(".afs"));
327
                        #endif
327
                        #endif
328
                        sfr.sfScript = 0; // FIXME: is that ok?
328
                        sfr.sfScript = 0; // FIXME: is that ok?
329
 
329
 
330
                        if (loadfile(&sfr, &reason)) {
330
                        if (loadfile(&sfr, &reason)) {
331
                                gdata->standalone = gdata->parmloaded = isStandalone;
331
                                gdata->standalone = gdata->parmloaded = isStandalone;
332
                                return true;
332
                                return true;
333
                        }
333
                        }
334
                }
334
                }
335
        }
335
        }
336
 
336
 
337
        if( (bUninitializedParams = !(params && readparams(params,false,&reasonstr))) ){
337
        if( (bUninitializedParams = !(params && readparams(params,false,&reasonstr))) ){
338
                /* either the parameter handle was uninitialised,
338
                /* either the parameter handle was uninitialised,
339
                   or the parameter data couldn't be read; set default values */
339
                   or the parameter data couldn't be read; set default values */
340
 
340
 
341
                // see if saved parameters exist
341
                // see if saved parameters exist
342
                gdata->standalone = gdata->parmloaded = readPARMresource((HMODULE)hDllInstance,&reason,READ_OBFUSC);
342
                gdata->standalone = gdata->parmloaded = readPARMresource((HMODULE)hDllInstance,&reason,READ_OBFUSC);
343
 
343
 
344
 
344
 
345
                if(!gdata->standalone){
345
                if(!gdata->standalone){
346
                        // no saved settings (not standalone)
346
                        // no saved settings (not standalone)
347
                        for(i = 0; i < 8; ++i)
347
                        for(i = 0; i < 8; ++i)
348
                                slider[i] = i*10+100;
348
                                slider[i] = i*10+100;
349
                        for(i = 0; i < 4; ++i)
349
                        for(i = 0; i < 4; ++i)
350
                                if(expr[i])
350
                                if(expr[i])
351
                                        free(expr[i]);
351
                                        free(expr[i]);
352
                        if(gpb->imageMode == plugInModeRGBColor){
352
                        if(gpb->imageMode == plugInModeRGBColor){
353
                                expr[0] = _strdup("r");
353
                                expr[0] = _strdup("r");
354
                                expr[1] = _strdup("g");
354
                                expr[1] = _strdup("g");
355
                                expr[2] = _strdup("b");
355
                                expr[2] = _strdup("b");
356
                                expr[3] = _strdup("a");
356
                                expr[3] = _strdup("a");
357
                        }else{
357
                        }else{
358
                                expr[0] = _strdup("c");
358
                                expr[0] = _strdup("c");
359
                                expr[1] = _strdup("c");
359
                                expr[1] = _strdup("c");
360
                                expr[2] = _strdup("c");
360
                                expr[2] = _strdup("c");
361
                                expr[3] = _strdup("c");
361
                                expr[3] = _strdup("c");
362
                        }
362
                        }
363
                }
363
                }
364
        }
364
        }
365
 
365
 
366
        // let scripting system change parameters, if we're scripted;
366
        // let scripting system change parameters, if we're scripted;
367
        // user may want to force display of dialog during scripting playback
367
        // user may want to force display of dialog during scripting playback
368
        switch (ReadScriptParamsOnRead()) {
368
        switch (ReadScriptParamsOnRead()) {
369
        case SCR_SHOW_DIALOG:
369
        case SCR_SHOW_DIALOG:
370
                showdialog = true;
370
                showdialog = true;
371
                break;
371
                break;
372
        case SCR_HIDE_DIALOG:
372
        case SCR_HIDE_DIALOG:
373
                showdialog = false;
373
                showdialog = false;
374
                break;
374
                break;
375
        default:
375
        default:
376
        case SCR_NO_SCRIPT:
376
        case SCR_NO_SCRIPT:
377
                showdialog = bUninitializedParams;
377
                showdialog = bUninitializedParams;
378
                break;
378
                break;
379
        }
379
        }
380
 
380
 
381
        saveparams(params);
381
        saveparams(params);
382
 
382
 
383
        return showdialog;
383
        return showdialog;
384
}
384
}
385
 
385
 
386
Boolean host_preserves_parameters() {
386
Boolean host_preserves_parameters() {
387
        #ifdef DEBUG_SIMULATE_GIMP
387
        #ifdef DEBUG_SIMULATE_GIMP
388
        return false;
388
        return false;
389
        #endif
389
        #endif
390
 
390
 
391
        if (gpb->hostSig == HOSTSIG_GIMP) return false;
391
        if (gpb->hostSig == HOSTSIG_GIMP) return false;
392
        if (gpb->hostSig == HOSTSIG_IRFANVIEW) return false;
392
        if (gpb->hostSig == HOSTSIG_IRFANVIEW) return false;
393
 
393
 
394
        /*
394
        /*
395
        char x[100];
395
        char x[100];
396
        sprintf(x, "Host Signature: %u", gpb->hostSig);
396
        sprintf(x, "Host Signature: %u", gpb->hostSig);
397
        simplealert(x);
397
        simplealert(x);
398
        */
398
        */
399
 
399
 
400
        // We just assume the other hosts preserve the parameters
400
        // We just assume the other hosts preserve the parameters
401
        return true;
401
        return true;
402
}
402
}
403
 
403
 
404
int64_t maxspace(){
404
int64_t maxspace(){
405
        // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
405
        // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
406
 
406
 
407
        // Plugins that don't support MaxSpace64 shall set the field to zero; then we will use MaxSpace instead.
407
        // Plugins that don't support MaxSpace64 shall set the field to zero; then we will use MaxSpace instead.
408
        // Also check "gpb->bufferProcs->numBufferProcs" to see if 64 bit API is available
408
        // Also check "gpb->bufferProcs->numBufferProcs" to see if 64 bit API is available
409
        if ((gpb->bufferProcs->numBufferProcs >= 8) && (gpb->maxSpace64 > 0)) {
409
        if ((gpb->bufferProcs->numBufferProcs >= 8) && (gpb->maxSpace64 > 0)) {
410
                uint64_t maxSpace64 = gpb->maxSpace64;
410
                uint64_t maxSpace64 = gpb->maxSpace64;
411
 
411
 
412
                return maxSpace64;
412
                return maxSpace64;
413
        } else {
413
        } else {
414
                // Note: If maxSpace gets converted from Int32 to unsigned int, we can reach up to 4 GB RAM. However, after this, there will be a wrap to 0 GB again.
414
                // Note: If maxSpace gets converted from Int32 to unsigned int, we can reach up to 4 GB RAM. However, after this, there will be a wrap to 0 GB again.
415
                unsigned int maxSpace32 = (unsigned int) gpb->maxSpace;
415
                unsigned int maxSpace32 = (unsigned int) gpb->maxSpace;
416
                uint64_t maxSpace64 = maxSpace32;
416
                uint64_t maxSpace64 = maxSpace32;
417
 
417
 
418
                if (gpb->hostSig == HOSTSIG_IRFANVIEW) maxSpace64 *= 1024; // IrfanView is giving Kilobytes instead of Bytes
418
                if (gpb->hostSig == HOSTSIG_IRFANVIEW) maxSpace64 *= 1024; // IrfanView is giving Kilobytes instead of Bytes
419
                //if (gpb->hostSig == HOSTSIG_SERIF_PHOTOPLUS) maxSpace64 *= 1024; // TODO: Serif PhotoPlus also gives Kilobytes instead of bytes. But since it uses not a unique host signature, there is nothing we can do???
419
                //if (gpb->hostSig == HOSTSIG_SERIF_PHOTOPLUS) maxSpace64 *= 1024; // TODO: Serif PhotoPlus also gives Kilobytes instead of bytes. But since it uses not a unique host signature, there is nothing we can do???
420
 
420
 
421
                return maxSpace64;
421
                return maxSpace64;
422
        }
422
        }
423
}
423
}
424
 
424
 
425
Boolean maxspace_available() {
425
Boolean maxspace_available() {
426
        // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
426
        // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
427
 
427
 
428
        // GIMP PSPI sets MaxSpace to hardcoded 100 MB
428
        // GIMP PSPI sets MaxSpace to hardcoded 100 MB
429
        if (gpb->hostSig == HOSTSIG_GIMP) return false;
429
        if (gpb->hostSig == HOSTSIG_GIMP) return false;
430
 
430
 
431
        // HOSTSIG_PAINT_NET sets MaxSpace to hardcoded 1 GB, see https://github.com/0xC0000054/PSFilterPdn/issues/5
431
        // HOSTSIG_PAINT_NET sets MaxSpace to hardcoded 1 GB, see https://github.com/0xC0000054/PSFilterPdn/issues/5
432
        // Comment by the host author "This was done to avoid any compatibility issues with plugins handling 2 GB - 1"
432
        // Comment by the host author "This was done to avoid any compatibility issues with plugins handling 2 GB - 1"
433
        if (gpb->hostSig == HOSTSIG_PAINT_NET) return false;
433
        if (gpb->hostSig == HOSTSIG_PAINT_NET) return false;
434
 
434
 
435
        return true;
435
        return true;
436
}
436
}
437
 
437
 
438
void DoPrepare(FilterRecordPtr pb){
438
void DoPrepare(FilterRecordPtr pb){
439
        int i;
439
        int i;
440
 
440
 
441
        for(i = 4; i--;){
441
        for(i = 4; i--;){
442
                if(expr[i]||tree[i]) DBG("expr[] or tree[] non-NULL in Prepare!");
442
                if(expr[i]||tree[i]) DBG("expr[] or tree[] non-NULL in Prepare!");
443
                expr[i] = NULL;
443
                expr[i] = NULL;
444
                tree[i] = NULL;
444
                tree[i] = NULL;
445
        }
445
        }
446
 
446
 
447
        // Commented out by DM, 18 Dec 2018:
447
        // Commented out by DM, 18 Dec 2018:
448
        // This code did not work on systems with 8 GB RAM:
448
        // This code did not work on systems with 8 GB RAM:
449
        /*
449
        /*
450
        long space = (pb->maxSpace*9)/10; // don't ask for more than 90% of available memory
450
        long space = (pb->maxSpace*9)/10; // don't ask for more than 90% of available memory
451
 
451
 
452
        maxSpace = 512L<<10; // this is a wild guess, actually
452
        maxSpace = 512L<<10; // this is a wild guess, actually
453
        if(maxSpace > space)
453
        if(maxSpace > space)
454
                        maxSpace = space;
454
                        maxSpace = space;
455
        pb->maxSpace = maxSpace;
455
        pb->maxSpace = maxSpace;
456
        */
456
        */
457
 
457
 
458
        // New variant:
458
        // New variant:
459
        if (maxspace_available()) {
459
        if (maxspace_available()) {
460
                pb->maxSpace = (int32)ceil((maxspace()/10.)*9); // don't ask for more than 90% of available memory
460
                pb->maxSpace = (int32)ceil((maxspace()/10.)*9); // don't ask for more than 90% of available memory
461
                // FIXME: Also maxSpace64
461
                // FIXME: Also maxSpace64
462
        }
462
        }
463
}
463
}
464
 
464
 
465
void RequestNext(FilterRecordPtr pb,long toprow){
465
void RequestNext(FilterRecordPtr pb,long toprow){
466
        /* Request next block of the image */
466
        /* Request next block of the image */
467
 
467
 
468
        pb->inLoPlane = pb->outLoPlane = 0;
468
        pb->inLoPlane = pb->outLoPlane = 0;
469
        pb->inHiPlane = pb->outHiPlane = nplanes-1;
469
        pb->inHiPlane = pb->outHiPlane = nplanes-1;
470
 
470
 
471
        if (HAS_BIG_DOC(pb)) {
471
        if (HAS_BIG_DOC(pb)) {
472
                // if any of the formulae involve random access to image pixels,
472
                // if any of the formulae involve random access to image pixels,
473
                // ask for the entire image
473
                // ask for the entire image
474
                if (needall) {
474
                if (needall) {
475
                        SETRECT(BIGDOC_IN_RECT(pb), 0, 0, BIGDOC_IMAGE_SIZE(pb).h, BIGDOC_IMAGE_SIZE(pb).v);
475
                        SETRECT(BIGDOC_IN_RECT(pb), 0, 0, BIGDOC_IMAGE_SIZE(pb).h, BIGDOC_IMAGE_SIZE(pb).v);
476
                } else {
476
                } else {
477
                        // TODO: This does not work with GIMP. So, if we are using GIMP, we should
477
                        // TODO: This does not work with GIMP. So, if we are using GIMP, we should
478
                        //       somehow always use "needall=true", and/or find out why this doesn't work
478
                        //       somehow always use "needall=true", and/or find out why this doesn't work
479
                        //       with GIMP.
479
                        //       with GIMP.
480
 
480
 
481
                        // otherwise, process the filtered area, by chunksize parts
481
                        // otherwise, process the filtered area, by chunksize parts
482
                        BIGDOC_IN_RECT(pb).left = BIGDOC_FILTER_RECT(pb).left;
482
                        BIGDOC_IN_RECT(pb).left = BIGDOC_FILTER_RECT(pb).left;
483
                        BIGDOC_IN_RECT(pb).right = BIGDOC_FILTER_RECT(pb).right;
483
                        BIGDOC_IN_RECT(pb).right = BIGDOC_FILTER_RECT(pb).right;
484
                        BIGDOC_IN_RECT(pb).top = (int32)toprow;
484
                        BIGDOC_IN_RECT(pb).top = (int32)toprow;
485
                        BIGDOC_IN_RECT(pb).bottom = (int32)MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
485
                        BIGDOC_IN_RECT(pb).bottom = (int32)MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
486
 
486
 
487
                        if (cnvused) {
487
                        if (cnvused) {
488
                                // cnv() needs one extra pixel in each direction
488
                                // cnv() needs one extra pixel in each direction
489
                                if (BIGDOC_IN_RECT(pb).left > 0)
489
                                if (BIGDOC_IN_RECT(pb).left > 0)
490
                                        --BIGDOC_IN_RECT(pb).left;
490
                                        --BIGDOC_IN_RECT(pb).left;
491
                                if (BIGDOC_IN_RECT(pb).right < BIGDOC_IMAGE_SIZE(pb).h)
491
                                if (BIGDOC_IN_RECT(pb).right < BIGDOC_IMAGE_SIZE(pb).h)
492
                                        ++BIGDOC_IN_RECT(pb).right;
492
                                        ++BIGDOC_IN_RECT(pb).right;
493
                                if (BIGDOC_IN_RECT(pb).top > 0)
493
                                if (BIGDOC_IN_RECT(pb).top > 0)
494
                                        --BIGDOC_IN_RECT(pb).top;
494
                                        --BIGDOC_IN_RECT(pb).top;
495
                                if (BIGDOC_IN_RECT(pb).bottom < BIGDOC_IMAGE_SIZE(pb).v)
495
                                if (BIGDOC_IN_RECT(pb).bottom < BIGDOC_IMAGE_SIZE(pb).v)
496
                                        ++BIGDOC_IN_RECT(pb).bottom;
496
                                        ++BIGDOC_IN_RECT(pb).bottom;
497
                        }
497
                        }
498
                }
498
                }
499
                BIGDOC_OUT_RECT(pb) = BIGDOC_FILTER_RECT(pb);
499
                BIGDOC_OUT_RECT(pb) = BIGDOC_FILTER_RECT(pb);
500
                /*
500
                /*
501
                {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
501
                {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
502
                                needall,
502
                                needall,
503
                                BIGDOC_IN_RECT(pb).left,BIGDOC_IN_RECT(pb).top,BIGDOC_IN_RECT(pb).right,BIGDOC_IN_RECT(pb).bottom,
503
                                BIGDOC_IN_RECT(pb).left,BIGDOC_IN_RECT(pb).top,BIGDOC_IN_RECT(pb).right,BIGDOC_IN_RECT(pb).bottom,
504
                                BIGDOC_FILTER_RECT(pb).left,BIGDOC_FILTER_RECT(pb).top,BIGDOC_FILTER_RECT(pb).right,BIGDOC_FILTER_RECT(pb).bottom);dbg(s);}
504
                                BIGDOC_FILTER_RECT(pb).left,BIGDOC_FILTER_RECT(pb).top,BIGDOC_FILTER_RECT(pb).right,BIGDOC_FILTER_RECT(pb).bottom);dbg(s);}
505
                */
505
                */
506
        } else {
506
        } else {
507
                // if any of the formulae involve random access to image pixels,
507
                // if any of the formulae involve random access to image pixels,
508
                // ask for the entire image
508
                // ask for the entire image
509
                if (needall) {
509
                if (needall) {
510
                        SETRECT(IN_RECT(pb), 0, 0, IMAGE_SIZE(pb).h, IMAGE_SIZE(pb).v);
510
                        SETRECT(IN_RECT(pb), 0, 0, IMAGE_SIZE(pb).h, IMAGE_SIZE(pb).v);
511
                }
511
                }
512
                else {
512
                else {
513
                        // TODO: This does not work with GIMP. So, if we are using GIMP, we should
513
                        // TODO: This does not work with GIMP. So, if we are using GIMP, we should
514
                        //       somehow always use "needall=true", and/or find out why this doesn't work
514
                        //       somehow always use "needall=true", and/or find out why this doesn't work
515
                        //       with GIMP.
515
                        //       with GIMP.
516
 
516
 
517
                        // otherwise, process the filtered area, by chunksize parts
517
                        // otherwise, process the filtered area, by chunksize parts
518
                        IN_RECT(pb).left = FILTER_RECT(pb).left;
518
                        IN_RECT(pb).left = FILTER_RECT(pb).left;
519
                        IN_RECT(pb).right = FILTER_RECT(pb).right;
519
                        IN_RECT(pb).right = FILTER_RECT(pb).right;
520
                        IN_RECT(pb).top = (int16)toprow;
520
                        IN_RECT(pb).top = (int16)toprow;
521
                        IN_RECT(pb).bottom = (int16)MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
521
                        IN_RECT(pb).bottom = (int16)MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
522
 
522
 
523
                        if (cnvused) {
523
                        if (cnvused) {
524
                                // cnv() needs one extra pixel in each direction
524
                                // cnv() needs one extra pixel in each direction
525
                                if (IN_RECT(pb).left > 0)
525
                                if (IN_RECT(pb).left > 0)
526
                                        --IN_RECT(pb).left;
526
                                        --IN_RECT(pb).left;
527
                                if (IN_RECT(pb).right < IMAGE_SIZE(pb).h)
527
                                if (IN_RECT(pb).right < IMAGE_SIZE(pb).h)
528
                                        ++IN_RECT(pb).right;
528
                                        ++IN_RECT(pb).right;
529
                                if (IN_RECT(pb).top > 0)
529
                                if (IN_RECT(pb).top > 0)
530
                                        --IN_RECT(pb).top;
530
                                        --IN_RECT(pb).top;
531
                                if (IN_RECT(pb).bottom < IMAGE_SIZE(pb).v)
531
                                if (IN_RECT(pb).bottom < IMAGE_SIZE(pb).v)
532
                                        ++IN_RECT(pb).bottom;
532
                                        ++IN_RECT(pb).bottom;
533
                        }
533
                        }
534
                }
534
                }
535
                OUT_RECT(pb) = FILTER_RECT(pb);
535
                OUT_RECT(pb) = FILTER_RECT(pb);
536
                /*
536
                /*
537
                {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
537
                {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
538
                                needall,
538
                                needall,
539
                                IN_RECT(pb).left,IN_RECT(pb).top,IN_RECT(pb).right,IN_RECT(pb).bottom,
539
                                IN_RECT(pb).left,IN_RECT(pb).top,IN_RECT(pb).right,IN_RECT(pb).bottom,
540
                                FILTER_RECT(pb).left,FILTER_RECT(pb).top,FILTER_RECT(pb).right,FILTER_RECT(pb).bottom);dbg(s);}
540
                                FILTER_RECT(pb).left,FILTER_RECT(pb).top,FILTER_RECT(pb).right,FILTER_RECT(pb).bottom);dbg(s);}
541
                */
541
                */
542
        }
542
        }
543
}
543
}
544
 
544
 
545
void DoStart(FilterRecordPtr pb){
545
void DoStart(FilterRecordPtr pb){
546
//dbg("DoStart");
546
//dbg("DoStart");
547
                        /* if src() or rad() functions are used, random access to the image data is required,
547
                        /* if src() or rad() functions are used, random access to the image data is required,
548
                           so we must request the entire image in a single chunk. */
548
                           so we must request the entire image in a single chunk. */
549
        if (HAS_BIG_DOC(pb)) {
549
        if (HAS_BIG_DOC(pb)) {
550
                chunksize = needall ? (BIGDOC_FILTER_RECT(pb).bottom - BIGDOC_FILTER_RECT(pb).top) : CHUNK_ROWS;
550
                chunksize = needall ? (BIGDOC_FILTER_RECT(pb).bottom - BIGDOC_FILTER_RECT(pb).top) : CHUNK_ROWS;
551
                toprow = BIGDOC_FILTER_RECT(pb).top;
551
                toprow = BIGDOC_FILTER_RECT(pb).top;
552
        } else {
552
        } else {
553
                chunksize = needall ? (FILTER_RECT(pb).bottom - FILTER_RECT(pb).top) : CHUNK_ROWS;
553
                chunksize = needall ? (FILTER_RECT(pb).bottom - FILTER_RECT(pb).top) : CHUNK_ROWS;
554
                toprow = FILTER_RECT(pb).top;
554
                toprow = FILTER_RECT(pb).top;
555
        }
555
        }
556
        RequestNext(pb, toprow);
556
        RequestNext(pb, toprow);
557
}
557
}
558
 
558
 
559
OSErr DoContinue(FilterRecordPtr pb){
559
OSErr DoContinue(FilterRecordPtr pb){
560
        OSErr e = noErr;
560
        OSErr e = noErr;
561
        long outoffset;
561
        long outoffset;
562
 
562
 
563
        if (HAS_BIG_DOC(pb)) {
563
        if (HAS_BIG_DOC(pb)) {
564
                VRect fr;
564
                VRect fr;
565
                if (needall) {
565
                if (needall) {
566
                        fr = BIGDOC_FILTER_RECT(pb);  // filter whole selection at once
566
                        fr = BIGDOC_FILTER_RECT(pb);  // filter whole selection at once
567
                } else if (cnvused) {
567
                } else if (cnvused) {
568
                        // we've requested one pixel extra all around
568
                        // we've requested one pixel extra all around
569
                        // (see RequestNext()), just for access purposes. But filter
569
                        // (see RequestNext()), just for access purposes. But filter
570
                        // original selection only.
570
                        // original selection only.
571
                        fr.left = BIGDOC_FILTER_RECT(pb).left;
571
                        fr.left = BIGDOC_FILTER_RECT(pb).left;
572
                        fr.right = BIGDOC_FILTER_RECT(pb).right;
572
                        fr.right = BIGDOC_FILTER_RECT(pb).right;
573
                        fr.top = toprow;
573
                        fr.top = toprow;
574
                        fr.bottom = MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
574
                        fr.bottom = MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
575
                } else {  // filter whatever portion we've been given
575
                } else {  // filter whatever portion we've been given
576
                        fr = BIGDOC_IN_RECT(pb);
576
                        fr = BIGDOC_IN_RECT(pb);
577
                }
577
                }
578
 
578
 
579
                outoffset = (long)pb->outRowBytes * (fr.top - BIGDOC_OUT_RECT(pb).top)
579
                outoffset = (long)pb->outRowBytes * (fr.top - BIGDOC_OUT_RECT(pb).top)
580
                        + (long)nplanes * (fr.left - BIGDOC_OUT_RECT(pb).left);
580
                        + (long)nplanes * (fr.left - BIGDOC_OUT_RECT(pb).left);
581
 
581
 
582
                if (!(e = process_scaled_bigdoc(pb, true, fr, fr,
582
                if (!(e = process_scaled_bigdoc(pb, true, fr, fr,
583
                        (Ptr)pb->outData + outoffset, pb->outRowBytes, 1.)))
583
                        (Ptr)pb->outData + outoffset, pb->outRowBytes, 1.)))
584
                {
584
                {
585
                        toprow += chunksize;
585
                        toprow += chunksize;
586
                        if (toprow < BIGDOC_FILTER_RECT(pb).bottom)
586
                        if (toprow < BIGDOC_FILTER_RECT(pb).bottom)
587
                                RequestNext(pb, toprow);
587
                                RequestNext(pb, toprow);
588
                        else {
588
                        else {
589
                                SETRECT(BIGDOC_IN_RECT(pb), 0, 0, 0, 0);
589
                                SETRECT(BIGDOC_IN_RECT(pb), 0, 0, 0, 0);
590
                                BIGDOC_OUT_RECT(pb) = BIGDOC_MASK_RECT(pb) = BIGDOC_IN_RECT(pb);
590
                                BIGDOC_OUT_RECT(pb) = BIGDOC_MASK_RECT(pb) = BIGDOC_IN_RECT(pb);
591
                        }
591
                        }
592
                }
592
                }
593
        } else {
593
        } else {
594
                Rect fr;
594
                Rect fr;
595
                if (needall) {
595
                if (needall) {
596
                        fr = FILTER_RECT(pb);  // filter whole selection at once
596
                        fr = FILTER_RECT(pb);  // filter whole selection at once
597
                } else if (cnvused) {
597
                } else if (cnvused) {
598
                        // we've requested one pixel extra all around
598
                        // we've requested one pixel extra all around
599
                        // (see RequestNext()), just for access purposes. But filter
599
                        // (see RequestNext()), just for access purposes. But filter
600
                        // original selection only.
600
                        // original selection only.
601
                        fr.left = FILTER_RECT(pb).left;
601
                        fr.left = FILTER_RECT(pb).left;
602
                        fr.right = FILTER_RECT(pb).right;
602
                        fr.right = FILTER_RECT(pb).right;
603
                        fr.top = toprow;
603
                        fr.top = toprow;
604
                        fr.bottom = MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
604
                        fr.bottom = MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
605
                } else {  // filter whatever portion we've been given
605
                } else {  // filter whatever portion we've been given
606
                        fr = IN_RECT(pb);
606
                        fr = IN_RECT(pb);
607
                }
607
                }
608
 
608
 
609
                outoffset = (long)pb->outRowBytes*(fr.top - OUT_RECT(pb).top)
609
                outoffset = (long)pb->outRowBytes*(fr.top - OUT_RECT(pb).top)
610
                        + (long)nplanes*(fr.left - OUT_RECT(pb).left);
610
                        + (long)nplanes*(fr.left - OUT_RECT(pb).left);
611
 
611
 
612
                if(!(e = process_scaled_olddoc(pb, true, fr, fr,
612
                if(!(e = process_scaled_olddoc(pb, true, fr, fr,
613
                        (Ptr)pb->outData+outoffset, pb->outRowBytes, 1.)))
613
                        (Ptr)pb->outData+outoffset, pb->outRowBytes, 1.)))
614
                {
614
                {
615
                        toprow += chunksize;
615
                        toprow += chunksize;
616
                        if(toprow < FILTER_RECT(pb).bottom)
616
                        if(toprow < FILTER_RECT(pb).bottom)
617
                                RequestNext(pb,toprow);
617
                                RequestNext(pb,toprow);
618
                        else{
618
                        else{
619
                                SETRECT(IN_RECT(pb),0,0,0,0);
619
                                SETRECT(IN_RECT(pb),0,0,0,0);
620
                                OUT_RECT(pb) = MASK_RECT(pb) = IN_RECT(pb);
620
                                OUT_RECT(pb) = MASK_RECT(pb) = IN_RECT(pb);
621
                        }
621
                        }
622
                }
622
                }
623
        }
623
        }
624
        return e;
624
        return e;
625
}
625
}
626
 
626
 
627
void DoFinish(FilterRecordPtr pb){
627
void DoFinish(FilterRecordPtr pb){
628
        int i;
628
        int i;
629
 
629
 
630
        WriteScriptParamsOnRead();
630
        WriteScriptParamsOnRead();
631
 
631
 
632
        for(i = 4; i--;){
632
        for(i = 4; i--;){
633
                freetree(tree[i]);
633
                freetree(tree[i]);
634
                if(expr[i]) free(expr[i]);
634
                if(expr[i]) free(expr[i]);
635
        }
635
        }
636
}
636
}