Subversion Repositories filter_foundry

Rev

Rev 235 | Rev 268 | 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. // Strict compatibility to Filter Factory
  29. //#define YUV_FILTER_FACTORY
  30.  
  31. extern value_type var[];
  32. extern int nplanes,varused[],cnvused;
  33. extern struct node *tree[];
  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.  
  39. extern int needinput;
  40. int state_changing_funcs_used;
  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.  
  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(){
  50.         int i;
  51.  
  52.         INITRANDSEED();
  53.  
  54.         for (i=0; i<NUM_CELLS; ++i) {
  55.                 cell[i] = 0;
  56.         }
  57. }
  58.  
  59. // full setup for evaluation, called when formulae have changed.
  60. Boolean setup(FilterRecordPtr pb){
  61.         int i;
  62.  
  63.         // Attention: If you introduce new variables, please define them also in lexer.l
  64.         if (HAS_BIG_DOC(pb)) {
  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;
  67.         } else {
  68.                 var['X'] = FILTER_RECT(pb).right - FILTER_RECT(pb).left;
  69.                 var['Y'] = FILTER_RECT(pb).bottom - FILTER_RECT(pb).top;
  70.         }
  71.         var['Z'] = nplanes;
  72.         var['D'] = 1024;
  73.         var['M'] = ff_c2m(var['X'],var['Y'])/2;
  74.  
  75.         /* initialise flags for tracking special variable usage */
  76.         for(i = 0; i < 0x100; i++)
  77.                 varused[i] = 0;
  78.         needall = cnvused = 0;
  79.         for(i = 0; i < nplanes; ++i){
  80. //char s[100];sprintf(s,"expr[%d]=%#x",i,expr[i]);dbg(s);
  81.                 if( tree[i] || (tree[i] = parseexpr(expr[i])) )
  82.                         checkvars(tree[i],varused,&cnvused,&needall,&state_changing_funcs_used);
  83.                 else
  84.                         break;
  85.         }
  86.         needinput = ( cnvused || needall
  87.                 || varused['r'] || varused['g'] || varused['b'] || varused['a']
  88.                 || varused['i'] || varused['u'] || varused['v'] || varused['c'] );
  89.  
  90.         /*
  91.          * Workaround for PSPI for GIMP:
  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,
  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
  96.          * needall=1 to disable chunked processing.
  97.          */
  98.         if (pb->hostSig == HOSTSIG_GIMP) needall = true;
  99.  
  100.         evalinit();
  101.         return i==nplanes; /* all required expressions parse OK */
  102. }
  103.  
  104. void evalpixel(unsigned char *outp,unsigned char *inp){
  105.         int f,k;
  106.  
  107.         if(needinput){
  108.                 var['r'] = inp[0];
  109.                 var['g'] = nplanes > 1 ? inp[1] : 0;
  110.                 var['b'] = nplanes > 2 ? inp[2] : 0;
  111.                 var['a'] = nplanes > 3 ? inp[3] : 0;
  112.  
  113. #ifdef YUV_FILTER_FACTORY
  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]
  116.                 if(varused['v']) var['v'] = (( 78L*var['r'])+(-65L*var['g'])+(-13L*var['b']))/256; // range: [-77..77]
  117. #else
  118.                 // These formulas are more accurate, e.g. pure white has now i=255 instead of 254
  119.  
  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]
  122.  
  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].
  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]
  127.  
  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].
  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]
  132. #endif
  133.  
  134.         }
  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']);
  137.  
  138.         for(k = 0; k < nplanes; ++k){
  139.                 if(needinput)
  140.                         var['c'] = inp[k];
  141.                 var['z'] = k;
  142.                 var['p'] = k; // undocumented alias of z
  143.                 f = eval(tree[k]);
  144.                 if (outp)
  145.                         outp[k] = f<0 ? 0 : (f>255 ? 255 : f); // clamp channel value to 0-255
  146.         }
  147. }
  148.  
  149. /* Zoom and filter image.
  150.  * Parameters:  pb          - Photoshop Filter parameter block
  151.  *              progress    - whether to use Photoshop's progress bar
  152.  *                            (not appropriate during preview)
  153.  *              filterRect  - rectangle (within pb->inRect)
  154.  *                            of area to be filtered. This may not correspond
  155.  *                            to pb->filterRect, it may be just a piece.
  156.  *              outPiece    - rectangle defining scaled output buffer.
  157.  *                            In case of zoomed preview, this is physically
  158.  *                            scaled FROM filterRect (or equal to filterRect
  159.  *                            for unscaled 1:1 filtering).
  160.  *              outData     - pointer to output data buffer
  161.  *              outRowBytes - row stride of output data buffer
  162.  *              zoom        - pixel scale factor (both horiz & vert)
  163.  *                            e.g. 2.0 means 1 output pixel per 2 input pixels.
  164.  */
  165.  
  166. //#define PROCESS_SCALED_GAP_DEBUG 1
  167.  
  168. OSErr process_scaled_bigdoc(FilterRecordPtr pb, Boolean progress,
  169.                           VRect filterPiece, VRect outPiece,
  170.                           void *outData, long outRowBytes, double zoom){
  171.         unsigned char *inrow,*outrow,*outp;
  172.         int j,i;
  173.         int64_t t, ticks = TICKCOUNT();
  174.         double x,y,k;
  175.  
  176.         #ifdef PROCESS_SCALED_GAP_DEBUG
  177.         char s[0x200];
  178.         int last_good_x, last_good_y;
  179.         last_good_y = -1;
  180.         #endif
  181.  
  182.         VRect filterRect;
  183.         VRect inRect;
  184.  
  185.         if (HAS_BIG_DOC(pb)) {
  186.                 filterRect = BIGDOC_FILTER_RECT(pb);
  187.                 inRect = BIGDOC_IN_RECT(pb);
  188.         } else {
  189.                 filterRect.bottom = FILTER_RECT(pb).bottom;
  190.                 filterRect.left = FILTER_RECT(pb).left;
  191.                 filterRect.right = FILTER_RECT(pb).right;
  192.                 filterRect.top = FILTER_RECT(pb).top;
  193.                 inRect.bottom = IN_RECT(pb).bottom;
  194.                 inRect.left = IN_RECT(pb).left;
  195.                 inRect.right = IN_RECT(pb).right;
  196.                 inRect.top = IN_RECT(pb).top;
  197.         }
  198.  
  199.         // find base pointer to selection image data
  200.         image_ptr = (unsigned char*)pb->inData
  201.                                 + (long)pb->inRowBytes*(filterRect.top - inRect.top)
  202.                                 + (long)nplanes*(filterRect.left - inRect.left);
  203.  
  204.         if (state_changing_funcs_used) {
  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) {
  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);
  209.                         #endif
  210.  
  211.                         var['y'] = (value_type)y;
  212.                         inrow = image_ptr + (long)(y)*pb->inRowBytes;
  213.  
  214.                         #ifdef PROCESS_SCALED_GAP_DEBUG
  215.                         last_good_x = -1;
  216.                         #endif
  217.  
  218.                         for (x = 0; x < (double)filterRect.right - (double)filterRect.left; ++x) {
  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);
  221.                                 #endif
  222.  
  223.                                 var['x'] = (value_type)x;
  224.                                 evalpixel(NULL,inrow + (long)(x)*nplanes);
  225.                         }
  226.  
  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); }
  229.                         #endif
  230.                 }
  231.         }
  232.  
  233.         // j indexes scaled output rows
  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 )
  236.         {
  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);
  239.                 #endif
  240.  
  241.                 var['y'] = (value_type)y;  // index of corresponding *input* row, top of selection == 0
  242.                 inrow = image_ptr + (long)y*pb->inRowBytes;
  243.  
  244.                 #ifdef PROCESS_SCALED_GAP_DEBUG
  245.                 last_good_x = -1;
  246.                 #endif
  247.  
  248.                 if (state_changing_funcs_used) {
  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) {
  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);
  253.                                 #endif
  254.  
  255.                                 var['x'] = (value_type)x;
  256.                                 evalpixel(NULL,inrow + (long)(x)*nplanes);
  257.                         }
  258.                 }
  259.  
  260.                 // i indexes scaled output columns
  261.                 for( outp = outrow, i = outPiece.left, x = (double)filterPiece.left - (double)filterRect.left ;
  262.                          i < outPiece.right ; ++i, outp += nplanes, x += zoom )
  263.                 {
  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);
  266.                         #endif
  267.  
  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 */
  270.  
  271.                         if (state_changing_funcs_used) {
  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) {
  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);
  276.                                         #endif
  277.  
  278.                                         var['x'] = (value_type)k;
  279.                                         if (var['x'] >= var['X']) break;
  280.                                         evalpixel(NULL,inrow + (long)(k)*nplanes);
  281.                                 }
  282.                         }
  283.                 }
  284.  
  285.                 if (state_changing_funcs_used) {
  286.                         // Fill gap between right border of preview-area and right border of selection/image border
  287.  
  288.                         for (x = (double)var['x']+1; x < (double)filterRect.right - (double)filterRect.left; ++x) {
  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);
  291.                                 #endif
  292.  
  293.                                 var['x'] = (value_type)x;
  294.                                 evalpixel(NULL,inrow + (long)(x)*nplanes);
  295.                         }
  296.  
  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);}
  299.                         #endif
  300.  
  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
  303.                         for (k = y+1; floor(k) < floor(y + zoom) && (j < outPiece.bottom-1); ++k) {
  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);
  306.                                 #endif
  307.  
  308.                                 var['y'] = (value_type)k;
  309.                                 if (var['y'] >= var['Y']) break;
  310.                                 inrow = image_ptr + (long)(k)*pb->inRowBytes;
  311.  
  312.                                 #ifdef PROCESS_SCALED_GAP_DEBUG
  313.                                 last_good_x = -1;
  314.                                 #endif
  315.  
  316.                                 for (x = 0; x < (double)filterRect.right - (double)filterRect.left; ++x) {
  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);
  319.                                         #endif
  320.  
  321.                                         var['x'] = (value_type)x;
  322.                                         evalpixel(NULL,inrow + (long)(x)*nplanes);
  323.                                 }
  324.  
  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);}
  327.                                 #endif
  328.                         }
  329.                 }
  330.  
  331.                 if(progress){
  332.                         if((t = TICKCOUNT()) > ticks){
  333.                                 ticks = t + TICKS_SEC/4;
  334.                                 if(pb->abortProc())
  335.                                         return userCanceledErr;
  336.                                 else
  337.                                         pb->progressProc((int)y - filterRect.top,filterRect.bottom - filterRect.top);
  338.                         }
  339.                 }
  340. #ifdef MAC_ENV
  341.                 else{
  342.                         /* to stop delays during typing of expressions,
  343.                            immediately abort preview calculation if a key or mouse has been pressed. */
  344.                         EventRecord event;
  345.                         if(EventAvail(mDownMask|keyDownMask|autoKeyMask,&event))
  346.                                 return userCanceledErr;
  347.                 }
  348. #endif
  349.         }
  350.  
  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
  353.         // preview output pixels left that could be affected by these gap evaluations.
  354.  
  355.         return noErr;
  356. }
  357.  
  358. OSErr process_scaled_olddoc(FilterRecordPtr pb, Boolean progress,
  359.         Rect filterPiece, Rect outPiece,
  360.         void* outData, long outRowBytes, double zoom) {
  361.  
  362.         VRect filterPiece32;
  363.         VRect outPiece32;
  364.  
  365.         filterPiece32.bottom = filterPiece.bottom;
  366.         filterPiece32.left = filterPiece.left;
  367.         filterPiece32.right = filterPiece.right;
  368.         filterPiece32.top = filterPiece.top;
  369.  
  370.         outPiece32.bottom = outPiece.bottom;
  371.         outPiece32.left = outPiece.left;
  372.         outPiece32.right = outPiece.right;
  373.         outPiece32.top = outPiece.top;
  374.  
  375.         return process_scaled_bigdoc(pb, progress, filterPiece32, outPiece32, outData, outRowBytes, zoom);
  376. }
  377.