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 | } |