Subversion Repositories filter_foundry

Rev

Rev 536 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 536 Rev 550
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.net
3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.net
4
    Copyright (C) 2018-2022 Daniel Marschall, ViaThinkSoft
4
    Copyright (C) 2018-2023 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 "ff.h"
21
#include "ff.h"
22
 
22
 
23
#include "symtab.h"
23
#include "symtab.h"
24
#include "node.h"
24
#include "node.h"
25
#include "funcs.h"
25
#include "funcs.h"
26
#include "y.tab.h"
26
#include "y.tab.h"
27
 
27
 
28
extern value_type var[];
28
extern value_type var[];
29
extern int nplanes,varused[],cnvused;
29
extern int nplanes,varused[],cnvused;
30
extern struct node *tree[];
30
extern struct node *tree[];
31
 
31
 
32
// points to first row, first column of selection image data
32
// points to first row, first column of selection image data
33
// this is used by src() and cnv() functions to access pixels
33
// this is used by src() and cnv() functions to access pixels
34
unsigned char *image_ptr;
34
unsigned char *image_ptr;
35
 
35
 
36
extern int needinput;
36
extern int needinput;
37
int state_changing_funcs_used;
37
int state_changing_funcs_used;
38
 
38
 
39
/* get prepared to evaluate expression trees--
39
/* get prepared to evaluate expression trees--
40
   this assumes that tree[] array is already set up
40
   this assumes that tree[] array is already set up
41
   return TRUE if we're ready to go
41
   return TRUE if we're ready to go
42
*/
42
*/
43
 
43
 
44
// minimum setup required when formulae have not changed,
44
// minimum setup required when formulae have not changed,
45
// and a new preview is to be generated. (Called by recalc_preview())
45
// and a new preview is to be generated. (Called by recalc_preview())
46
void evalinit(void){
46
void evalinit(void){
47
        int i;
47
        int i;
48
 
48
 
49
        initialize_rnd_variables();
49
        initialize_rnd_variables();
50
 
50
 
51
        for (i=0; i<NUM_CELLS; ++i) {
51
        for (i=0; i<NUM_CELLS; ++i) {
52
                cell[i] = 0;
52
                cell[i] = 0;
53
        }
53
        }
54
}
54
}
55
 
55
 
