Subversion Repositories filter_foundry

Rev

Rev 198 | Rev 206 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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