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 |