56
// full setup for evaluation, called when formulae have changed.
56
// full setup for evaluation, called when formulae have changed.
57
Boolean setup(FilterRecordPtr pb){
57
Boolean setup(FilterRecordPtr pb){
58
        int srcrad;
58
        int srcrad;
59
        int i;
59
        int i;
60
 
60
 
61
        // Attention: If you introduce new variables, please define them also in lexer.l
61
        // Attention: If you introduce new variables, please define them also in lexer.l
62
        if (HAS_BIG_DOC(pb)) {
62
        if (HAS_BIG_DOC(pb)) {
63
                var['X'] = BIGDOC_FILTER_RECT(pb).right - BIGDOC_FILTER_RECT(pb).left;
63
                var['X'] = BIGDOC_FILTER_RECT(pb).right - BIGDOC_FILTER_RECT(pb).left;
64
                var['Y'] = BIGDOC_FILTER_RECT(pb).bottom - BIGDOC_FILTER_RECT(pb).top;
64
                var['Y'] = BIGDOC_FILTER_RECT(pb).bottom - BIGDOC_FILTER_RECT(pb).top;
65
        } else {
65
        } else {
66
                var['X'] = FILTER_RECT(pb).right - FILTER_RECT(pb).left;
66
                var['X'] = FILTER_RECT(pb).right - FILTER_RECT(pb).left;
67
                var['Y'] = FILTER_RECT(pb).bottom - FILTER_RECT(pb).top;
67
                var['Y'] = FILTER_RECT(pb).bottom - FILTER_RECT(pb).top;
68
        }
68
        }
69
        var['Z'] = nplanes;
69
        var['Z'] = nplanes;
70
        var['D'] = val_D;
70
        var['D'] = val_D;
71
        var['M'] = ff_M();
71
        var['M'] = ff_M();
72
 
72
 
73
        var['R'] = var['G'] = var['B'] = var['A'] = var['C'] = 255;
73
        var['R'] = var['G'] = var['B'] = var['A'] = var['C'] = 255;
74
        var['I'] = val_I;
74
        var['I'] = val_I;
75
        var['U'] = val_U;
75
        var['U'] = val_U;
76
        var['V'] = val_V;
76
        var['V'] = val_V;
77
 
77
 
78
        /* initialise flags for tracking special variable usage */
78
        /* initialise flags for tracking special variable usage */
79
        for(i = 0; i < 0x100; i++)
79
        for(i = 0; i < 0x100; i++)
80
                varused[i] = 0;
80
                varused[i] = 0;
81
        needall = srcrad = cnvused = state_changing_funcs_used = 0;
81
        needall = srcrad = cnvused = state_changing_funcs_used = 0;
82
        for(i = 0; i < nplanes; ++i){
82
        for(i = 0; i < nplanes; ++i){
83
                //char s[100];sprintf(s,"expr[%d]=%#x",i,expr[i]);dbg(s);
83
                //char s[100];sprintf(s,"gdata->parm.szFormula[%d]=%#x",i,gdata->parm.szFormula[i]);dbg(s);
84
                if( tree[i] || (tree[i] = parseexpr(expr[i])) )
84
                if( tree[i] || (tree[i] = parseexpr(gdata->parm.szFormula[i])) )
85
                        // if src() and rad() is used => needall=1, since we need arbitary access to all pixels
85
                        // if src() and rad() is used => needall=1, since we need arbitary access to all pixels
86
                        checkvars(tree[i],varused,&cnvused,&srcrad,&state_changing_funcs_used);
86
                        checkvars(tree[i],varused,&cnvused,&srcrad,&state_changing_funcs_used);
87
                else
87
                else
88
                        break;
88
                        break;
89
        }
89
        }
90
        needall = srcrad;
90
        needall = srcrad;
91
        needinput = ( cnvused || needall
91
        needinput = ( cnvused || needall
92
                || varused['r'] || varused['g'] || varused['b'] || varused['a']
92
                || varused['r'] || varused['g'] || varused['b'] || varused['a']
93
                || varused['i'] || varused['u'] || varused['v'] || varused['c'] );
93
                || varused['i'] || varused['u'] || varused['v'] || varused['c'] );
94
 
94
 
95
        /*
95
        /*
96
         * Workaround for PSPI for GIMP:
96
         * Workaround for PSPI for GIMP:
97
         * Filters will only fill the bottom of the picture, not the whole canvas.
97
         * Filters will only fill the bottom of the picture, not the whole canvas.
98
         * The reason is that OnContinue/main.c:RequestNext() processes the image in chunks,
98
         * The reason is that OnContinue/main.c:RequestNext() processes the image in chunks,
99
         * and probably due to a bug, PSPI only applies the image data of the last chunk.
99
         * and probably due to a bug, PSPI only applies the image data of the last chunk.
100
         * Workaround applied in FF 1.7: If the host is GIMP, then we set
100
         * Workaround applied in FF 1.7: If the host is GIMP, then we set
101
         * needall=1 to disable chunked processing.
101
         * needall=1 to disable chunked processing.
102
         */
102
         */
103
        if (pb->hostSig == HOSTSIG_GIMP) needall = true;
103
        if (pb->hostSig == HOSTSIG_GIMP) needall = true;
104
 
104
 
105
        // If we want accurate rnd(a,b) results (i.e. FilterFoundry and FilterFactory output
105
        // If we want accurate rnd(a,b) results (i.e. FilterFoundry and FilterFactory output
106
        // exactly the same picture), we must not use chunked processing.
106
        // exactly the same picture), we must not use chunked processing.
107
        if (state_changing_funcs_used) needall = true;
107
        if (state_changing_funcs_used) needall = true;
108
 
108
 
109
        // DM 09 Sep 2021: Added, because otherwise, some filters are very, very, very slow!
109
        // DM 09 Sep 2021: Added, because otherwise, some filters are very, very, very slow!
110
        // e.g. BlowOut by Greg Schorno:
110
        // e.g. BlowOut by Greg Schorno:
111
    //     R = put(sin(d*ctl(0)/4+ctl(2)*4)/(val(1,256,16)*256/M),0),src(x+get(0),y+get(0),z)
111
    //     R = put(sin(d*ctl(0)/4+ctl(2)*4)/(val(1,256,16)*256/M),0),src(x+get(0),y+get(0),z)
112
    //     G = src(x+get(0),y+get(0),z)
112
    //     G = src(x+get(0),y+get(0),z)
113
    //     B = src(x+get(0),y+get(0),z)
113
    //     B = src(x+get(0),y+get(0),z)
114
        state_changing_funcs_used = 0;
114
        state_changing_funcs_used = 0;
115
 
115
 
116
        evalinit();
116
        evalinit();
117
        return i==nplanes; /* all required expressions parse OK */
117
        return i==nplanes; /* all required expressions parse OK */
118
}
118
}
119
 
