Subversion Repositories filter_foundry

Rev

Rev 288 | Rev 312 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

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