Subversion Repositories filter_foundry

Rev

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

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