119
 
120
void evalpixel(unsigned char *outp,unsigned char *inp){
120
void evalpixel(unsigned char *outp,unsigned char *inp){
121
        int f,k;
121
        int f,k;
122
 
122
 
123
        if(needinput){
123
        if(needinput){
124
                var['r'] = inp[0];
124
                var['r'] = inp[0];
125
                var['g'] = nplanes > 1 ? inp[1] : 0;
125
                var['g'] = nplanes > 1 ? inp[1] : 0;
126
                var['b'] = nplanes > 2 ? inp[2] : 0;
126
                var['b'] = nplanes > 2 ? inp[2] : 0;
127
                var['a'] = nplanes > 3 ? inp[3] : 0;
127
                var['a'] = nplanes > 3 ? inp[3] : 0;
128
 
128
 
129
                // For Y, the definition is Y := 0.299R + 0.587G + 0.114B
129
                // For Y, the definition is Y := 0.299R + 0.587G + 0.114B
130
                if(varused['i']) var['i'] = ff_i();
130
                if(varused['i']) var['i'] = ff_i();
131
 
131
 
132
                // For U, the definition is U := (B-Y) * 0.493; the range would be [-111..111]
132
                // For U, the definition is U := (B-Y) * 0.493; the range would be [-111..111]
133
                // Filter Factory divided it by 2, resulting in a range of [-55..55].
133
                // Filter Factory divided it by 2, resulting in a range of [-55..55].
134
                // Due to compatibility reasons, we adopt that behavior.
134
                // Due to compatibility reasons, we adopt that behavior.
135
                if(varused['u']) var['u'] = ff_u();
135
                if(varused['u']) var['u'] = ff_u();
136
 
136
 
137
                // For V, the definition is V := (R-Y) * 0.877; the range would be [-156..156]
137
                // For V, the definition is V := (R-Y) * 0.877; the range would be [-156..156]
138
                // Filter Factory divided it by 2, resulting in a range of [-78..78].
138
                // Filter Factory divided it by 2, resulting in a range of [-78..78].
139
                // Due to compatibility reasons, we adopt that behavior.
139
                // Due to compatibility reasons, we adopt that behavior.
140
                if(varused['v']) var['v'] = ff_v();
140
                if(varused['v']) var['v'] = ff_v();
141
        }
141
        }
142
 
142
 
143
        if(varused['d']) var['d'] = ff_d();
143
        if(varused['d']) var['d'] = ff_d();
144
        if(varused['m']) var['m'] = ff_m();
144
        if(varused['m']) var['m'] = ff_m();
145
 
145
 
146
        for(k = 0; k < nplanes; ++k){
146
        for(k = 0; k < nplanes; ++k){
147
                if(needinput)
147
                if(needinput)
148
                        var['c'] = inp[k];
148
                        var['c'] = inp[k];
149
                var['z'] = k;
149
                var['z'] = k;
150
                var['p'] = k; // undocumented alias of z
150
                var['p'] = k; // undocumented alias of z
151
                f = eval(tree[k]);
151
                f = eval(tree[k]);
152
                if (outp)
152
                if (outp)
153
                        outp[k] = f<0 ? 0 : (f>255 ? 255 : f); // clamp channel value to 0-255
153
                        outp[k] = f<0 ? 0 : (f>255 ? 255 : f); // clamp channel value to 0-255
154
        }
154
        }
155
}
155
}
156
 
156
 
157
/* Zoom and filter image.
157
/* Zoom and filter image.
158
 * Parameters:  pb          - Photoshop Filter parameter block
158
 * Parameters:  pb          - Photoshop Filter parameter block
159
 *              progress    - whether to use Photoshop's progress bar
159
 *              progress    - whether to use Photoshop's progress bar
160
 *                            (not appropriate during preview)
160
 *                            (not appropriate during preview)
161
 *              filterRect  - rectangle (within pb->inRect)
161
 *              filterRect  - rectangle (within pb->inRect)
162
 *                            of area to be filtered. This may not correspond
162
 *                            of area to be filtered. This may not correspond
163
 *                            to pb->filterRect, it may be just a piece.
163
 *                            to pb->filterRect, it may be just a piece.
164
 *              outPiece    - rectangle defining scaled output buffer.
164
 *              outPiece    - rectangle defining scaled output buffer.
165
 *                            In case of zoomed preview, this is physically
165
 *                            In case of zoomed preview, this is physically
166
 *                            scaled FROM filterRect (or equal to filterRect
166
 *                            scaled FROM filterRect (or equal to filterRect
167
 *                            for unscaled 1:1 filtering).
167
 *                            for unscaled 1:1 filtering).
168
 *              outData     - pointer to output data buffer
168
 *              outData     - pointer to output data buffer
169
 *              outRowBytes - row stride of output data buffer
169
 *              outRowBytes - row stride of output data buffer
170
 *              zoom        - pixel scale factor (both horiz & vert)
170
 *              zoom        - pixel scale factor (both horiz & vert)
171
 *                            e.g. 2.0 means 1 output pixel per 2 input pixels.
171
 *                            e.g. 2.0 means 1 output pixel per 2 input pixels.
172
 */
172
 */
173
 
173
 
174
//#define PROCESS_SCALED_GAP_DEBUG 1
174
//#define PROCESS_SCALED_GAP_DEBUG 1
175
 
175
 
176
OSErr process_scaled_bigdoc(FilterRecordPtr pb, Boolean progress,
176
OSErr process_scaled_bigdoc(FilterRecordPtr pb, Boolean progress,
177
                          VRect filterPiece, VRect outPiece,
177
                          VRect filterPiece, VRect outPiece,
178
                          void *outData, long outRowBytes, double zoom){
178
                          void *outData, long outRowBytes, double zoom){
179
        unsigned char *inrow,*outrow,*outp;
179
        unsigned char *inrow,*outrow,*outp;
180
        int j,i;
180
        int j,i;
181
        int64_t t, ticks = TICKCOUNT();
181
        int64_t t, ticks = TICKCOUNT();
182
        double x,y,k;
182
        double x,y,k;
183
 
183
 
184
        #ifdef PROCESS_SCALED_GAP_DEBUG
184
        #ifdef PROCESS_SCALED_GAP_DEBUG
185
        char s[0x200];
185
        char s[0x200];
186
        int last_good_x, last_good_y;
186
        int last_good_x, last_good_y;
187
        last_good_y = -1;
187
        last_good_y = -1;
188
        #endif
188
        #endif
189
 
189
 
190
        VRect filterRect;
190
        VRect filterRect;
191
        VRect inRect;
191
        VRect inRect;
192
 
192
 
193
        if (HAS_BIG_DOC(pb)) {
193
        if (HAS_BIG_DOC(pb)) {
194
                filterRect = BIGDOC_FILTER_RECT(pb);
194
                filterRect = BIGDOC_FILTER_RECT(pb);
195
                inRect = BIGDOC_IN_RECT(pb);
195
                inRect = BIGDOC_IN_RECT(pb);
196
        } else {
196
        } else {
197
                filterRect.bottom = FILTER_RECT(pb).bottom;
197
                filterRect.bottom = FILTER_RECT(pb).bottom;
198
                filterRect.left = FILTER_RECT(pb).left;
198
                filterRect.left = FILTER_RECT(pb).left;
199
                filterRect.right = FILTER_RECT(pb).right;
199
                filterRect.right = FILTER_RECT(pb).right;
200
                filterRect.top = FILTER_RECT(pb).top;
200
                filterRect.top = FILTER_RECT(pb).top;
201
                inRect.bottom = IN_RECT(pb).bottom;
201
                inRect.bottom = IN_RECT(pb).bottom;
202
                inRect.left = IN_RECT(pb).left;
202
                inRect.left = IN_RECT(pb).left;
203
                inRect.right = IN_RECT(pb).right;
203
                inRect.right = IN_RECT(pb).right;
204
                inRect.top = IN_RECT(pb).top;
204
                inRect.top = IN_RECT(pb).top;
205
        }
205
        }
206
 
206
 
207
        // find base pointer to selection image data
207
        // find base pointer to selection image data
208
        image_ptr = (unsigned char*)pb->inData
208
        image_ptr = (unsigned char*)pb->inData
209
                                + (long)pb->inRowBytes*(filterRect.top - inRect.top)
209
                                + (long)pb->inRowBytes*(filterRect.top - inRect.top)
210
                                + (long)nplanes*(filterRect.left - inRect.left);
210
                                + (long)nplanes*(filterRect.left - inRect.left);
211
 
211
 
212
        if (state_changing_funcs_used) {
212
        if (state_changing_funcs_used) {
213
                // Fill gap between selection/filter top border and top preview zoomed border
213
                // Fill gap between selection/filter top border and top preview zoomed border
214
                for (y = 0; y < (double)filterPiece.top - (double)filterRect.top; ++y) {
214
                for (y = 0; y < (double)filterPiece.top - (double)filterRect.top; ++y) {
215
                        #ifdef PROCESS_SCALED_GAP_DEBUG
215
                        #ifdef PROCESS_SCALED_GAP_DEBUG
216
                        if (state_changing_funcs_used && last_good_y != (int)floor(y-1)) { sprintf(s, "Non calculated Y gap, type 1: %f, last good %d, zoom %f\n", y, last_good_y, zoom); simplealert(s); } last_good_y = (int)floor(y);
216
                        if (state_changing_funcs_used && last_good_y != (int)floor(y-1)) { sprintf(s, "Non calculated Y gap, type 1: %f, last good %d, zoom %f\n", y, last_good_y, zoom); simplealert(s); } last_good_y = (int)floor(y);
217
                        #endif
217
                        #endif
218
 
218
 
219
                        var['y'] = (value_type)y;
219
                        var['y'] = (value_type)y;
220
                        inrow = image_ptr + (long)(y)*pb->inRowBytes;
220
                        inrow = image_ptr + (long)(y)*pb->inRowBytes;
221
 
221
 
222
                        #ifdef PROCESS_SCALED_GAP_DEBUG
222
                        #ifdef PROCESS_SCALED_GAP_DEBUG
223
                        last_good_x = -1;
223
                        last_good_x = -1;
224
                        #endif
224
                        #endif
225
 
225
 
226
                        for (x = 0; x < (double)filterRect.right - (double)filterRect.left; ++x) {
226
                        for (x = 0; x < (double)filterRect.right - (double)filterRect.left; ++x) {
227
                                #ifdef PROCESS_SCALED_GAP_DEBUG
227
                                #ifdef PROCESS_SCALED_GAP_DEBUG
228
                                if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 1a: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
228
                                if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 1a: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
229
                                #endif
229
                                #endif
230
 
230
 
231
                                var['x'] = (value_type)x;
231
                                var['x'] = (value_type)x;
232
                                evalpixel(NULL,inrow + (long)(x)*nplanes);
232
                                evalpixel(NULL,inrow + (long)(x)*nplanes);
233
                        }
233
                        }
234
 
234
 
235
                        #ifdef PROCESS_SCALED_GAP_DEBUG
235
                        #ifdef PROCESS_SCALED_GAP_DEBUG
236
                        if (var['x'] != var['X']-1) { sprintf(s, "X not at right border #1: x=%d, X=%d\n", var['x'], var['X']); simplealert(s); }
236
                        if (var['x'] != var['X']-1) { sprintf(s, "X not at right border #1: x=%d, X=%d\n", var['x'], var['X']); simplealert(s); }
237
                        #endif
237
                        #endif
238
                }
238
                }
239
        }
239
        }
240
 
240
 
241
        // j indexes scaled output rows
241
        // j indexes scaled output rows
242
        for( j = outPiece.top, outrow = (unsigned char*)outData, y = (double)filterPiece.top - (double)filterRect.top ;
242
        for( j = outPiece.top, outrow = (unsigned char*)outData, y = (double)filterPiece.top - (double)filterRect.top ;
243
                 j < outPiece.bottom ; ++j, outrow += outRowBytes, y += zoom )
243
                 j < outPiece.bottom ; ++j, outrow += outRowBytes, y += zoom )
244
        {
244
        {
245
                #ifdef PROCESS_SCALED_GAP_DEBUG
245
                #ifdef PROCESS_SCALED_GAP_DEBUG
246
                if (state_changing_funcs_used && last_good_y != (int)floor(y-1)) { sprintf(s, "Non calculated Y gap, type 1: %f, last good %d, zoom %f\n", y, last_good_y, zoom); simplealert(s); } last_good_y = (int)floor(y);
246
                if (state_changing_funcs_used && last_good_y != (int)floor(y-1)) { sprintf(s, "Non calculated Y gap, type 1: %f, last good %d, zoom %f\n", y, last_good_y, zoom); simplealert(s); } last_good_y = (int)floor(y);
247
                #endif
247
                #endif
248
 
248
 
249
                var['y'] = (value_type)y;  // index of corresponding *input* row, top of selection == 0
249
                var['y'] = (value_type)y;  // index of corresponding *input* row, top of selection == 0
250
                inrow = image_ptr + (long)y*pb->inRowBytes;
250
                inrow = image_ptr + (long)y*pb->inRowBytes;
251
 
251
 
252
                #ifdef PROCESS_SCALED_GAP_DEBUG
252
                #ifdef PROCESS_SCALED_GAP_DEBUG
253
                last_good_x = -1;
253
                last_good_x = -1;
254
                #endif
254
                #endif
255
 
255
 
256
                if (state_changing_funcs_used) {
256
                if (state_changing_funcs_used) {
257
                        // Fill gap between left selection/image border and left border of the preview-area
257
                        // Fill gap between left selection/image border and left border of the preview-area
258
                        for (x = 0; x < (double)filterPiece.left - (double)filterRect.left; ++x) {
258
                        for (x = 0; x < (double)filterPiece.left - (double)filterRect.left; ++x) {
259
                                #ifdef PROCESS_SCALED_GAP_DEBUG
259
                                #ifdef PROCESS_SCALED_GAP_DEBUG
260
                                if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 2a: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
260
                                if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 2a: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
261
                                #endif
261
                                #endif
262
 
262
 
263
                                var['x'] = (value_type)x;
263
                                var['x'] = (value_type)x;
264
                                evalpixel(NULL,inrow + (long)(x)*nplanes);
264
                                evalpixel(NULL,inrow + (long)(x)*nplanes);
265
                        }
265
                        }
266
                }
266
                }
267
 
267
 
268
                // i indexes scaled output columns
268
                // i indexes scaled output columns
269
                for( outp = outrow, i = outPiece.left, x = (double)filterPiece.left - (double)filterRect.left ;
269
                for( outp = outrow, i = outPiece.left, x = (double)filterPiece.left - (double)filterRect.left ;
270
                         i < outPiece.right ; ++i, outp += nplanes, x += zoom )
270
                         i < outPiece.right ; ++i, outp += nplanes, x += zoom )
271
                {
271
                {
272
                        #ifdef PROCESS_SCALED_GAP_DEBUG
272
                        #ifdef PROCESS_SCALED_GAP_DEBUG
273
                        if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 2b: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
273
                        if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 2b: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
274
                        #endif
274
                        #endif
275
 
275
 
276
                        var['x'] = (value_type)x;  // index of corresponding *input* column, left of selection == 0
276
                        var['x'] = (value_type)x;  // index of corresponding *input* column, left of selection == 0
277
                        evalpixel(outp,inrow + (long)(x)*nplanes); /* var['x'] & var['y'] are implicit parameters */
277
                        evalpixel(outp,inrow + (long)(x)*nplanes); /* var['x'] & var['y'] are implicit parameters */
278
 
278
 
279
                        if (state_changing_funcs_used) {
279
                        if (state_changing_funcs_used) {
280
                                // Fill gap between each X-preview-pixel (discarded pixels due to zoom level)
280
                                // Fill gap between each X-preview-pixel (discarded pixels due to zoom level)
281
                                for (k = x+1; floor(k) < floor(x + zoom); ++k) {
281
                                for (k = x+1; floor(k) < floor(x + zoom); ++k) {
282
                                        #ifdef PROCESS_SCALED_GAP_DEBUG
282
                                        #ifdef PROCESS_SCALED_GAP_DEBUG
283
                                        if (state_changing_funcs_used && last_good_x != (int)floor(k-1)) { sprintf(s, "Non calculated X gap, type 2c: %f (x=%f), last good %d, zoom %f\n", k, x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(k);
283
                                        if (state_changing_funcs_used && last_good_x != (int)floor(k-1)) { sprintf(s, "Non calculated X gap, type 2c: %f (x=%f), last good %d, zoom %f\n", k, x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(k);
284
                                        #endif
284
                                        #endif
285
 
285
 
286
                                        var['x'] = (value_type)k;
286
                                        var['x'] = (value_type)k;
287
                                        if (var['x'] >= var['X']) break;
287
                                        if (var['x'] >= var['X']) break;
288
                                        evalpixel(NULL,inrow + (long)(k)*nplanes);
288
                                        evalpixel(NULL,inrow + (long)(k)*nplanes);
289
                                }
289
                                }
290
                        }
290
                        }
291
                }
291
                }
292
 
292
 
293
                if (state_changing_funcs_used) {
293
                if (state_changing_funcs_used) {
294
                        // Fill gap between right border of preview-area and right border of selection/image border
294
                        // Fill gap between right border of preview-area and right border of selection/image border
295
 
295
 
296
                        for (x = (double)var['x']+1; x < (double)filterRect.right - (double)filterRect.left; ++x) {
296
                        for (x = (double)var['x']+1; x < (double)filterRect.right - (double)filterRect.left; ++x) {
297
                                #ifdef PROCESS_SCALED_GAP_DEBUG
297
                                #ifdef PROCESS_SCALED_GAP_DEBUG
298
                                if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 2d: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
298
                                if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 2d: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
299
                                #endif
299
                                #endif
300
 
300
 
301
                                var['x'] = (value_type)x;
301
                                var['x'] = (value_type)x;
302
                                evalpixel(NULL,inrow + (long)(x)*nplanes);
302
                                evalpixel(NULL,inrow + (long)(x)*nplanes);
303
                        }
303
                        }
304
 
304
 
305
                        #ifdef PROCESS_SCALED_GAP_DEBUG
305
                        #ifdef PROCESS_SCALED_GAP_DEBUG
306
                        if (var['x'] != var['X']-1) { sprintf(s, "X not at right border #2: x=%d, X=%d\n", var['x'], var['X']); simplealert(s);}
306
                        if (var['x'] != var['X']-1) { sprintf(s, "X not at right border #2: x=%d, X=%d\n", var['x'], var['X']); simplealert(s);}
307
                        #endif
307
                        #endif
308
 
308
 
309
                        // Fill gap between each Y-preview-pixel (discarded pixels due to zoom level),
309
                        // Fill gap between each Y-preview-pixel (discarded pixels due to zoom level),
310
                        // but not for the very last line, since we are then done drawing our preview picture
310
                        // but not for the very last line, since we are then done drawing our preview picture
311
                        for (k = y+1; floor(k) < floor(y + zoom) && (j < outPiece.bottom-1); ++k) {
311
                        for (k = y+1; floor(k) < floor(y + zoom) && (j < outPiece.bottom-1); ++k) {
312
                                #ifdef PROCESS_SCALED_GAP_DEBUG
312
                                #ifdef PROCESS_SCALED_GAP_DEBUG
313
                                if (state_changing_funcs_used && last_good_y != (int)floor(k-1)) { sprintf(s, "Non calculated Y gap, type 3a: %f (y=%f), last good %d, zoom %f\n", k, y, last_good_y, zoom); simplealert(s); } last_good_y = (int)floor(k);
313
                                if (state_changing_funcs_used && last_good_y != (int)floor(k-1)) { sprintf(s, "Non calculated Y gap, type 3a: %f (y=%f), last good %d, zoom %f\n", k, y, last_good_y, zoom); simplealert(s); } last_good_y = (int)floor(k);
314
                                #endif
314
                                #endif
315
 
315
 
316
                                var['y'] = (value_type)k;
316
                                var['y'] = (value_type)k;
317
                                if (var['y'] >= var['Y']) break;
317
                                if (var['y'] >= var['Y']) break;
318
                                inrow = image_ptr + (long)(k)*pb->inRowBytes;
318
                                inrow = image_ptr + (long)(k)*pb->inRowBytes;
319
 
319
 
320
                                #ifdef PROCESS_SCALED_GAP_DEBUG
320
                                #ifdef PROCESS_SCALED_GAP_DEBUG
321
                                last_good_x = -1;
321
                                last_good_x = -1;
322
                                #endif
322
                                #endif
323
 
323
 
324
                                for (x = 0; x < (double)filterRect.right - (double)filterRect.left; ++x) {
324
                                for (x = 0; x < (double)filterRect.right - (double)filterRect.left; ++x) {
325
                                        #ifdef PROCESS_SCALED_GAP_DEBUG
325
                                        #ifdef PROCESS_SCALED_GAP_DEBUG
326
                                        if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 3b: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
326
                                        if (state_changing_funcs_used && last_good_x != (int)floor(x-1)) { sprintf(s, "Non calculated X gap, type 3b: %f, last good %d, zoom %f\n", x, last_good_x, zoom); simplealert(s); } last_good_x = (int)floor(x);
327
                                        #endif
327
                                        #endif
328
 
328
 
329
                                        var['x'] = (value_type)x;
329
                                        var['x'] = (value_type)x;
330
                                        evalpixel(NULL,inrow + (long)(x)*nplanes);
330
                                        evalpixel(NULL,inrow + (long)(x)*nplanes);
331
                                }
331
                                }
332
 
332
 
333
                                #ifdef PROCESS_SCALED_GAP_DEBUG
333
                                #ifdef PROCESS_SCALED_GAP_DEBUG
334
                                if (var['x'] != var['X']-1) {sprintf(s, "X not at right border #3: x=%d, X=%d\n", var['x'], var['X']); simplealert(s);}
334
                                if (var['x'] != var['X']-1) {sprintf(s, "X not at right border #3: x=%d, X=%d\n", var['x'], var['X']); simplealert(s);}
335
                                #endif
335
                                #endif
336
                        }
336
                        }
337
                }
337
                }
338
 
338
 
339
                if(progress){
339
                if(progress){
340
                        if((t = TICKCOUNT()) > ticks){
340
                        if((t = TICKCOUNT()) > ticks){
341
                                ticks = t + TICKS_SEC/4;
341
                                ticks = t + TICKS_SEC/4;
342
                                if(pb->abortProc())
342
                                if(pb->abortProc())
343
                                        return userCanceledErr;
343
                                        return userCanceledErr;
344
                                else
344
                                else
345
                                        pb->progressProc((int)y - filterRect.top,filterRect.bottom - filterRect.top);
345
                                        pb->progressProc((int)y - filterRect.top,filterRect.bottom - filterRect.top);
346
                        }
346
                        }
347
                }else{
347
                }else{
348
                        #ifdef MAC_ENV
348
                        #ifdef MAC_ENV
349
                        /* to stop delays during typing of expressions,
349
                        /* to stop delays during typing of expressions,
350
                           immediately abort preview calculation if a key or mouse has been pressed. */
350
                           immediately abort preview calculation if a key or mouse has been pressed. */
351
                        EventRecord event;
351
                        EventRecord event;
352
                        if(EventAvail(mDownMask|keyDownMask|autoKeyMask,&event)) {
352
                        if(EventAvail(mDownMask|keyDownMask|autoKeyMask,&event)) {
353
                                return userCanceledErr;
353
                                return userCanceledErr;
354
                        }
354
                        }
355
                        #endif
355
                        #endif
356
                }
356
                }
357
        }
357
        }
358
 
358
 
359
        // Note for state_changing_funcs_used: We will not evaluate the gap between bottom border
359
        // Note for state_changing_funcs_used: We will not evaluate the gap between bottom border
360
        // of preview area and the bottom border of the selection/filter, because there are no
360
        // of preview area and the bottom border of the selection/filter, because there are no
361
        // preview output pixels left that could be affected by these gap evaluations.
361
        // preview output pixels left that could be affected by these gap evaluations.
362
 
362
 
363
        return noErr;
363
        return noErr;
364
}
364
}
365
 
365
 
366
OSErr process_scaled_olddoc(FilterRecordPtr pb, Boolean progress,
366
OSErr process_scaled_olddoc(FilterRecordPtr pb, Boolean progress,
367
        Rect filterPiece, Rect outPiece,
367
        Rect filterPiece, Rect outPiece,
368
        void* outData, long outRowBytes, double zoom) {
368
        void* outData, long outRowBytes, double zoom) {
369
 
369
 
370
        VRect filterPiece32;
370
        VRect filterPiece32;
371
        VRect outPiece32;
371
        VRect outPiece32;
372
 
372
 
373
        filterPiece32.bottom = filterPiece.bottom;
373
        filterPiece32.bottom = filterPiece.bottom;
374
        filterPiece32.left = filterPiece.left;
374
        filterPiece32.left = filterPiece.left;
375
        filterPiece32.right = filterPiece.right;
375
        filterPiece32.right = filterPiece.right;
376
        filterPiece32.top = filterPiece.top;
376
        filterPiece32.top = filterPiece.top;
377
 
377
 
378
        outPiece32.bottom = outPiece.bottom;
378
        outPiece32.bottom = outPiece.bottom;
379
        outPiece32.left = outPiece.left;
379
        outPiece32.left = outPiece.left;
380
        outPiece32.right = outPiece.right;
380
        outPiece32.right = outPiece.right;
381
        outPiece32.top = outPiece.top;
381
        outPiece32.top = outPiece.top;
382
 
382
 
383
        return process_scaled_bigdoc(pb, progress, filterPiece32, outPiece32, outData, outRowBytes, zoom);
383
        return process_scaled_bigdoc(pb, progress, filterPiece32, outPiece32, outData, outRowBytes, zoom);
384
}
384
}
385
 
385