home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: OtherApp / OtherApp.zip / wincam.zip / winc_src.zip / color.c next >
C/C++ Source or Header  |  1997-02-28  |  95KB  |  2,995 lines

  1. /**
  2.     This code in this module is
  3.     (c) Copyright 1996 StarDot Technologies
  4.     (c) 1996 by daniel lawton
  5.  
  6.     This color processing code is licensed for use only with the
  7.     WinCam.One digital camera developed by StarDot Technologies.
  8.     (Visit http://www.wincam.com for more information.)
  9.  
  10.     The translation from x86 assembler to C was done by Paul Fox with the
  11.     agreement of StarDot Technologies.  Errors of translation are perhaps
  12.     inevitable -- Paul takes all responsibility for such errors.
  13.  
  14.     Although StarDot Technologies provided the technical interface and
  15.     processing information used in this software, StarDot Technologies
  16.     makes no warranties nor provides any technical support regarding its
  17.     use with WinCam.One. 
  18.  
  19.     This program is free software; you can redistribute it and/or modify it
  20.     under the terms of the GNU General Public License as published by the
  21.     Free Software Foundation; either version 2 of the License, or (at your
  22.     option) any later version.
  23.  
  24.     This program is distributed in the hope that it will be useful, but
  25.     WITHOUT ANY WARRANTY; without even the implied warranty of
  26.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  27.     General Public License for more details.
  28.  
  29.     You should have received a copy of the GNU General Public License along
  30.     with this program; if not, write to the Free Software Foundation, Inc.,
  31.     675 Mass Ave, Cambridge, MA 02139, USA.
  32.  
  33.  
  34.         [ Allowing release of this code under GPL terms is, in my
  35.       opinion, very generous of the folks at StarDot.  If you
  36.       use this software, please let them know, so that they know
  37.       these efforts weren't a waste of time.  Thanks!  -pgf ]
  38.  
  39. **/
  40.  
  41. /*
  42.     If you spend much time reading this code, you'll note that some
  43.     of the C constructs look a little unnatural -- this is probably
  44.     a result of being translated from the assembly code original.  I'm
  45.     open to patches and improvements.  -pgf
  46. */
  47.  
  48. typedef unsigned char byte;
  49. #include <string.h>
  50. #include <math.h>
  51. #include "trace.h"
  52.  
  53. #include "color.h"
  54.  
  55. #ifdef THIS_IS_WHATS_IN_COLOR_H
  56. struct colordata {
  57.     int linenum;
  58.     int mode;
  59. #define COLOR_NONINTERLACED_24    0
  60. #define COLOR_INTERLACED_24 1
  61. #define GREY_NONINTERLACED_8    2
  62. #define GREY_INTERLACED_8   3
  63. #define GREY_NONINTERLACED_24    4
  64. #define GREY_INTERLACED_24  5
  65. #define RESET_LINESTATS     0x80
  66. #define GET_LINESTAT_FOR_LINE    0x81
  67.  
  68.     int bufwidth;
  69.     int bufheight;
  70.     int redlev;
  71.     int greenlev;
  72.     int bluelev;
  73.     int intensity;
  74.     int pixlimits[2];
  75.     int hazelevel;
  76.     int diflimit;
  77.     int options;
  78. #define OPT_COLOR_AVG        0x01
  79. #define OPT_COLOR_CROP        0x02
  80. #define OPT_VIGNETTE_CORRECTION 0x04
  81. #define OPT_SIMPLE_SUBTRACTION    0x08
  82. #define OPT_HORIZ_STRETCH   0x10
  83. #define OPT_COLOR_TRACING   0x20
  84. #define OPT_EDGE_CORRECTION 0x40
  85.  
  86.     byte    blacklevs[2];
  87.     byte    *input_off;
  88.     byte    *temp_off;
  89.     byte    *result_off;
  90. };
  91.  
  92. extern void sharpcolor(struct colordata *);
  93. #endif
  94.  
  95. /** these should be commented out for a running version.  **/
  96. /* #define MOIREDBG   1 */ /** shows map of internal moire removal logic  **/
  97. /* #define SHOWBAD    1 */ /** shows bad pixels as black dots.    **/
  98.  
  99. #ifdef COMMENTARY
  100. /*
  101.  
  102.  
  103.  here are some recommended defaults:
  104.     red level = 128
  105.     blue level = 128
  106.     green level = 75 (ccd is more sensitive to green.  take 59% of 128.
  107.     intensity = 336
  108.     pixlimits = 3, 6
  109.     haze = 8
  110.     diflimit = 42
  111.     options = 65h
  112.  
  113.  this routine takes in pointers to lines of pixels of color
  114.  mosiac information from the sharp lz2313b5.  it processes to make a line
  115.  which is the color information for the bottom of each set of 2 lines.
  116.  the initial data produced is "unrefined" but displayable.  it is later
  117.  refined to remove moire patterns when sufficient information becomes
  118.  available. when the data is no longer needed for moire processing on
  119.  other lines, a final intensity adjustment is made using your selection
  120.  of color cropping and options bits.
  121.  
  122.  thus you call 1 time and get an initial image line, but the final
  123.  data is available later, and you poll the program to find out if
  124.  the data is finished.    or you can subtract a fixed value from the line
  125.  you are processing to find out where the finished lines begin.
  126.  
  127.  because this routine processes each line several times, the buffers to hold
  128.  the input and output data must be valid for the minimum number of
  129.  scan lines it takes to produce the moire free data.  the number is
  130.  equal to twice the value you are using for the larger of pixlimits.
  131.  
  132.  if your program is running in flat mode, simply allocate
  133.  a full buffer for the input data (about 256k depending on how black
  134.  levels are stored) and a full buffer for the output data (755712 bytes).
  135.  you can either poll to see if a line is finished, or use the same logic
  136.  as is used when a full screen buffer is not available.
  137.  
  138.  if your program does not enough memory for a full buffer, you can
  139.  free up the input or output buffers pixlimits*2 scan lines after you call.
  140.  the final data will be available for these lines and you can recycle
  141.  the data.  for instance, if you have just passed the data for scan line
  142.  16h for the first time, and your high pixlimits value is 2,
  143.  scan line 12h is free as a result of the call.  note that if you had
  144.  passed the data for scan line 116h, 112h would be free and there would be
  145.  no effect on the scan lines from 0-0f5h.  the upper screen image is not
  146.  connected to the lower screen image.
  147.  
  148.  you can also poll the routine to find out if a scan line is free.
  149.  use funtion 81h and look for return code 03.
  150.  
  151.  because scan lines are processed several times, before calling for the
  152.  first time you must use the reset function, to signal to the program that
  153.  the data in old buffers is invalid.  if you do not do this you will
  154.  get an "overlay" effect from the last processed data, or worse yet, if
  155.  you are running in protected mode you might crash the program when
  156.  invalid addresses from the old buffers list are used.
  157.  
  158.  on return, the resulting bgr data is in the buffer specified by
  159.  result_off in 24 bit bgr format if color, 8 bit grayscale
  160.  if black and white.  your input data is not modified.    note that the
  161.  output data is processed in degrees, as surrounding lines become available.
  162.  the first pass is not free of moire patterns, the second is not final
  163.  intensity adjusted.  the third pass has complete data and the buffer
  164.  can be reused.  use function 81h to check status.
  165.  
  166.  here's a detailed description of the data structure values.
  167.  
  168.  *line number of line to be processed. 0-245 or 256-501.
  169.       not the screen display row!
  170.       add 100h for second image of interlaced.
  171.        note: although you should present all lines for processing,
  172.        it is generally understood that only about 480 of the 492
  173.        possible lines are valid. you should throw out the top
  174.        10 lines in double scan mode, 5 in single scan mode, and
  175.        also don't use the bottom 2 lines.  the ccd takes a while
  176.        to "warm up" and the bottom most line is invalid due
  177.        to the method of interleaving pixels.
  178.  
  179.        also, there is a problem when presenting bad line numbers,
  180.        and the problem seems to crash the system.  be sure to range
  181.        check your line numbers.  don't pass an out of range
  182.        line for the image type you are processing.
  183.  
  184.  
  185.  *mode or command: 0=clr noninterlaced, 1=clr interlaced (both 24 bit bgr)
  186.       2=b&w noninteraced  3=b&w interlaced (both 8 bit gray)
  187.       4=b&w noninteraced  5=b&w interlaced (both 24 bit bgr)
  188.        80h = reset color processing line statuses.
  189.          used before any color processing, not needed for
  190.          black and white.  bufheight must be valid
  191.          for the next image to be processed when this reset
  192.          call is made.  no other variables in your
  193.          structure are used with this command.
  194.        81h = return status of line specified in line number entry
  195.          only valid during color processing.   only
  196.          the line number in the structure needs to be valid
  197.          when using this command.  also, this command has no
  198.          meaning when used in black and white mode.
  199.          status is returned in the mode/command byte of
  200.          the structure:
  201.          0=line completely unprocessed
  202.          1=image present, but moire patterns still exist,
  203.            buffers must not be altered.
  204.          2=image color processed, moire patterns fixed,
  205.            final intensity is not complete.  buffers
  206.            must not be altered.
  207.          3=final data available with final intensity.
  208.            buffers (input and output) are available for
  209.            reuse.
  210.  *bufwidth = buffer (image) width in unprocessed pixels.  the output buffer
  211.      width should be the same unless stretch is enabled.  this width
  212.      is necessary because of the variable image size capability of
  213.      the camera.  for a full image it will be 512.    other possible
  214.      image sizes are: 384, 256, 170, 128, 102, 72, 64, 56, 46, 40, or
  215.      any other combination that allows alternating color pixel filters
  216.      of the required type.    when considering how to call the camera
  217.      for an image keep in mind that your image must alternate between
  218.      even and odd color filter pixels from the original 512 image,
  219.      an image that has more than 1 even or odd filter in a row cannot
  220.      be processed.    note: stretched images will be 1.25 times the
  221.      size you specify here.
  222.  *bufheight= buffer (image) height.  in cases of double scan, this is the
  223.      height of each scan. for instance, on 512x492 double scan this
  224.      height will be 246, the height of a single scan.  likewise this
  225.      height will be 246 for a 256x246 image where the vertical rows
  226.      are not doubled visually.  the 256 mode also has a 256x143
  227.      size, and in this case the output data is displayed twice
  228.      vertically in order to acheive the correct aspect ratio.  the
  229.      condition of the displayed data has no bearing on what is
  230.      reported here, you report the actual number of scan lines you
  231.      will receive from the camera, regardless of whether you intend
  232.      to crop off top or bottom lines or intend to display each row
  233.      twice.  other possible buffer heights are: 164, 123, 98, 82,
  234.      70, 61, 54, 42, 37, 27, 22, and 19.  others may be possible,
  235.      but you must alternate between even and odd numbered rows from
  236.      the original 246 rows of pixel information.
  237.  
  238.  *redlev = final red level.   128 = 100%.  0-256. default: 128
  239.     note: red and blue should counter balance each other
  240.     in most cases.    if you subtract 16 from red, add it to blue.
  241.  *greenlev = final green level. 128=100%.  recommended default is 75.  it's
  242.     interesting to note that the ccd is more sensitive to green
  243.     and that's why we have to adjust it down.
  244.     [ i've modified the code to do the 128-->75 conversion.  so now
  245.     the "recommended default is 128, just like for red and blue.  -pgf ]
  246.  *bluelev = final blue level.  128 = 100%.  0-256. default: 128
  247.     note: red and blue should counter balance each other
  248.     in most cases.    if you subtract 16 from red, add it to blue.
  249.  *intensity level for output. 128 gives 100%.  you can use from 0-4096
  250.  *pixlimits are the limits in distance (in pixels) to average colors together
  251.     to make the final color.  the first byte is the low limit
  252.     (the least averaging that will take place) and the second is the
  253.     high limit.  a value of 0 means no averaging.
  254.  
  255.     a high number greatly reduces moire patterns, but
  256.     creates a magenta smear on the picture.
  257.  
  258.     values for pixlimits are 0-10.  3 for the low and 8 for the high
  259.     is the recommended value.  to disable any color smoothing
  260.     (as in astronomical applications), set both to 0.
  261.  
  262.     note: the size of pixlimits is tied to the size of the temporary
  263.     output data buffers you provide in your entry structure. you must
  264.     have at least (pixlimits high)*2 buffers of bufwidth*3 bytes.
  265.     you can have more, but not less. if stretch is active, your buffer
  266.     must be bufwidth*1.25*3 bytes.
  267.  
  268.     you can reduce the memory required by using a lower
  269.     value of pixlimits if desired, but if memory is not a problem, just
  270.     alot the max of 20 buffers (for pixlimits 10) and use it with any
  271.     lower pixlimits value.
  272.     note: you cannot change pixlimits during processing of
  273.     an image.  it must remain consistent.  also, going above
  274.     10 would not work with the method used here to trick
  275.     the checking of flag bytes in the routine findline2.
  276.  *hazelevel is the value to subtract from every final r, g, & b value.
  277.     8 suggested.
  278.     note: it is suggested that if your software adjust the intensity
  279.     according to the haze.  this is needed so that the picture doesn't
  280.     get darker or lighter with a haze change.  unfortunately,
  281.     to do this you have to make an assumption about the image.
  282.     you have to assume what the average overall value of the
  283.     image is, interms of rgb intensity.  the example below shows
  284.     how to adjust the haze value based on the assumption that the
  285.     final output range is close to 0-128:
  286.  
  287.     intensity = (requested intensity) * 128/(128-haze)
  288.  
  289.  *diflimit is an internal calculation value.  when differences between
  290.     adjacent color filter types exceed this value the larger of the
  291.     pixlimit values is used to make a color.  below this value the
  292.     smaller pixlimit value is used.  the value is a 0-128 percent.
  293.     42 suggested.
  294.  
  295.  *options is a word of flag bits.
  296.     bit 0001 set if input pixel averaging is enabled.  in this
  297.         mode, 4 adjacent pixels of the same color filter type
  298.         are averaged before color calculations are made. there
  299.         is no effect on intensity information.  this
  300.         should be the default.
  301.     bit 0002 set if color cropping enabled.  in this mode,
  302.         when an rgb component goes over 255 the entire color
  303.         intensity is adjusted to make colors stay relatively
  304.         the same as calculated.  when off, just the offending
  305.         color is cropped, making the actual final color be in
  306.         error, but allowing brighter colors.
  307.     bit 0004 set if vignette correction is enabled.  this
  308.         flattens the brightness response of the image which
  309.         would normally be brighter in the center by almost
  310.         2.5 times as opposed to the corners of the screen.
  311.     bit 0008 clear if mathematical calculations should be used
  312.         to generate the color information.
  313.         set if the simple subtraction method the ccd
  314.         was designed for is desired.
  315.     bit 0010 set if output should be mathematically stretched.
  316.         a 512 wide buffer will stretch to 640.  other
  317.         sizes will stretch to the integer of input*1.25.
  318.         this stretch uses information available only
  319.         internally and will likely be of a better quality
  320.         than a stretch done by windows or a graphics program.
  321.  
  322.         here are stretch sizes for specific input sizes:
  323.  
  324.             512 stretches to 640
  325.             384 stretches to 480
  326.             306 stretches to 382
  327.             256 stretches to 320
  328.             170 stretches to 212
  329.             128 stretches to 160
  330.             102 stretches to 127
  331.             72 stretches to 90
  332.             64 stretches to 80
  333.             56 stretches to 70
  334.             52 stretches to 65
  335.             46 stretches to 57
  336.             40 stretches to 50
  337.  
  338.     bit 0020 set means color tracing is on.  recommended default.
  339.         in this mode, colors averaging decisions involve
  340.         tracing out from the current point and stopping
  341.         at detectable boundries.  otherwise the area specified
  342.         by pixlimit is used.
  343.  
  344.     bit 0040 set means edge correction.  in color mode this is
  345.         primarily right side blue reduction, but the leftmost
  346.         pixels are also adjusted.  the ccd seems
  347.         to have a higher blue sensitivity on the sides of
  348.         the mask.  and the leading pixel seems to be
  349.         darker in differing amounts for the rgb levels.
  350.         when this bit is set, these values are adjusted.
  351.         bit set is the recommended default.
  352.  
  353.         in black and white mode, the leftmost pixel is
  354.         brightened.
  355.  
  356.     *** clear unused bits in this options word***
  357.  
  358.  *black levels are the averages of the leading and trailing black levels
  359.     sent by the camera.  the first byte is the average of the leading,
  360.     the second the average of the trailing.
  361.  *input_off is the 32 bit offset of the buffer holding the bufwidth byte data
  362.     for the current. this offset must be suitable for indexing to
  363.     fetch the other lines.  they must be in a position that is relative
  364.     to the central line in the same manner as they were fetched from
  365.     the ccd.  this means that you need a contiguous buffer
  366.     to hold both the lower scan image and the upper scan image.
  367.  
  368.     in color mode, 3 lines above and 3 below must have valid data at the
  369.     time of the call.  for instance, loading your value into inp, it must
  370.     be valid to address the extreme edge line as [inp-512*3] (if your
  371.     bufwidth is 512), and [inp+512].  this must be true for the entire
  372.     input line width of bufwidth pixels.
  373.  
  374.     in black and white mode interlaced, only this offset is used,
  375.     other lines are not accessed.
  376.  
  377.  *temp_off is the offset of temporary buffers to hold intermediate output
  378.     data results.  you must point this to a block of memory that
  379.     is large enough for your maximum supported pixlimits+1 times
  380.     bufwidth*3*2. if you support pixlimits of 10, and a bufwidth of
  381.     512,  this amounts to 11*512*3*2 or 33792 bytes.  stretch doesn't
  382.     affect this buffer size, it's for intermediate (pre-stretch)
  383.     calculations.
  384.  
  385.     you don't change this offset with each new row, just point to the
  386.     base of this buffer.  example buffer sizes:
  387.  
  388.         max pixlimits   memory required
  389.           1        6144
  390.           4        15360
  391.           8        27648
  392.          10        33792
  393.  
  394.         note: this buffer is not used in black and white mode.
  395.  *result_off is the offset of the bufwidth*3 byte buffer to hold results.
  396.     24 bit bgr or 8 bit b&w. if b&w, output is only bufwidth bytes.
  397.     no indexing is done to fetch lines above or below this buffer,
  398.     the buffer can be an independant buffer in any memory location.
  399.     the only requirement is that it remain valid for pixlimits*2
  400.     scan lines after it has been processed.  it takes this long to
  401.     complete the final information.  the upper and lower images in
  402.     double scan or non-interleaved mode are independant, thus the
  403.     buffers for each must remain for pixlimits*2 scan lines of that
  404.     image half, regareless of the processing position of the other.
  405.     also note that if stretch is active your buffer must be
  406.     bufwidth*1.25*3 bytes in length (or *1 if b&w).
  407.  
  408. */
  409. #endif /* COMMENTARY */
  410.  
  411. /** some defines used by the program to determine the type
  412.  * of color filter used. **/
  413. #define CYG    4
  414. #define CYMG    5
  415. #define YEG    6
  416. #define YEMG    7
  417.  
  418.  
  419. /* these 3 defines determine the order of the output color bytes */
  420. #ifdef ORIGINAL_TRANSLATION
  421. #define BLUE    0   /* bgr output */
  422. #define GREEN    1
  423. #define RED    2
  424. #else
  425. #define RED    0   /* rgb output */
  426. #define GREEN    1
  427. #define BLUE    2
  428. #endif
  429.  
  430.  
  431. byte lowplimit;
  432. byte highplimit;
  433.  
  434.  
  435.  
  436. int opts;   /** user's options flag word **/
  437.  
  438. int greenfix;    /** greenlev (green) base 128 percent **/
  439. int redfix; /** red fix from redlev **/
  440. int bluefix;    /** blue fix from bluelev **/
  441.  
  442. #if NEEDED
  443. int graygreen;
  444. int grayred;
  445. int grayblue;
  446. #endif
  447.  
  448. long bwidth;    /** buffer width as passed by caller **/
  449. long bheight;    /** and the height **/
  450.  
  451.  
  452.  
  453. byte centralbw; /** black and white for pixel being processed. **/
  454. byte centraldev; /** deviation allowed in b&w from centralbw **/
  455.  
  456. byte moirefound; /** to flag a pixel as having moire patterns. **/
  457.      /** (only bit 1 set if moire trouble) **/
  458.  
  459. #define FLAGMOIRE   0x01
  460. #define UNDERFLO -7
  461.  
  462. byte *tempoff;    /** for temporary output data pointers **/
  463.  
  464.  
  465. long runningred, runninggreen, runningblue; /** for adjustments to color **/
  466.  
  467. long runningcount; /** count of samples in average for averagearea **/
  468.  
  469.  
  470. /** note:  surrounding the valid linestats bytes are values of 02.  these
  471.  * flag values fake out the routines that check if lines are surrounded by
  472.  * valid data.    by marking them done and valid and free of moire patterns,
  473.  * the logic to free up lines has free access at the ends without range
  474.  * checking.  the logic to remove moire also gets fooled, and the actual
  475.  * routine that does it does some range checking before it looks at the
  476.  * lines of information.  **/
  477.  
  478. byte statsbase[10 + 246 + 10 + 246 + 10];
  479. byte *linestats = &statsbase[10];
  480.  
  481. /** the linestats values are as follows: 
  482.  *   0 = nothing in the buffer. 
  483.  *   1 = preliminary info, not final moire adjusted. 
  484.  *   2 = final moire adjusted , but not intensity or color balance adjusted. 
  485.  *   3 = completely done data, and it's not surrounded by any lines which 
  486.  *     will need to examine it.  it's been intensity adjusted according 
  487.  *     to the user's options. **/
  488. #define LS_NOTHING  0
  489. #define LS_PRELIM   1
  490. #define LS_ALMOST   2
  491. #define LS_DONE     3
  492.  
  493. /** offset of original data for central line of each color line. **/
  494. byte *input_offs[512];
  495.  
  496. byte blacks[512];   /** black adjustment for each line **/
  497.  
  498. byte *out_offs[512]; /** offset of output data for each line **/
  499.  
  500. byte tracebufs[512*42]; /** trace buffers for color mode. **/
  501.  
  502. /* prototypes */
  503. void color_interlaced(struct colordata *cdp);
  504. void grey_interlaced(struct colordata *cdp);
  505. byte grey_pix(struct colordata *, int, int, byte *);
  506. void simplergb(void);
  507. int adjustcolor(void);
  508. int findline(int bank, int ls_level);
  509. void moirerow(struct colordata *, int);
  510. void moverow(int);
  511. int grey_vignettesub(int, int, int);
  512. void averagearea(int line, int col);
  513. void vignettesub(int line, int col);
  514. int goodaverage(int, int, int);
  515. int boundryaverage(int, int, int);
  516. void allaverage(int, int, int);
  517. void clearaverage(void);
  518. void next_all_average(int line, int col, int searchlimit);
  519. void continue_all_average(int col, int searchlimit, byte *tr_off, byte *brg_p);
  520. int next_boundry_average(int line, int col, int searchlimit);
  521. int continue_boundry_average(int col, int searchlimit, byte *tr_off, byte *brg_p);
  522. int next_good_average(int line, int col, int searchlimit);
  523. int continue_good_average(int col, int searchlimit, byte *tr_off, byte *brg_p);
  524. void fixintensity(int, int);
  525. int bluesub(int, int, int, int, int);
  526. int redsub(int, int, int, int, int);
  527. int greensub(int, int, int, int, int);
  528. int g_cymg_yeg_yemg(int, int, int, int);
  529. int g_cyg_cymg_yeg(int, int, int, int);
  530. int g_cyg_yeg_yemg(int, int, int, int);
  531. int g_cyg_cymg_yemg(int, int, int, int);
  532. int r_cymg_yeg_yemg(int, int, int, int);
  533. int r_cyg_cymg_yeg(int, int, int, int);
  534. int r_cyg_yeg_yemg(int, int, int, int);
  535. int r_cyg_cymg_yemg(int, int, int, int);
  536. int b_cymg_yeg_yemg(int, int, int, int);
  537. int b_cyg_cymg_yeg(int, int, int, int);
  538. int b_cyg_yeg_yemg(int, int, int, int);
  539. int b_cyg_cymg_yemg(int, int, int, int);
  540.  
  541. #ifdef    MOIREDBG 
  542. #define MOIREDBGSET(r,b,g)  {
  543.     runningred = r * 255; \
  544.     runningblue = b * 255; \
  545.     runninggreen = g * 255; \
  546.     }
  547. #else
  548. #define MOIREDBGSET(r,b,g)
  549. #endif
  550. /** compare cl and ch and decide if they are too different and thus an
  551. * indication of an edge in the image.  return false if edge suspected. **/
  552. inline int
  553. checkedge(byte ch, byte cl, int dlimit)
  554. {
  555.     return ((cl * dlimit)/128) > abs(cl - ch);
  556. }
  557.  
  558. /** adjust for blacklevel, but don't underflow */
  559. inline byte 
  560. bfix(byte p, int bl)
  561. {
  562.     int np = p - bl;
  563.     if (np < 0)
  564.     return 0;
  565.     return (byte)np;
  566. }
  567.  
  568. /** do a safe rounded division */
  569. inline int rdiv(int n, int d)
  570. {
  571.     if (d) /* don't divide by zero */
  572.     return (n + (d/2)) / d;   /* add d/2 to force rounding */
  573.     else
  574.     return n;
  575. }
  576.  
  577. /** find the absolute value of an integer **/
  578. inline int absolute(int i)
  579. {
  580.     return (i < 0) ? -i : i;
  581. }
  582.  
  583. /** this routine finds the length of the third side of triangle where the
  584. * angle between the other 2 is 90 degrees.  ax has the length of one and dx
  585. * the other.  the length of the third side is returned in ax.  **/
  586.  
  587. inline int findlength(int a, int b)
  588. {
  589. #ifdef assembler_findlength
  590. /* this is quite a bit less code than gcc generates -- perhaps
  591.  * i should use inline assembler? */
  592. /* on the other hand, i should really use a lookup table -- i prototyped
  593.  * it, and it takes about 40% less time than the sqrt version below.  but
  594.  * the table is really big -- 32K, even if you only store the upper half
  595.  * of the 256x123 matrix of values. */
  596.     finit 
  597.     mov temp,ax 
  598.     fild    temp 
  599.     fmul    st,st(0) 
  600.  
  601.     mov temp,dx 
  602.     fild    temp 
  603.     fmul    st,st(0) 
  604.  
  605.     fadd 
  606.     fsqrt 
  607.     fistp   temp 
  608.     mov ax,temp 
  609. #else
  610. #if slightly_slower
  611.     return (int)hypot((double)a, (double)b);
  612. #else
  613.     return (int)sqrt((double)(a * a + b * b));
  614. #endif
  615. #endif
  616. }
  617.  
  618. /** this sub will take a row number and return the correct
  619. * offset in tracebufs.    these are used to hold b&w info for color
  620. * tracing.  **/
  621.  
  622. inline byte *
  623. pointtrace(int line)
  624. {
  625.     int bankbeg = line & 0xff00;
  626.     line &= 0xff;    /** get the bank offset **/
  627.     line %= 21;     /** make mod 21 **/  /* WHY 21?!?!?!  pgf */
  628.     if (bankbeg != 0) /** if upper bank, skip 21 buffers **/
  629.     line += 21;
  630.     return &tracebufs[line * 512];
  631. }
  632.  
  633.  
  634. void
  635. reset_linestats(int bh)
  636. {
  637.     /**    clear the line stats, leave full of LS_ALMOST's **/
  638.     memset(statsbase, LS_ALMOST, sizeof(statsbase));
  639.  
  640.     /**    clear it for the specified height **/
  641.     memset(linestats, LS_NOTHING, bh);
  642.  
  643.     /** pad rest with a number that allows color processing but
  644.     * doesn't allow line to be transported (line done) **/
  645.     memset(&linestats[bh], LS_DONE, 256-bh);
  646.  
  647.     /**    clear the line stats high image **/
  648.     memset(&linestats[256], LS_NOTHING, bh);
  649.  
  650.     /**    now pad the rest with 3's (line done) **/
  651.     memset(&linestats[256+bh], LS_DONE, 256-bh);
  652. }
  653.  
  654. void
  655. sharpcolor( struct colordata *cdp )   /* the user's parameter structure */
  656. {
  657.  
  658.     if (cdp->mode == RESET_LINESTATS) {
  659.     /** reset color processing line status bytes. **/
  660.     reset_linestats(cdp->bufheight);
  661.     return;
  662.     }
  663.  
  664.     if (cdp->mode == GET_LINESTAT_FOR_LINE) {
  665.     /** return status of color processed lines. **/
  666.     cdp->mode = linestats[cdp->linenum];
  667.     return;
  668.     }
  669.  
  670.  
  671.     TRACE("k", __FILE__ ": sharpcolor: imageline %d, inp %p, outp %p\n",
  672.     cdp->linenum, cdp->input_off, cdp->result_off);
  673.  
  674.     /** get common stuff **/
  675.     opts = cdp->options;
  676. #ifdef SHOWBAD
  677.     opts &= ~(OPT_EDGE_CORRECTION |
  678.       OPT_COLOR_TRACING |
  679.       OPT_VIGNETTE_CORRECTION |
  680.       OPT_COLOR_AVG);
  681. #endif
  682.  
  683. #ifdef SHOWBAD
  684.     lowplimit = highplimit = 0;
  685. #else
  686.     lowplimit = cdp->pixlimits[0];
  687.     highplimit = cdp->pixlimits[1];
  688. #endif
  689.  
  690.     /** get the buffer width **/
  691.     bwidth = cdp->bufwidth;
  692.     if (bwidth == 0 || bwidth > 512)
  693.     bwidth = 512;
  694.  
  695.     bheight = cdp->bufheight;
  696.     if (bheight == 0 || bheight > 246)
  697.     bheight = 246;
  698.  
  699.     /** go to the appropriate mode for this data or execute the
  700.     * desired command.    **/
  701.     switch(cdp->mode) {
  702.     case GREY_INTERLACED_24:
  703.     case GREY_INTERLACED_8:
  704.     grey_interlaced(cdp);
  705.     return;
  706.  
  707.     /** color interlaced. **/
  708.     case COLOR_INTERLACED_24:
  709.     /* the rest of the routine takes care of this case */
  710.     color_interlaced(cdp);
  711.     break;
  712.  
  713.     case GREY_NONINTERLACED_24:
  714.     case GREY_NONINTERLACED_8:
  715.     case COLOR_NONINTERLACED_24:
  716.     default:
  717.     /* not implemented */
  718.     return;
  719.  
  720.     }
  721. }
  722.  
  723. /** remove moire pattern possibilities for any lines which
  724. * have enough surrounding ones to be processed.  these go into
  725. * the temporary buffers because we can't change the ones 
  726. * still needed to remove moire patterns from other lines.    **/
  727. void
  728. do_other_lines(struct colordata *cdp, int line)
  729. {
  730.     int foundone;
  731.     int l;
  732.  
  733.     do {
  734.     /** set flag meaning didn't find one **/
  735.     foundone = 0;
  736.  
  737.     /** see if any need processing **/
  738.     l = findline(line & 0xff00, LS_PRELIM);
  739.     if (l >= 0) {
  740.         line = l;
  741.         moirerow(cdp, line);
  742.         foundone = 1;
  743.     }
  744.     /** and look for any fully done rows which are no longer
  745.     * needed and can have their final data moved to the output
  746.     * location.  we have to interleave this function with
  747.     * moverow so that we don't overwrite data at the very end
  748.     * of processing.  we have to free up buffers as fast as we
  749.     * fill them.  **/
  750.  
  751.     l = findline(line & 0xff00, LS_ALMOST);
  752.     if (l >= 0) {
  753.         line = l;
  754.         moverow(line);
  755.         foundone = 1;
  756.     }
  757.  
  758.     } while (foundone != 0); /** see if any were found in last pass **/
  759. }
  760.  
  761. void
  762. color_interlaced(struct colordata *cdp)
  763. {
  764.     long neg1, neg2, neg3, pos1, pos2;
  765.     byte *traceoff;
  766.     byte *outptr;   /** where to store output of color **/
  767.     byte *startout; /** copy for final adjustments **/
  768.     byte *startin;  /** copy of start pointer for final adjustments **/
  769.     int col;        /** index of current pixel **/
  770.     byte *inp;        /** pointer to current pixel **/
  771.     int centraltype; /** type of pixel we are on **/
  772.     int imageline = cdp->linenum;
  773.     int line_in_bank = imageline & 0xff;
  774.     int bl; /** black level we are subtracting  **/
  775.  
  776.     /** when we fetch pixels, we put them into the variables that are laid
  777.      ** out like this: **/
  778. #if ORIG
  779.     int
  780.     l2top2pix,      l1top2pix,    top2pix,    r1top2pix,      r2top2pix,    r3top2pix,
  781.     l2top1pix,      l1top1pix,    top1pix,    r1top1pix,      r2top1pix,    r3top1pix,
  782.     l2top0pix,      l1top0pix,    top0pix,    r1top0pix,      r2top0pix,    r3top0pix,
  783.     l2centpix,      l1centpix,    centpix,    r1centpix,      r2centpix,    r3centpix,
  784.     l2bot0pix,      l1bot0pix,    bot0pix,    r1bot0pix,      r2bot0pix,    r3bot0pix,
  785.     l2bot1pix,      l1bot1pix,    bot1pix,    r1bot1pix,      r2bot1pix,    r3bot1pix;
  786. #else
  787. #if LATER_MAYBE
  788. #define L1TOP1PIX   0
  789. #define TOP1PIX     1
  790. #define R1TOP1PIX   2
  791. #define R2TOP1PIX   3
  792. #define L1TOP0PIX   4
  793. #define TOP0PIX     5
  794. #define R1TOP0PIX   6
  795. #define R2TOP0PIX   7
  796. #define L1CENTPIX   8
  797. #define CENTPIX     9
  798. #define R1CENTPIX   10
  799. #define R2CENTPIX   11
  800. #define L1BOT0PIX   12
  801. #define BOT0PIX     13
  802. #define R1BOT0PIX   14
  803. #define R2BOT0PIX   15
  804.     int r[16];
  805.     
  806. #define l1top1pix r[L1TOP1PIX]
  807. #define top1pix   r[TOP1PIX  ]
  808. #define r1top1pix r[R1TOP1PIX]
  809. #define r2top1pix r[R2TOP1PIX]
  810. #define l1top0pix r[L1TOP0PIX]
  811. #define top0pix   r[TOP0PIX  ]
  812. #define r1top0pix r[R1TOP0PIX]
  813. #define r2top0pix r[R2TOP0PIX]
  814. #define l1centpix r[L1CENTPIX]
  815. #define centpix   r[CENTPIX  ]
  816. #define r1centpix r[R1CENTPIX]
  817. #define r2centpix r[R2CENTPIX]
  818. #define l1bot0pix r[L1BOT0PIX]
  819. #define bot0pix   r[BOT0PIX  ]
  820. #define r1bot0pix r[R1BOT0PIX]
  821. #define r2bot0pix r[R2BOT0PIX]
  822.  
  823. #else
  824.     int
  825.     l1top1pix,      top1pix,    r1top1pix,    r2top1pix,
  826.     l1top0pix,      top0pix,    r1top0pix,    r2top0pix,
  827.     l1centpix,      centpix,    r1centpix,    r2centpix,
  828.     l1bot0pix,      bot0pix,    r1bot0pix,    r2bot0pix;
  829. #endif
  830.  
  831. #endif
  832.  
  833.     int centpix2; /** this is a copy of central pix for color avrg. **/
  834.     int entrycymg, entryyeg, entryyemg, entrycyg;
  835.  
  836.     /** get passed in black levels, average 'em **/
  837.     bl = (cdp->blacklevs[0] + cdp->blacklevs[1]) / 2;
  838.  
  839.  
  840.     /**     get green level **/
  841.     /**     adjust this way, but process for 128 **/
  842.  
  843.     /*
  844.      * greenfix needs to be 59% of the base values for red and blue.  this
  845.      * adjustment used to be left to the user, but i've moved it in here
  846.      * so the user can use 128 as the base (100%) value for all three
  847.      * colors.
  848.      */
  849.     greenfix = (75 * cdp->greenlev) / 128;
  850. #if NEEDED
  851.     /** while setting the adjustment percents **/
  852.     /** we need to make something that will **/
  853.     /** balance out to gray after these are **/
  854.     /** used.  we fill in bad pixels with it. **/
  855.     graygreen = (3*128) / ((greenfix) ? greenfix : 1);
  856. #endif
  857.  
  858.  
  859.     /** 384 = 3*128.  we want the final **/
  860.     /** gray to come out to intensity 3. **/
  861.     /** intensity 1 would be better; bit **/
  862.     /** 01 is set in the blue to mark bad. **/
  863.     redfix = cdp->redlev;
  864. #if NEEDED
  865.     grayred = (3*128) / ((redfix) ? redfix : 1);
  866. #endif
  867.  
  868.  
  869.     /** but we can't use 01 because a slight **/
  870.     /** rounding error might make some = 0. **/
  871.     /** so 3 is next odd number up. **/
  872.     bluefix = cdp->bluelev;
  873. #if NEEDED
  874.     grayblue = (3*128) / ((bluefix) ? bluefix : 1);
  875. #endif
  876.  
  877.     /** save output pointer **/
  878.     outptr = cdp->result_off;
  879.     /** and save a copy **/
  880.     startout = outptr;
  881.  
  882.     /** get offset of temporary buffers **/
  883.     tempoff = cdp->temp_off;
  884.  
  885.     /** get center line offset **/
  886.     /** save offset of starting data **/
  887.     startin = cdp->input_off;
  888.  
  889.  
  890.     /** set pixel being done. **/
  891.     col = 0;
  892.  
  893.     /** make indexes to fetch lines above **/
  894.     neg1 = -bwidth;
  895.     neg2 = -(2 * bwidth);
  896.     neg3 = -(3 * bwidth);
  897.  
  898.     /** if closer than 3, just go 1 for 3 **/
  899.     if (line_in_bank < 3)
  900.     neg3 = neg1;
  901.  
  902.     /** if closer than 2, use 0 for 2 back **/
  903.     if (line_in_bank < 2)
  904.     neg2 = 0;
  905.  
  906.     /** in this case, we have to go down, not up. **/
  907.     if (line_in_bank < 1)
  908.     neg1 = neg3 = bwidth;
  909.  
  910.     /** make index to go 1 line below **/
  911.     pos1 = bwidth;
  912.     pos2 = bwidth * 2;
  913.  
  914.     /** see if none below **/
  915.     if (line_in_bank == 245) {
  916.     pos1 = -pos1; /** if can't go 1 below, go 1 above. **/
  917.     pos2 = 0; /** and point 2 below to 0 **/
  918.     }
  919.  
  920.     /** see if only 1 below **/
  921.     if (line_in_bank == 244)
  922.     pos2 = 0; /** if so, 2 below becomes zero. **/
  923.  
  924.     /** set up the b&w trace buffer **/
  925.     traceoff = pointtrace(imageline);
  926.  
  927.     /** main pixel loop **/
  928.     /** for starters, we'll need specific pixels no matter which color
  929.     * cell we are on.  also, they have to be gotten differently
  930.     * depending on where we are in the line (start, middle, end).  we
  931.     * put these into variables.  we have to watch out for the ends of
  932.     * the line where we can't get the pixels we would like to have
  933.     * relative to the center pixel **/
  934.  
  935.     /** inp has the line we are on. outptr has the output.  **/
  936.     inp = startin;
  937.     do {
  938.     /** get central pixel **/
  939.     centpix = bfix(inp[0], bl);
  940.  
  941.     /** get pixel 2 above one we are on **/
  942.     top1pix = bfix(inp[neg2], bl);
  943.  
  944.     /** get pixel 1 above one we are on **/
  945.     top0pix = bfix(inp[neg1], bl);
  946.  
  947.     /** get pixel 1 below one we are on **/
  948.     bot0pix = bfix(inp[pos1], bl);
  949.  
  950.     /** if we are at the end of the line and have to be careful
  951.     * how we fetch pixels to the right of the central one. 
  952.     * **/
  953.  
  954.     if (col >= bwidth - 3) {
  955.         if (col == bwidth - 3) {
  956.         r1centpix = bfix(inp[1], bl);
  957.         r2centpix = bfix(inp[2], bl);
  958.         l1centpix = bfix(inp[-1], bl);
  959.  
  960.         r1top1pix = bfix(inp[neg2+1], bl);
  961.         r2top1pix = bfix(inp[neg2+2], bl);
  962.         l1top1pix = bfix(inp[neg2-1], bl);
  963.  
  964.         r1top0pix = bfix(inp[neg1+1], bl);
  965.         r2top0pix = bfix(inp[neg1+2], bl);
  966.         l1top0pix = bfix(inp[neg1-1], bl);
  967.  
  968.         r1bot0pix = bfix(inp[pos1+1], bl);
  969.         r2bot0pix = bfix(inp[pos1+2], bl);
  970.         l1bot0pix = bfix(inp[pos1-1], bl);
  971.  
  972.         } else if (col == bwidth - 2) {
  973.  
  974.         r1centpix = bfix(inp[1    ], bl);
  975.         r2centpix = centpix;
  976.         l1centpix = bfix(inp[ -1 ], bl);
  977.  
  978.         r1top1pix = bfix(inp[neg2+1  ], bl);
  979.         r2top1pix = top1pix;
  980.         l1top1pix = bfix(inp[neg2-1  ], bl);
  981.  
  982.         r1top0pix = bfix(inp[neg1+1  ], bl);
  983.         r2top0pix = top0pix;
  984.         l1top0pix = bfix(inp[neg1-1  ], bl);
  985.  
  986.         r1bot0pix = bfix(inp[pos1+1  ], bl);
  987.         r2bot0pix = bot0pix;
  988.         l1bot0pix = bfix(inp[pos1-1  ], bl);
  989.  
  990.         } else /* if (col == bwidth - 1) */ {
  991.         r1centpix = bfix(inp[-1  ], bl);
  992.         l1centpix = bfix(inp[-1  ], bl);
  993.         r2centpix = centpix;
  994.  
  995.         r1top1pix = bfix(inp[neg2-1  ], bl);
  996.         l1top1pix = bfix(inp[neg2-1  ], bl);
  997.         r2top1pix = top1pix;
  998.  
  999.         r1top0pix = bfix(inp[ neg1-1 ], bl);
  1000.         l1top0pix = bfix(inp[ neg1-1 ], bl);
  1001.         r2top0pix = top0pix;
  1002.  
  1003.         l1bot0pix = bfix(inp[pos1-1  ], bl);
  1004.         r1bot0pix = bfix(inp[pos1-1  ], bl);
  1005.         r2bot0pix = bot0pix;
  1006.  
  1007.         }
  1008.     } else    if (col <= 1) {
  1009.         if (col == 0) {
  1010.         r1centpix = l1centpix = bfix(inp[1 ], bl);
  1011.         r2centpix = bfix(inp[2 ], bl);
  1012.  
  1013.         r1top1pix = l1top1pix = bfix(inp[neg2+1  ], bl);
  1014.         r2top1pix = bfix(inp[neg2+2  ], bl);
  1015.  
  1016.         r1top0pix = l1top0pix = bfix(inp[neg1+1  ], bl);
  1017.         r2top0pix = bfix(inp[neg1+2  ], bl);
  1018.  
  1019.         r1bot0pix = l1bot0pix = bfix(inp[pos1+1  ], bl);
  1020.         r2bot0pix = bfix(inp[pos1+2  ], bl);
  1021.  
  1022.         } else { /* must be 1 */
  1023.         r1centpix = bfix(inp[1    ], bl);
  1024.         l1centpix = bfix(inp[-1  ], bl);
  1025.         r2centpix = bfix(inp[2    ], bl);
  1026.  
  1027.         r1top1pix = bfix(inp[neg2+1  ], bl);
  1028.         l1top1pix = bfix(inp[neg2-1], bl);
  1029.         r2top1pix = bfix(inp[neg2+2  ], bl);
  1030.  
  1031.         r1top0pix = bfix(inp[neg1+1  ], bl);
  1032.         l1top0pix = bfix(inp[neg1-1  ], bl);
  1033.         r2top0pix = bfix(inp[neg1+2  ], bl);
  1034.  
  1035.         r1bot0pix = bfix(inp[pos1+1  ], bl);
  1036.         l1bot0pix = bfix(inp[pos1-1  ], bl);
  1037.         r2bot0pix = bfix(inp[pos1+2  ], bl);
  1038.  
  1039.         }
  1040.     } else {
  1041.  
  1042.         /** in the middle of the line we don't have
  1043.         * to worry about were to index.  **/
  1044.  
  1045.         r1centpix = bfix(inp[1    ], bl);
  1046.         r2centpix = bfix(inp[2    ], bl);
  1047.         l1centpix = bfix(inp[-1  ], bl);
  1048.  
  1049.         r1top1pix = bfix(inp[neg2+1  ], bl);
  1050.         r2top1pix = bfix(inp[neg2+2  ], bl);
  1051.         l1top1pix = bfix(inp[neg2-1  ], bl);
  1052.  
  1053.         r1top0pix = bfix(inp[neg1+1  ], bl);
  1054.         r2top0pix = bfix(inp[neg1+2  ], bl);
  1055.         l1top0pix = bfix(inp[neg1-1  ], bl);
  1056.  
  1057.         r1bot0pix = bfix(inp[pos1+1  ], bl);
  1058.         r2bot0pix = bfix(inp[pos1+2  ], bl);
  1059.         l1bot0pix = bfix(inp[pos1-1  ], bl);
  1060.     }
  1061.  
  1062.     /** we have the pixels.  analyze to see which are probably
  1063.     * on an edge and need more moire correction.  **/
  1064.  
  1065.     /** l2top2pix   l1top2pix  top2pix    r1top2pix   r2top2pix  r3top2pix  **/
  1066.     /** l2top1pix   l1top1pix  top1pix    r1top1pix   r2top1pix  r3top1pix  **/
  1067.     /** l2top0pix   l1top0pix  top0pix    r1top0pix   r2top0pix  r3top0pix  **/
  1068.     /** l2centpix   l1centpix  centpix    r1centpix   r2centpix  r3centpix  **/
  1069.     /** l2bot0pix   l1bot0pix  bot0pix    r1bot0pix   r2bot0pix  r3bot0pix  **/
  1070.     /** l2bot1pix   l1bot1pix  bot1pix    r1bot1pix   r2bot1pix  r3bot1pix  **/
  1071.  
  1072.     /** assume moire will be found. **/
  1073.     moirefound  = 1;
  1074.  
  1075.     /** here's a simple black and white check for boundries. 
  1076.     * since any 2 adjacent cells make b&w info, this should
  1077.     * catch most vertical edges.  **/
  1078.  
  1079.     /** X 0 0 X **/
  1080.     /** X 0 0 X **/
  1081.     /** X X X X **/
  1082.     if (checkedge((top0pix + r1top0pix)/2,
  1083.         (centpix + r1centpix)/2, cdp->diflimit)) {
  1084.  
  1085.         /** we passed vertically as far as intensity goes,
  1086.         * but we need some horizontal checks.  **/
  1087.  
  1088.         /**   X x x X **/
  1089.         /**   0 x 0 X **/
  1090.         /**   X X X X **/
  1091.         if (checkedge(l1centpix, r1centpix, cdp->diflimit)) {
  1092.  
  1093.         /**   X x x X **/
  1094.         /**   X 0 x 0 **/
  1095.         /**   X X X X **/
  1096.         if (checkedge(centpix, r2centpix, cdp->diflimit)) {
  1097.  
  1098.             moirefound = 0;
  1099.         }
  1100.         }
  1101.     }
  1102.     /** done fetching and checking the color filters we will use to
  1103.     * make the color info.    but before we make color, we create b&w
  1104.     * info for this pixel.    it's used for color tracing.  **/
  1105.  
  1106.     centralbw = (centpix + r1centpix)/2;
  1107.     traceoff[col] = centralbw;
  1108.  
  1109.     /** now apply pixel color averaging, if the user has selected it. 
  1110.     * since we've detected bad moire areas, we'll only do the pixel
  1111.     * color averaging on these areas.  otherwise the good pixels will
  1112.     * get averaged into potential bad ones.  **/
  1113.  
  1114.     /** l2top2pix   l1top2pix  top2pix    r1top2pix   r2top2pix  r3top2pix  **/
  1115.     /** l2top1pix   l1top1pix  top1pix    r1top1pix   r2top1pix  r3top1pix  **/
  1116.     /** l2top0pix   l1top0pix *top0pix *r1top0pix   r2top0pix  r3top0pix  **/
  1117.     /** l2centpix   l1centpix *centpix *r1centpix   r2centpix  r3centpix  **/
  1118.     /** l2bot0pix   l1bot0pix  bot0pix    r1bot0pix   r2bot0pix  r3bot0pix  **/
  1119.     /** l2bot1pix   l1bot1pix  bot1pix    r1bot1pix   r2bot1pix  r3bot1pix  **/
  1120.  
  1121.     /** make a copy in case color averaging off **/
  1122.     centpix2 = centpix;
  1123.  
  1124.     if (moirefound && (opts & OPT_COLOR_AVG)) {
  1125.  
  1126.         centpix2 = (centpix + r2centpix + top1pix + r2top1pix) / 4;
  1127.  
  1128.         r1centpix = (r1centpix + l1centpix + r1top1pix + l1top1pix) / 4;
  1129.  
  1130.         top0pix = (top0pix + r2top0pix + bot0pix + r2bot0pix) / 4;
  1131.  
  1132.         r1top0pix = (r1top0pix + l1top0pix + r1bot0pix + l1bot0pix) / 4;
  1133.     }
  1134.     /** now we fetch the info according to the type of color
  1135.     * filter the central pixel is under.  **/
  1136.  
  1137.     /** cyg  yemg cyg  yemg cyg  yemg  (yemg)-alpha(cyg)=red **/
  1138.     /** cymg yeg  cymg yeg    cymg yeg   (cymg)-beta(yeg)=blue **/
  1139.     if ((imageline & 1) == 0) {
  1140.         if ((col & 1) == 0) { /** cyg central pixel **/
  1141.         centraltype = CYG;
  1142.         entryyemg = r1centpix;
  1143.         entrycyg = centpix2;
  1144.         entrycymg = top0pix;
  1145.         entryyeg = r1top0pix;
  1146.  
  1147.         } else { /** yemg central pixel **/
  1148.         centraltype = YEMG;
  1149.         entryyemg = centpix2;
  1150.         entrycyg = r1centpix;
  1151.         entrycymg = r1top0pix;
  1152.         entryyeg = top0pix;
  1153.         }
  1154.     } else {
  1155.         if ((col & 1) == 0) { /** cymg central pixel **/
  1156.         centraltype = CYMG;
  1157.         entryyemg = r1top0pix;
  1158.         entrycyg = top0pix;
  1159.         entrycymg = centpix2;
  1160.         entryyeg = r1centpix;
  1161.         } else { /** yeg central pixel **/
  1162.         centraltype = YEG;
  1163.         entryyemg = top0pix;
  1164.         entrycyg = r1top0pix;
  1165.         entrycymg = r1centpix;
  1166.         entryyeg = centpix2;
  1167.         }
  1168.     }
  1169.  
  1170.     /** now we make colors using the surrounding pixels we have
  1171.     * set up.  **/
  1172.  
  1173.     /** at this point, we make rgb values using the following
  1174.     * in the 3-equation calculations:
  1175.     *   entrycymg, entryyeg  (blue values) 
  1176.     *   entryyemg, entrycyg  (red values) 
  1177.     *   "centpix" = pixel we are on, 
  1178.     *   "centraltype" = cymg, yeg, yemg, or cyg.
  1179.     **/
  1180.     runningblue = bluesub(entrycyg, entrycymg,
  1181.                 entryyeg, entryyemg, centraltype);
  1182.     runningred = redsub(entrycyg, entrycymg,
  1183.                 entryyeg, entryyemg, centraltype);
  1184.     runninggreen = greensub(entrycyg, entrycymg,
  1185.                 entryyeg, entryyemg, centraltype);
  1186.  
  1187.     /** now runningred=red*2, runningblue=blue*2, runninggreen=green*2 
  1188.     **/
  1189.  
  1190.     if (opts & OPT_EDGE_CORRECTION) {
  1191.         int lowfixup[5] = { 100, 105, 105, 110, 110 };
  1192.         int highfixup[5] = { 100, 100, 85, 75, 70};
  1193.         if (col <= 4) {
  1194.         runningblue = (runningblue * lowfixup[col])/128;
  1195.         } else if (col >= 507) {
  1196.         runningblue = (runningblue * highfixup[col-507])/128;
  1197.         }
  1198.         
  1199.     }
  1200.  
  1201.     /** we scale colors down below the 1 byte range rather than
  1202.     * chop them at this point.  the final results are a user
  1203.     * selectable option, but during the intermediate state we
  1204.     * must scale them down to preserve the accurate intensity
  1205.     * information for moire removal.  for instance, if we
  1206.     * chopped off the red, then when that color was applied to
  1207.     * another cell during moire removal it's final intensity
  1208.     * would be way off because chopping off the red created a
  1209.     * phony hue which cannot be correctly recalculated for
  1210.     * intensity against the color filter reading.  **/
  1211.  
  1212.     adjustcolor();
  1213.  
  1214.     /** all done making the initial color.    now store it.  but
  1215.     * we also have to create a flag to signal if the color was
  1216.     * on an edge and in need of some moire processing.  the eye
  1217.     * is less sensitive to blue, so we use the low bit of blue
  1218.     * to signal this.  **/
  1219.  
  1220.  
  1221.     /** store blue **/
  1222. #ifdef SHOWBAD
  1223.     if (moirefound) {
  1224.         runninggreen = runningblue = runningred = 0;
  1225.         outptr[BLUE] = 0;
  1226.     } else {
  1227.         outptr[BLUE] = (runningblue & 0xfe) | moirefound;
  1228.     }
  1229. #else
  1230.     outptr[BLUE] = (runningblue & 0xfe) | moirefound;
  1231. #endif
  1232.  
  1233.     /** store green **/
  1234.     outptr[GREEN] = runninggreen;
  1235.  
  1236.     /** store red **/
  1237.     outptr[RED] = runningred;
  1238.  
  1239.     outptr += 3;
  1240.  
  1241.     /** move along source **/
  1242.     inp++;
  1243.     } while (++col < bwidth);
  1244.  
  1245.     /** we've done the initial processing for this line.  save the
  1246.     * pointers to this line and flag it's status.  **/
  1247.  
  1248.     linestats[imageline] = LS_PRELIM;
  1249.     blacks[imageline] = bl;
  1250.     input_offs[imageline] = startin;
  1251.     out_offs[imageline] = startout;
  1252.  
  1253.     /** now process any lines that are or have become ready **/
  1254.     do_other_lines(cdp, imageline);
  1255.  
  1256. }
  1257.  
  1258. /** black and white interlaced.  double or single doesn't matter,
  1259. * the caller must put together the correct rows. 
  1260. *    
  1261. * for b&w processing we just add 2 adjacent pixels.  this gives
  1262. * virtually the same result for even or odd scan lines.  the only
  1263. * difference is 12/142 in the blue level.  we need to adjust the
  1264. * blue just a little to make it perfect.  to do that, we use the
  1265. * scan odd scan line from which it's possible to calculate the blue
  1266. * level.  we then take 4% of that blue level and subtract it from
  1267. * our value to make this line match the duller one. **/
  1268. void
  1269. grey_interlaced(struct colordata *cdp)
  1270. {
  1271.     byte *outp;
  1272.     byte *inp;
  1273.     int b2, b1;
  1274.     int col;
  1275.     int imageline = cdp->linenum;
  1276.  
  1277.     /** point to output **/
  1278.     outp = cdp->result_off;
  1279.     /** point to central line **/
  1280.     inp = cdp->input_off;
  1281.  
  1282.     /**     set counter for pixel being done. **/
  1283.     col = 0;
  1284.  
  1285.     /** add 2 adjacent pixels.    there's a 3.9% blue variance
  1286.      * on every other scan line but we don't do anything about
  1287.      * that for now.  */
  1288.     do {
  1289.     b1 = grey_pix(cdp, imageline, col, inp);
  1290.  
  1291.     /** b1 has a value to store, but if we are
  1292.     * stretching we have to do the stretch at each
  1293.     * multiple of 4.  the ratio is 5/4.  **/
  1294.  
  1295.     /** see if even multiple of 4, and see if stretch **/
  1296.     if ((opts & OPT_HORIZ_STRETCH) &&
  1297.         ((col % 4) == 0)) {
  1298.  
  1299.         /** but we don't for the very first **/
  1300.         if (col == 0) {
  1301.  
  1302.         /** it's the first and stretch is
  1303.         * on.  we can't average to the last
  1304.         * one, so we average to the next
  1305.         * one.    but we have to make it now. 
  1306.         * **/
  1307.  
  1308.         /** store it **/
  1309.         *outp++ = b1;
  1310.  
  1311.  
  1312.         if (cdp->mode == GREY_INTERLACED_24) {
  1313.             /** if so, that 5th needs
  1314.             * 24 bits **/
  1315.             *outp++ = b1;
  1316.             *outp++ = b1;
  1317.         }
  1318.  
  1319.         inp++;
  1320.         /** make the next **/
  1321.         b1 = grey_pix(cdp, imageline, col, inp);
  1322.  
  1323.         /** get last, average with new **/
  1324.         b1 += *(outp-1);
  1325.         b1 /= 2;
  1326.  
  1327.         /** trick code by backing up **/
  1328.         inp--;
  1329.  
  1330.         } else {
  1331.  
  1332.         /** not the first.  we can average
  1333.         * to the previous sample to
  1334.         * accomplish stretch.  */
  1335.  
  1336.         /**    get last, average with new **/
  1337.         b2 = *(outp-1);
  1338.         b2 += b1;
  1339.         b2 /= 2;
  1340.  
  1341.         /** add a 5th for every 4. **/
  1342.         *outp++ = b2;
  1343.  
  1344.         if (cdp->mode == GREY_INTERLACED_24) {
  1345.         /** if so, that 5th needs 24 bits **/
  1346.             *outp++ = b2;
  1347.             *outp++ = b2;
  1348.         }
  1349.         }
  1350.     }
  1351.  
  1352.     /** we duped if necessary, now b1 has a new sample.  **/
  1353.  
  1354.     /** store result, move output pointer **/
  1355.     *outp++ = b1;
  1356.  
  1357.     /** if so, that 5th needs 24 bits **/
  1358.     if (cdp->mode == GREY_INTERLACED_24) {
  1359.         *outp++ = b1;
  1360.         *outp++ = b1;
  1361.     }
  1362.  
  1363.     /** move along source **/
  1364.     inp++;
  1365.  
  1366.     /** go till 1 before last.  we can't add 2 at end **/
  1367.     } while (++col < bwidth-1);
  1368.  
  1369.     /** so we just dup the end one.  **/
  1370.     *outp++ = b1;
  1371.     if (cdp->mode == GREY_INTERLACED_24) {
  1372.     *outp++ = b1;
  1373.     *outp++ = b1;
  1374.     }
  1375.  
  1376. }
  1377.  
  1378. /** this sub makes a black and white pixel from [inp].    it does
  1379. * intensity and vignetting too.  it averages 2 adjacent pixels. 
  1380. * the value is returned in b1.    **/
  1381.  
  1382. byte
  1383. grey_pix(struct colordata *cdp, int imageline, int col, byte *inp)
  1384. {
  1385.     int b1, b2;
  1386.     int bl = blacks[imageline];
  1387.  
  1388.  
  1389.     /** get bytes we're examining an do black level adjustment **/
  1390.     b1 = bfix(inp[0], bl);
  1391.     b2 = bfix(inp[1], bl);
  1392.  
  1393.     /** add the two to make 2 double ones **/
  1394.     b1 += b2;
  1395.  
  1396.     /** multiply by the base 128 percentage **/
  1397.     /** but double it to match the b&w **/
  1398.     /** processing method. **/
  1399.     b1 *= cdp->intensity / 8;
  1400.     b1 /= (128/2);
  1401.  
  1402.     /** subtract haze level **/
  1403.     b1 -= cdp->hazelevel;
  1404.     if (b1 < 0)
  1405.     b1 = 0;
  1406.  
  1407.     /** do vignette processing if enabled **/
  1408.     if (opts & OPT_VIGNETTE_CORRECTION)
  1409.     b1 = grey_vignettesub(imageline, col, b1);
  1410.  
  1411.     /** is edge color correction on? **/
  1412.     if (opts & OPT_EDGE_CORRECTION) {
  1413.     /** take 190/128 of left pixel **/
  1414.     if (col == 0)
  1415.         b1 = (b1 * 190) / 128;
  1416.     }
  1417.     /** we have a value in ax, see if it overflowed into a word. **/
  1418.     if (b1 > 255)
  1419.     b1 = 255;
  1420.  
  1421.     return (byte)b1;
  1422. }
  1423.  
  1424.  
  1425.  
  1426. /* the user gave us 2*highplimit+1 extra rows in which to stroe
  1427.  * intermediate results.  pick one of them.
  1428.  */
  1429. byte *
  1430. pointtemp(int line)
  1431. {
  1432.     int row;
  1433.     int i;
  1434.     row = line & 0xff;
  1435.     i = row % (highplimit + 1);
  1436.     if (line >= 256)
  1437.     i += highplimit + 1;
  1438.  
  1439.     return &tempoff[i * 3 * bwidth];
  1440. }
  1441.  
  1442.  
  1443. /** this sub makes sure that runningred, runningblue and runninggreen are
  1444. * not above 0ffh.  if any of them is, the largest is scaled down to 0ffh
  1445. * and the rest are scaled accordingly.    **/
  1446. int
  1447. adjustcolor(void)
  1448. {
  1449.     int maxrunning;
  1450.     int factor;
  1451.  
  1452.     maxrunning = runningred;
  1453.     if (maxrunning < runningblue)
  1454.     maxrunning = runningblue;
  1455.     if (maxrunning < runninggreen)
  1456.     maxrunning = runninggreen;
  1457.     if (maxrunning < 256)
  1458.     return 0;
  1459.  
  1460.     /* figure out a safe ratio */
  1461.     factor = rdiv(255*128, maxrunning);
  1462.  
  1463.     runningred *= factor;
  1464.     runningred /= 128;
  1465.     if (runningred > 255) runningred = 255;
  1466.  
  1467.     runningblue *= factor;
  1468.     runningblue /= 128;
  1469.     if (runningblue > 255) runningblue = 255;
  1470.  
  1471.     runninggreen *= factor;
  1472.     runninggreen /= 128;
  1473.     if (runninggreen > 255) runninggreen = 255;
  1474.  
  1475.     return 1;
  1476. }
  1477.  
  1478.  
  1479.  
  1480. /** this sub looks for any rows that can be a) finished as far as moire
  1481. * pattern processing goes, or b) completely finished.  returns zero if
  1482. * none.  return -1 or the row number. **/
  1483.  
  1484. int
  1485. findline(int bank, int ls_level)
  1486. {
  1487.     int cr;
  1488.     int line = bank;    /* first line of current bank */
  1489.     int end = line + bheight;    /* last line of current bank */
  1490.     while (line < end) {
  1491.     /** check up and down for specified distance.  plimits
  1492.     * lines above and below must have valid data and the
  1493.     * central one must have 01 as it's flag (unfinished).  it's
  1494.     * ok to check above or below the buffer by up to 10 because
  1495.     * we've put extra bytes there to allow it.  **/
  1496.  
  1497.     if (linestats[line] == ls_level) {
  1498.         /** we can index negative because of the statsbase[10]
  1499.         * buffer below the start of linestats */
  1500.         for (cr = -highplimit; cr <= highplimit; cr++) {
  1501.         if (linestats[line + cr] < ls_level) {
  1502.             break;
  1503.         }
  1504.         }
  1505.         if (cr > highplimit) { /* none were < ls_level */
  1506.         return line;
  1507.         }
  1508.     }
  1509.     line++;
  1510.     }
  1511.     return -1;
  1512. }
  1513.  
  1514.  
  1515.  
  1516.  
  1517. /** this routine moves line from it's temporary buffer to it's output
  1518. * buffer and flags it as done in linestats.  it's stretched at this time. 
  1519. * **/
  1520.  
  1521. void
  1522. moverow(int line)
  1523. {
  1524.     byte *from, *to;
  1525.     int count;
  1526.     int i;
  1527.  
  1528.     linestats[line] = LS_DONE;
  1529.  
  1530.     to = out_offs[line];
  1531.     from = pointtemp(line);
  1532.  
  1533.     TRACE("k", __FILE__ ": moving line %d from %p to %p \n",
  1534.         line, from, to);
  1535.  
  1536.     /** see if the data is stretched or unstretched. **/
  1537.  
  1538.     if ((opts & OPT_HORIZ_STRETCH) == 0) {
  1539.     /** unstretched data. **/
  1540.     memcpy(to, from, 3 * bwidth);
  1541.     return;
  1542.     }
  1543.  
  1544.     /** stretched data.  the output size will be 1.25 times the input
  1545.     * size, partial pixels are not created.  for instance, 102
  1546.     * calculates as follows:  102 x 1.25 = 127.5 you get 127 pixels,
  1547.     * not 128.    **/
  1548.     /** get width in 3 color cells **/
  1549.     count = bwidth;
  1550.  
  1551.     i = 0;
  1552.  
  1553.     do {
  1554.     /** move 1 rgb value **/
  1555.     *to++ = *from++;
  1556.     *to++ = *from++;
  1557.     *to++ = *from++;
  1558.  
  1559.     /** see if it's the 4th pixel.    we stretch there **/
  1560.     /** if not, just loop **/
  1561.     if (i == 3) {
  1562.         /** but if it is, we have to have some data to **/
  1563.         /** the right of it. **/
  1564.         if (count != 1) {
  1565.         /** average the colors of this pixel from
  1566.         * those around it **/
  1567.         *to++ = (from[0] + from[-3])/2;
  1568.         *to++ = (from[1] + from[-2])/2;
  1569.         *to++ = (from[2] + from[-1])/2;
  1570.  
  1571.         } else {
  1572.  
  1573.         /** if we need to stretch but there's **/
  1574.         /** nothing to right, just dup it. **/
  1575.         *to++ = from[-3];
  1576.         *to++ = from[-2];
  1577.         *to++ = from[-1];
  1578.         }
  1579.     }
  1580.  
  1581.     i = (i + 1) & 3; /** make counter for next pixel **/
  1582.  
  1583.     } while (--count > 0);
  1584. }
  1585.  
  1586. /** this sub will remove moire patterns for the dram row you specify in
  1587. * line and make final color adjustments.  you must verify that it's
  1588. * surrounding pixlimit rows are available before calling and that it is in
  1589. * need of final processing (linestat=1).  when the line is on the screen
  1590. * border, this routine uses whichever rows can be used (at the top it goes
  1591. * down, at the bottom it goes up). 
  1592.  
  1593. * the resulting data goes into the temporary buffers, not into the final
  1594. * output buffer.  this prevents probogation of the color averaging.  **/
  1595.  
  1596. void
  1597. moirerow(struct colordata *cdp, int line)
  1598. {
  1599.  
  1600.     byte *to, *from;
  1601.     byte *traceoff;
  1602.     int col;
  1603.     int centpix;
  1604.     int centtype;
  1605.     int bl;
  1606.  
  1607.     /** point to the temporary output buffer into which to put the
  1608.     * corrected data.  we can't move it to the real output buffer yet
  1609.     * or else it will cause color smearing when the averaging moves
  1610.     * down the screen.    **/
  1611.  
  1612.     to = pointtemp(line);   /** find the temporary buffer **/
  1613.  
  1614.     /** get input data offset **/
  1615.     from = input_offs[line];
  1616.  
  1617.     TRACE("k", __FILE__ ": moirerow line %d from %p to %p\n", line,
  1618.         from, to);
  1619.  
  1620.     /** set image as moire fixed, but not final intensity adjusted.  **/
  1621.     linestats[line] = LS_ALMOST;
  1622.  
  1623.     /** get dark level of this line **/
  1624.     bl = blacks[line];
  1625.  
  1626.     /** clear loop counter **/
  1627.     col = 0;
  1628.  
  1629.     /** we'll average the pixels around this one together to smooth
  1630.     * out the apperance and minimize the effect of moire patterns.  **/
  1631.  
  1632.     /** first step is to get particulars of the original in order to
  1633.     * adjust the intensity when done.  we also get the b&w info of this
  1634.     * pixel as stored in tracebuf.  we use that to find boundries as we
  1635.     * average.    **/
  1636.  
  1637.     do {
  1638.     /** get pixel we are trying to fix, adjust for black level **/
  1639.     centpix = bfix(*from, bl);
  1640.  
  1641.     if ((line & 1) == 0) { /** see if on a cyg yemg line **/
  1642.         if ((col & 1) == 0) {
  1643.         centtype = CYG; /** its cyg **/
  1644.         } else {
  1645.         centtype = YEMG; /** its yemg **/
  1646.         }
  1647.     } else { /** nope. it's a cymg yeg line **/
  1648.         if ((col & 1) == 0) {
  1649.         centtype = CYMG; /** its cymg **/
  1650.         } else {
  1651.         centtype = YEG; /** its yeg **/
  1652.         }
  1653.     } 
  1654.  
  1655.     /** now get the original b&w info.     **/
  1656.     traceoff = pointtrace(line); /** point to the trace buffer **/
  1657.  
  1658.     /** set central pixel b&w info **/
  1659.     centralbw = traceoff[col];
  1660.  
  1661.     /** create the amount this pixel can deviate **/
  1662.     /** make percent*128 [ we use half as much]  **/
  1663.     /** set for checkedge **/
  1664.     centraldev = (centralbw * cdp->diflimit)/128/2;
  1665.     if (centraldev > 255) centraldev = 255;
  1666.  
  1667.     /** we have the particulars so we can set an intensity
  1668.     * when done and we have b&w info for boundry checking.    now
  1669.     * we have to average neighboring pixels to make a color. 
  1670.     * **/
  1671.  
  1672.     /** use an averaging technique **/
  1673.     averagearea(line, col);
  1674.  
  1675.     /** color to use is in runningred, green, blue.  match it
  1676.     * to the intensity of the cell we are on so that the black
  1677.     * and white info is perfect.  **/
  1678.  
  1679. #ifndef MOIREDBG    /** for visual display of moire logic **/
  1680.  
  1681.     fixintensity(centpix, centtype); /** adjust the intensity to the cell type **/
  1682.  
  1683.     /** if edge color correction is on, we have to do the left
  1684.     * most pixel which is too dark and has to be fixed after
  1685.     * calling fixintensity.  **/
  1686.  
  1687.     if (col == 0 && (opts & OPT_EDGE_CORRECTION)) {
  1688.  
  1689.         runningblue *= 190;
  1690.         runningblue /= 128;
  1691.  
  1692.         runninggreen *= 190;
  1693.         runninggreen /= 128;
  1694.  
  1695.         runningred *= 190;
  1696.         runningred /= 128;
  1697.     }
  1698.  
  1699. #endif /** MOIREDBG **/
  1700.  
  1701.     /** make the final intensity adjustment.  we do that
  1702.     * before color balance so that we get finer resolution on
  1703.     * the color balance.  */
  1704.  
  1705.     /** multiply by the base 128 percentage intensity **/
  1706.     runningblue *= cdp->intensity;
  1707.     runningblue /= 128;
  1708.  
  1709.     /** multiply by the base 128 percentage intensity **/
  1710.     runninggreen *= cdp->intensity;
  1711.     runninggreen /= 128;
  1712.  
  1713.     /** multiply by the base 128 percentage intensity **/
  1714.     runningred *= cdp->intensity;
  1715.     runningred /= 128;
  1716.  
  1717.     /** if vignette correction is on we need to do that now. **/
  1718.     if (opts & OPT_VIGNETTE_CORRECTION) {
  1719.         vignettesub(line, col);
  1720.     }
  1721.  
  1722.     /** now do the color balance adjustments and the haze level **/
  1723.  
  1724.  
  1725. #ifndef MOIREDBG
  1726.  
  1727.     /** adjust red level for white balance **/
  1728.     runningred = ((runningred * redfix) / 128) - cdp->hazelevel;
  1729.     if (runningred < 0) runningred = 0;
  1730.  
  1731.     /** give specified adjustment to green **/
  1732.     runninggreen = ((runninggreen * greenfix) / 128) - cdp->hazelevel;
  1733.     if (runninggreen < 0) runninggreen = 0;
  1734.  
  1735.     /** adjust blue level for white balance **/
  1736.     runningblue = ((runningblue * bluefix) / 128) - cdp->hazelevel;
  1737.     if (runningblue < 0) runningblue = 0;
  1738.  
  1739. #endif /* MOIREDBG */
  1740.  
  1741.     /** see what type of scaling down is enabled, cropping to
  1742.     * fit, or simply chopping it off.  **/
  1743.  
  1744.     /** see if color cropping is on **/
  1745.     if (opts & OPT_COLOR_CROP) {
  1746.         adjustcolor(); /** if on, scale them down **/
  1747.     }
  1748.  
  1749.     /** set adjusted blue **/
  1750.     to[BLUE] = (runningblue <= 255) ? runningblue : 255;
  1751.  
  1752.     /** set adjusted green **/
  1753.     to[GREEN] = (runninggreen <= 255) ? runninggreen : 255;
  1754.  
  1755.     /** set adjusted red **/
  1756.     to[RED] = (runningred <= 255) ? runningred : 255;
  1757.  
  1758.     to += 3;
  1759.     from++;
  1760.     col ++;
  1761.  
  1762.     } while (col < bwidth);
  1763.  
  1764.     return;
  1765. }
  1766.  
  1767. /** this routine does the vignette adjustment.    the intensity of the lens
  1768. * falls off as we get further from the center.    assuming that it falls as
  1769. * the square of the distance, the measurements taken indicated a 50%
  1770. * falloff from center to right side.  since a 50% falloff is acheived by
  1771. * dividing by 2, the square root of that is 1.41.  but the falloff at the
  1772. * center is arbitrarily assigned to be zero since we desire to brighten the
  1773. * sides, not lower the brightness of the center.  thus the distance from
  1774. * center to right side, a distance of 256 pixels horizontally, is .41
  1775. * units.  we based our initial calculations on that assumption.  after that
  1776. * we twiked the numbers to balance a white piece of paper best. 
  1777. *
  1778. * to find the distance from the center we take the square root of the sum
  1779. * of the squares of the horizontal and vertical distances.  we divide by
  1780. * that square.    **/
  1781.  
  1782. /** on input: line has the row number, col has the pixel number, 
  1783. * and the data is in runningblue, runninggreen, and runningred. **/
  1784.  
  1785. /* on return: runningred, etc are changed. **/
  1786.  
  1787.  
  1788. #define HORZPITCH 624        /** horz pitch is what you would expect
  1789.         * to be called vertical pitch.    the
  1790.         * ccd is laid on it's side image wise.    **/
  1791.  
  1792. #define VERTPITCH (HORZPITCH*75)/96   /** the ratio is 7.5uM to 9.6uM **/
  1793.  
  1794. void
  1795. vignettesub(int line, int col)
  1796. {
  1797.  
  1798.     int x, y, l, factor;
  1799.  
  1800.     /** get vertical size (horizontal to us). **/
  1801.     /** make center point of image. **/
  1802.     /** (remember!  ccd is laid on side, so vertical **/
  1803.     /** distance is really horizontal distance!) **/
  1804.     /** make absolute value of it. **/
  1805.     x = absolute((bwidth/2) - col);
  1806.  
  1807.     /** now adjust for image size **/
  1808.     /** full image is 512, we we make ratio **/
  1809.     x *= bwidth;
  1810.     x /= 512;
  1811.  
  1812.     /** correct for pitch **/
  1813.     /** divide by 128 to get result **/
  1814.     /** but another 4 to keep numbers as /4 **/
  1815.     x *= (VERTPITCH * 128)/HORZPITCH;
  1816.     x /= (128*4);
  1817.  
  1818.     /** make horizontal center point (vertical to us) **/
  1819.     /** remember to remove 100h which selects bank **/
  1820.  
  1821.     y = absolute((bheight/2) - (line & 0xff));
  1822.     y *= bheight;
  1823.     y /= (256*4);   /** we can assume 246=256 for speed. **/
  1824.         /** since we're making /4 numbers when done, **/
  1825.  
  1826.     /** find distance to pixel. **/
  1827.     l = findlength(x,y);
  1828.  
  1829.     /** make center be 1.   **/
  1830.     l += HORZPITCH/4;
  1831.  
  1832.     /** make square of distance * (horzpitch/4)^2 **/
  1833.     l *= l;
  1834.     factor = (HORZPITCH/4)*(HORZPITCH/4);
  1835.  
  1836.     /** now l has the square of the distance and factor has the factor
  1837.     * that distance square is multiplied by.  we need to multiply the
  1838.     * intensity by that squared distance, then divide by factor.  **/
  1839.  
  1840.     runningblue *= l;
  1841.     runningblue /= factor;
  1842.  
  1843.     runninggreen *= l;
  1844.     runninggreen /= factor;
  1845.  
  1846.     runningred *= l;
  1847.     runningred /= factor;
  1848. }
  1849.  
  1850. /** this is like vignettesub but it's used for a single b&w level.
  1851. * col has the pixel number, and line the line number.  **/
  1852. int
  1853. grey_vignettesub(int line, int col, int b)
  1854. {
  1855.     int x, y, l, factor;
  1856.  
  1857.     /** get vertical size (horizontal to us).
  1858.     * make center point of image. 
  1859.     * (remember!  ccd is laid on side, so vertical 
  1860.     * distance is really horizontal distance!) 
  1861.     * make absolute value of it. **/
  1862.     x = absolute((bwidth/2) - col);
  1863.  
  1864.     /** now adjust for image size **/
  1865.     x *= bwidth;
  1866.     /** full image is 512, we we make ratio **/
  1867.     x /= (128*4);
  1868.  
  1869.     /** correct for pitch **/
  1870.     x *= (VERTPITCH * 128)/HORZPITCH;
  1871.  
  1872.     /** divide by 128 to get result **/
  1873.     /** but another 4 to keep numbers as /4 **/
  1874.     x /= (128*4);
  1875.  
  1876.     /** make horizontal center point (vertical to us) **/
  1877.     /** but work in byte to remove 100h **/
  1878.     /** make absolute value of vert. dif from center **/
  1879.     y = absolute((bheight/2) - (line & 0xff));
  1880.  
  1881.     /** we can also assume 246=256 for speed. **/
  1882.     y *= bheight;
  1883.     y /= (256*4);
  1884.  
  1885.     /** find distance using dx and ax. returned in ax. **/
  1886.     l = findlength(x,y);
  1887.  
  1888.     /** make center be 1.   **/
  1889.     l += HORZPITCH/4;
  1890.  
  1891.     /** make square of distance * (horzpitch/4)^2 **/
  1892.     l *= l;
  1893.     factor = (HORZPITCH/4)*(HORZPITCH/4);
  1894.  
  1895.     /** now l has the square of the distance and factor has the factor
  1896.     * that distance square is multiplied by.  we need to multiply the
  1897.     * intensity by that squared distance, then divide by factor.  **/
  1898.  
  1899.     return (b * l) / factor;
  1900. }
  1901.  
  1902.  
  1903. /** this routine averages the area surrounding the pixel specified by
  1904. * line and col.  the average is returned in runningred,
  1905. * runninggreen, and runningblue.  it assumes that the low bit of blue is
  1906. * used to flag if the lower or upper pixlimits value should be used.  **/
  1907.  
  1908. void
  1909. averagearea(int line, int col)
  1910. {
  1911.  
  1912.     byte *brg_p;
  1913.     int searchlimit;
  1914.  
  1915.     /** point to pixel in question **/
  1916.     brg_p = out_offs[line] + col*3;
  1917.  
  1918.     /** use upper limit(if pixel marked bad)? **/
  1919.     if (brg_p[BLUE] & 1) {
  1920.     searchlimit = highplimit;
  1921.  
  1922.     /** we're using the larger pixlimit.  experiments show we
  1923.     * should grab the whole area.  first we try just the good
  1924.     * ones, then if that fails we use it all.  **/
  1925.  
  1926.     /** try to use only the good ones **/
  1927.     if (goodaverage(line, col, searchlimit)) {
  1928.         MOIREDBGSET(1,0,0); /** red: moderate amount go here. **/
  1929.     } else if ((opts & OPT_COLOR_TRACING) && 
  1930.             boundryaverage(line, col, searchlimit)) {
  1931.         MOIREDBGSET(0,1,0); /** blue: a low amount go here. **/
  1932.     } else { /** no good. use all of them. **/
  1933.         allaverage(line, col, searchlimit);
  1934.         MOIREDBGSET(0,0,0); /** black: a moderately to low amount **/
  1935.     }
  1936.  
  1937.     } else {
  1938.     searchlimit = lowplimit;
  1939.  
  1940.     /** we're using the smaller pixlimit.  try to use only good
  1941.     * pixels first.  **/
  1942.  
  1943.     /** try to use only the good ones **/
  1944.     if (goodaverage(line, col, searchlimit)) {
  1945.         MOIREDBGSET(1,1,1); /** white: a high amount go here. **/
  1946.     } else if ((opts & OPT_COLOR_TRACING) &&
  1947.             boundryaverage(line, col, searchlimit)) {
  1948.         /** try just boundry tracing **/
  1949.         MOIREDBGSET(1,0,1); /** yellow: extreme low amount here **/
  1950.     } else { /** no good. use all of them. **/
  1951.         allaverage(line, col, searchlimit);
  1952.         MOIREDBGSET(0,0,1); /** green: extreme low amount go here. **/
  1953.     }
  1954.     }
  1955. #ifndef MOIREDBG 
  1956.     /** now average the colors we added. **/
  1957.     runningred = rdiv(runningred, runningcount);
  1958.     runninggreen = rdiv(runninggreen, runningcount);
  1959.     runningblue = rdiv(runningblue, runningcount);
  1960. #endif
  1961. }
  1962.  
  1963. inline void
  1964. clearaverage(void)
  1965. {
  1966.     runningred = runninggreen = runningblue = runningcount = 0;
  1967. }
  1968.  
  1969.  
  1970. /** this sub makes the average for the area specified in searchlimit.  it
  1971. * uses all pixels, there are no boundry or good pixel checks, and it always
  1972. * returns an averaged value.  **/
  1973.  
  1974. void
  1975. allaverage(int line, int col, int searchlimit)
  1976. {
  1977.     int i;
  1978.     int bankbeg = line & 0xff00;
  1979.     int bankend = bankbeg + bheight;
  1980.     int searchpos;
  1981.  
  1982.     /** clear the color averages **/
  1983.     clearaverage();
  1984.  
  1985.     /** do this row **/
  1986.     next_all_average(line, col, searchlimit);
  1987.  
  1988.     searchpos = 0;
  1989.  
  1990.     while (++searchpos <= searchlimit) {
  1991.  
  1992.     /** go 1 up and then 1 down and repeat until we've done
  1993.     * pixlimit above and below **/
  1994.  
  1995.     /** try to go 1 up **/
  1996.     i = line - searchpos;
  1997.     if (i >= bankbeg)
  1998.         next_all_average(i, col, searchlimit);
  1999.  
  2000.     /** try to go 1 down **/
  2001.     i = line + searchpos;
  2002.     if (i < bankend)
  2003.         next_all_average(i, col, searchlimit);
  2004.     }
  2005.  
  2006. }
  2007.  
  2008. /** this routine takes a row number in bx and sets up to call
  2009. * continue_all_average.  it uses all pixels.  **/
  2010.  
  2011. /** next_all_average: **/
  2012. void
  2013. next_all_average(int line, int col, int searchlimit)
  2014. {
  2015.     byte *traceoff;
  2016.  
  2017.     /** set up the trace buffer pointer **/
  2018.     traceoff = pointtrace(line);
  2019.     
  2020.     continue_all_average(col, searchlimit, &traceoff[col],
  2021.     out_offs[line] + col*3);
  2022. }
  2023.  
  2024.  
  2025. /** entry:  brg_p points to the bgr pixel data, tr_off points to the
  2026. * b&w trace buffer entries for the pixel data, col is the number of
  2027. * the pixel on the scan line, centraltype and centpix have the original
  2028. * type of pixel we are trying to match and it's value.    centralbw has the
  2029. * black and white rendition of the cell you are on.  you have called
  2030. * clearaverage 1 time before starting your accumulated average.  **/
  2031.  
  2032. /** on return, runningred, etc.  have runningcount samples in them.  **/
  2033.  
  2034. /** call here with a new scan line after calling clearaverage and it will
  2035. * add the new samples to the average **/
  2036.  
  2037. void
  2038. continue_all_average(int col, int searchlimit, byte *tr_off, byte *brg_p)
  2039. {
  2040.     int counter;
  2041.     byte *p, *trp;
  2042.  
  2043.     p = brg_p; /** starting position of rgb **/
  2044.     trp = tr_off; /** and of bw info **/
  2045.  
  2046.     /** look left on the same scan line for a pixel we can use. **/
  2047.  
  2048.     /** this is the count of pixels to the left **/
  2049.     counter = col;
  2050.     /** skip if only doing 1 we are on **/
  2051.     if (counter != 0 && searchlimit != 0) {
  2052.     if (counter > searchlimit)
  2053.         counter = searchlimit;
  2054.  
  2055.     /** average the ones to the left **/
  2056.     do {
  2057.         p -= 3;
  2058.  
  2059.         /** average the new color **/
  2060.         runningblue += p[BLUE];
  2061.         runninggreen += p[GREEN];
  2062.         runningred += p[RED];
  2063.  
  2064.         ++runningcount;
  2065.  
  2066.     } while (--counter > 0);
  2067.  
  2068.     }
  2069.  
  2070.     /** now average the colors to the right of this pixel, including
  2071.     * the one we are on.  **/
  2072.  
  2073.     p = brg_p;
  2074.     trp = tr_off;
  2075.  
  2076.     /** make count to right, including one we are on **/
  2077.     counter = bwidth - col;
  2078.  
  2079.     if (counter > searchlimit + 1)
  2080.     counter = searchlimit + 1;
  2081.  
  2082.     do { 
  2083.     /** average the new color **/
  2084.     runningblue += p[BLUE];
  2085.     runninggreen += p[GREEN];
  2086.     runningred += p[RED];
  2087.  
  2088.     ++runningcount;
  2089.  
  2090.     p += 3;
  2091.  
  2092.     } while (--counter > 0);
  2093.  
  2094. }
  2095.  
  2096.  
  2097. /** this sub makes the average for the area specified in searchlimit.  it
  2098. * uses all pixels until it hits a boundry.  use this only if the options
  2099. * bits have boundry tracing on.  this routine does not check for bad
  2100. * pixels.  since boundry checking mean there aren't enough, this routine
  2101. * returns a flag:  non-zero means there were enough, zero means there
  2102. * weren't enough.  **/
  2103.  
  2104. /** boundryaverage: **/
  2105. int
  2106. boundryaverage(int line, int col, int searchlimit)
  2107. {
  2108.     int i;
  2109.     int bankbeg = line & 0xff00;
  2110.     int bankend = bankbeg + bheight;
  2111.     int searchpos;
  2112.  
  2113.     /** clear the color averages **/
  2114.     clearaverage();
  2115.  
  2116.     /** do this row **/
  2117.     (void)next_boundry_average(line, col, searchlimit);
  2118.  
  2119.     /** go up and repeat until we've done pixlimit above or we hit a
  2120.     * block **/
  2121.     searchpos = 0;
  2122.     while (++searchpos <= searchlimit) {
  2123.     i = line - searchpos;
  2124.     if (i < bankbeg || next_boundry_average(i, col, searchlimit) == 0)
  2125.         break;
  2126.     }
  2127.  
  2128.     /** go down and repeat until we've done pixlimit below or we hit a
  2129.     * block **/
  2130.     searchpos = 0;
  2131.     while (++searchpos <= searchlimit) {
  2132.     i = line + searchpos;
  2133.     if (i >= bankend || next_boundry_average(i, col, searchlimit) == 0)
  2134.         break;
  2135.     }
  2136.  
  2137.     /** now average the colors we added if there are enough.  we must
  2138.     * have 1/2 of the specified search area.  we can't use a fixed
  2139.     * number for what is considered enough, or else the user increasing
  2140.     * his pixlimit has no effect on some pixels.  **/
  2141.  
  2142.     if (runningcount < (((searchlimit*2+1) * (searchlimit*2+1))/2))
  2143.     return 0;
  2144.  
  2145.     return 1;
  2146. }
  2147.  
  2148. /** this routine takes a row number in bx and sets up to call
  2149. * continue_boundry_average.  it doesn't pay attention to "good" or "bad"
  2150. * pixel markings in the low bit of the blue, but it does honor b&w
  2151. * boundries.  it returns a flag:  zero means no pixels were found on this
  2152. * line, non-zero means some were found.  zero implies a solid boundry in
  2153. * the line direction you were moving.  **/
  2154.  
  2155. int
  2156. next_boundry_average(int line, int col, int searchlimit)
  2157. {
  2158.     int counted;
  2159.     byte *traceoff;
  2160.  
  2161.     /** set up the trace buffer pointer **/
  2162.     traceoff = pointtrace(line);
  2163.     
  2164.     counted = continue_boundry_average(col, searchlimit, &traceoff[col],
  2165.         out_offs[line] + col*3);
  2166.     runningcount += counted;
  2167.     return counted != 0;
  2168. }
  2169.  
  2170. /** this routine takes a pointer to a pixel on an rgb scan line and a pixel
  2171. * number in col and averages searchlimit pixels to the left and
  2172. * searchlimit to the right, including the one we are on.  it does boundry
  2173. * tracing during that process, aborting at the end of a boundry.  it does
  2174. * not check for "bad" pixels.  don't call unless boundry tracing is on in
  2175. * the options bits. 
  2176. *
  2177. * entry:  brg_p points to the bgr pixel data, tr_off points to the b&w
  2178. * trace buffer entries for the pixel data, col is the number of the
  2179. * pixel on the scan line, centraltype and centpix have the original type
  2180. * of pixel we are trying to match and it's value.  centralbw has the black
  2181. * and white rendition of the cell you are on.  you have called clearaverage
  2182. * 1 time before starting your accumulated average. 
  2183. *
  2184. * returns no. of samples we've added to runningred, etc.
  2185. **/
  2186.  
  2187. int
  2188. continue_boundry_average(int col, int searchlimit, byte *tr_off, byte *brg_p)
  2189. {
  2190.     int counter;
  2191.     byte *p, *trp;
  2192.     int counted = 0;
  2193.  
  2194.  
  2195.     p = brg_p; /** starting position of rgb **/
  2196.     trp = tr_off; /** and of bw info **/
  2197.  
  2198.     /** look left on the same scan line for a pixel we can use. **/
  2199.  
  2200.     /** this is the count of pixels to the left **/
  2201.     counter = col;
  2202.     /** skip if only doing 1 we are on **/
  2203.     if (counter != 0 && searchlimit != 0) {
  2204.     if (counter > searchlimit)
  2205.         counter = searchlimit;
  2206.  
  2207.     /** average the ones to the left **/
  2208.     do {
  2209.         p -= 3;
  2210.  
  2211.         /** get b&w for check of boundry, see if too
  2212.         * different: if so, we hit a block **/
  2213.         trp--;
  2214.         if (abs(*trp - centralbw) > centraldev)
  2215.         break;
  2216.  
  2217.         /** average the new color **/
  2218.         runningblue += p[BLUE];
  2219.         runninggreen += p[GREEN];
  2220.         runningred += p[RED];
  2221.  
  2222.         ++counted;
  2223.  
  2224.     } while (--counter > 0);
  2225.  
  2226.     }
  2227.  
  2228.     /** now average the colors to the right of this pixel, including
  2229.     * the one we are on.  **/
  2230.  
  2231.     p = brg_p;
  2232.     trp = tr_off;
  2233.  
  2234.     /** make count to right, including one we are on **/
  2235.     counter = bwidth - col;
  2236.  
  2237.     if (counter > searchlimit + 1)
  2238.     counter = searchlimit + 1;
  2239.  
  2240.     do { 
  2241.     /** get b&w for check of boundry, see if too
  2242.     * different: if so, we hit a block **/
  2243.     if (abs(*trp - centralbw) > centraldev)
  2244.         break;
  2245.  
  2246.     /** average the new color **/
  2247.     runningblue += p[BLUE];
  2248.     runninggreen += p[GREEN];
  2249.     runningred += p[RED];
  2250.  
  2251.     ++counted;
  2252.  
  2253.     trp++;
  2254.     p += 3;
  2255.  
  2256.     } while (--counter > 0);
  2257.     return counted;
  2258. }
  2259.  
  2260. /** this sub makes the average for the area specified in searchlimit.  it
  2261. * uses only pixels which have not been marked as having moire troubles, and
  2262. * which are not on or past a boundry with the current b&w info for the
  2263. * starting pixel.  since this might mean there aren't enough, this routine
  2264. * returns a flag:  non-zero means there were enough, zero means there
  2265. * weren't enough.  **/
  2266.  
  2267.  
  2268.  
  2269. int
  2270. goodaverage(int line, int col, int searchlimit)
  2271. {
  2272.     int i;
  2273.     int bankbeg = line & 0xff00;
  2274.     int bankend = bankbeg + bheight;
  2275.     int searchpos;
  2276.  
  2277.     /** clear the color averages **/
  2278.     clearaverage();
  2279.  
  2280.     /** do this row **/
  2281.     next_good_average(line, col, searchlimit);
  2282.  
  2283.  
  2284.     /** go up and repeat until we've done pixlimit above or we hit a
  2285.     * block **/
  2286.     searchpos = 0;
  2287.     while (++searchpos <= searchlimit) {
  2288.     i = line - searchpos;
  2289.     if (i < bankbeg || next_good_average(i, col, searchlimit) == 0)
  2290.         break;
  2291.     }
  2292.  
  2293.     /** go down and repeat until we've done pixlimit below or we hit a
  2294.     * block **/
  2295.     searchpos = 0;
  2296.     while (++searchpos <= searchlimit) {
  2297.     i = line + searchpos;
  2298.     if (i >= bankend || next_good_average(i, col, searchlimit) == 0)
  2299.         break;
  2300.     }
  2301.  
  2302.     /** now average the colors we added if there are enough.  we must
  2303.     * have 1/4 of the specified search area.  **/
  2304.     if (runningcount < (((searchlimit*2+1) * (searchlimit*2+1))/4))
  2305.     return 0;
  2306.  
  2307.     return 1;
  2308. }
  2309.  
  2310. /** this routine takes a row number in bx and sets up to call
  2311. * continue_good_average.  it does pay attention to "good" or "bad" pixel
  2312. * markings in the low bit of the blue, as well as honoring b&w boundries. 
  2313. * it returns a flag:  z means no pixels were found on this line, nz means
  2314. * some were found.  z implies a solid boundry in the line direction you
  2315. * were moving.    **/
  2316.  
  2317. int
  2318. next_good_average(int line, int col, int searchlimit)
  2319. {
  2320.     int counted;
  2321.     byte *traceoff;
  2322.  
  2323.     /** set up the trace buffer pointer **/
  2324.     traceoff = pointtrace(line);
  2325.     
  2326.     counted = continue_good_average(col, searchlimit,
  2327.     &traceoff[col], out_offs[line] + col*3);
  2328.     runningcount += counted;
  2329.     return counted != 0;
  2330. }
  2331.  
  2332. /** this routine takes a pointer to a pixel on an rgb scan line
  2333. * and a pixel number in col and averages searchlimit pixels
  2334. * to the left and searchlimit to the right, including the one we are on. 
  2335. * it does boundry tracing during that process, aborting at the end of a
  2336. * boundry.  it also checks for "bad" pixels.  you may call regardless of
  2337. * whether boundry tracing is on or off. 
  2338. *
  2339. * on entry: brg_p points to the bgr pixel data, tr_off points to 
  2340. * the b&w trace buffer entries for the pixel data, col is the number  
  2341. * of the pixel on the scan line, centraltype and centpix have the 
  2342. * original type of pixel we are trying to match and it's value.  you 
  2343. * have called clearaverage 1 time before starting your accumulated average. 
  2344. *
  2345. * returns no. of samples we've added to runningred, etc.
  2346. **/
  2347.  
  2348.  
  2349. int
  2350. continue_good_average(int col, int searchlimit, byte *tr_off, byte *brg_p)
  2351. {
  2352.  
  2353.     int counter;
  2354.     byte *p, *trp;
  2355.     int counted = 0;
  2356.  
  2357.  
  2358.     p = brg_p; /** starting position of rgb **/
  2359.     trp = tr_off; /** and of bw info **/
  2360.  
  2361.     /** look left on the same scan line for a pixel we can use. **/
  2362.  
  2363.     /** this is the count of pixels to the left **/
  2364.     counter = col;
  2365.     /** skip if only doing 1 we are on **/
  2366.     if (counter != 0 && searchlimit != 0) {
  2367.     if (counter > searchlimit)
  2368.         counter = searchlimit;
  2369.  
  2370.     /** average the ones to the left **/
  2371.     if ((opts & OPT_COLOR_TRACING) == 0) {
  2372.         do {
  2373.         p -= 3;
  2374.  
  2375.         /** get blue, see if "bad" **/
  2376.         if ((p[BLUE] & 1) == 0) {
  2377.             /** average the new color **/
  2378.             runningblue += p[BLUE];
  2379.             runninggreen += p[GREEN];
  2380.             runningred += p[RED];
  2381.  
  2382.             ++counted;
  2383.         }
  2384.         } while (--counter > 0);
  2385.     } else {
  2386.         do {
  2387.         p -= 3;
  2388.  
  2389.         /** get b&w for check of boundry, see if too
  2390.         * different: end if boundry **/
  2391.         trp--;
  2392.         if (abs(*trp - centralbw) > centraldev)
  2393.             break;
  2394.  
  2395.         /** get blue, see if "bad" **/
  2396.         if ((p[BLUE] & 1) == 0) {
  2397.             /** average the new color **/
  2398.             runningblue += p[BLUE];
  2399.             runninggreen += p[GREEN];
  2400.             runningred += p[RED];
  2401.  
  2402.             ++counted;
  2403.         }
  2404.         } while (--counter > 0);
  2405.     }
  2406.  
  2407.     }
  2408.  
  2409.     /** now average the colors to the right of this pixel, including
  2410.     * the one we are on.  **/
  2411.  
  2412.     p = brg_p;
  2413.     trp = tr_off;
  2414.  
  2415.     /** make count to right, including one we are on **/
  2416.     counter = bwidth - col;
  2417.  
  2418.     if (counter > searchlimit + 1)
  2419.     counter = searchlimit + 1;
  2420.  
  2421.     if ((opts & OPT_COLOR_TRACING) == 0) {
  2422.     do { 
  2423.         /** get blue, see if "bad" **/
  2424.         if ((p[BLUE] & 1) == 0) {
  2425.         /** average the new color **/
  2426.         runningblue += p[BLUE];
  2427.         runninggreen += p[GREEN];
  2428.         runningred += p[RED];
  2429.  
  2430.         ++counted;
  2431.         }
  2432.         p += 3;
  2433.     } while (--counter > 0);
  2434.     } else {
  2435.     do {
  2436.         /** get b&w for check of boundry, see if too
  2437.         * different: if so, boundry and we stop moving right **/
  2438.         if (abs(*trp - centralbw) > centraldev)
  2439.         break;
  2440.  
  2441.         /** get blue, see if "bad" **/
  2442.         if ((p[BLUE] & 1) == 0) {
  2443.         /** average the new color **/
  2444.         runningblue += p[BLUE];
  2445.         runninggreen += p[GREEN];
  2446.         runningred += p[RED];
  2447.  
  2448.         ++counted;
  2449.         }
  2450.         trp++;
  2451.         p += 3;
  2452.     } while (--counter > 0);
  2453.     }
  2454.  
  2455.     return counted;
  2456.  
  2457. }
  2458.  
  2459.  
  2460. /** this sub takes whatever is in runningred, green, and blue, and adjusts
  2461. * them to match the value read in centpix with filter curtype.    this
  2462. * routine uses math and the single pixel to make the intensity adjustment. 
  2463. * **/
  2464.  
  2465. void
  2466. fixintensity(int curpix, int curtype)
  2467. {
  2468.     int tmp;
  2469.     int redlevel, greenlevel, bluelevel;
  2470.  
  2471. #define SCAL(x) (x*128)/100;
  2472.  
  2473.     if (curtype == CYG) { /** cyg filter characteristics **/
  2474.     redlevel = SCAL(22);
  2475.     greenlevel = SCAL(178);
  2476.     bluelevel = SCAL(83);
  2477.  
  2478.     } else if (curtype == YEMG) { /** yemg filter characteristics **/
  2479.     redlevel = SCAL(131);
  2480.     greenlevel = SCAL(127);
  2481.     bluelevel = SCAL(59);
  2482.  
  2483.     } else if (curtype == CYMG) { /** cymg filter characteristics **/
  2484.     redlevel = SCAL(61);
  2485.     greenlevel = SCAL(121);
  2486.     bluelevel = SCAL(138);
  2487.  
  2488.     } else { /** yeg filter characteristics **/
  2489.     redlevel = SCAL(92);
  2490.     greenlevel = SCAL(184);
  2491.     bluelevel = SCAL(16);
  2492.     }
  2493.  
  2494.     tmp = (redlevel * runningred)/128;
  2495.     tmp += (bluelevel * runningblue)/128;
  2496.     tmp += (greenlevel * runninggreen)/128;
  2497.  
  2498.     tmp = rdiv(curpix*256,tmp);
  2499.  
  2500.     runningred = (runningred * tmp)/128;
  2501.     runninggreen = (runninggreen * tmp)/128;
  2502.     runningblue = (runningblue * tmp)/128;
  2503.  
  2504. }
  2505.  
  2506.  
  2507.  
  2508. /** common code for color calcs */
  2509. inline int
  2510. color_eqn(int A, int a, int B, int b, int C, int c)
  2511. {
  2512.     int t;
  2513.     t =     (A * 128)/100 * a +
  2514.     (B * 128)/100 * b +
  2515.     (C * 128)/100 * c;
  2516.     if (t < 0) {
  2517.     /** if underflow, it's a moire situation **/
  2518.     if (t < UNDERFLO * 128)
  2519.         moirefound |= FLAGMOIRE;
  2520.     t = 0;
  2521.     }
  2522.  
  2523.     /** result*128 is in t.   **/
  2524.     return t / 128;
  2525. }
  2526.  
  2527.  
  2528. /* shorthand for common args for the color calc routines */
  2529. #define E entrycyg, entrycymg, entryyeg, entryyemg
  2530.  
  2531. /** these subs solve for green for any combination of three color filters. 
  2532. * the values should be in entrycymg, entryyeg, entryyemg, and entrycyg. 
  2533. * the names give the color filters in alphabetical order seperated by _ and
  2534. * all preceeded by g.  **/
  2535.  
  2536. /** cymg, yeg, and yemg.
  2537.      cymg = .61r +  1.21g + 1.38b 
  2538.      yeg  = .92r +  1.84g + .16b
  2539.      yemg = 1.31r + 1.27g + .59b     
  2540.  
  2541.     g = .21*cymg + .92*yeg - .74*yemg
  2542. **/
  2543.  
  2544. inline int
  2545. g_cymg_yeg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2546. {
  2547.     return color_eqn(21, entrycymg, 92, entryyeg, -74, entryyemg);
  2548. }
  2549.  
  2550.  
  2551. /** cyg, cymg and yeg 
  2552.       cymg = .61r + 1.21g + 1.38b 
  2553.       yeg  = .92r + 1.84g + .16b 
  2554.       cyg  = .22r + 1.78g + .83b 
  2555.  
  2556.     g = .74*cyg + .13*yeg - .46*cymg
  2557. **/
  2558.  
  2559. inline int
  2560. g_cyg_cymg_yeg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2561. {
  2562.     return color_eqn(74, entrycyg, 13, entryyeg, -46, entrycymg);
  2563. }
  2564.  
  2565.  
  2566. /** cyg, yeg, and yemg 
  2567.       yemg = 1.31r + 1.27g + .59b    
  2568.       yeg  = .92r + 1.84g + .16b 
  2569.       cyg = .22r +  1.78g + .83b 
  2570.  
  2571.     g = .23*cyg + .67*yeg - .51*yemg
  2572. **/
  2573.  
  2574. inline int
  2575. g_cyg_yeg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2576. {
  2577.     return color_eqn( 23, entrycyg, 67, entryyeg, -51, entryyemg );
  2578. }
  2579.  
  2580.  
  2581. /** cyg, cymg and yemg 
  2582.       yemg = 1.31r + 1.27g + .59b    
  2583.       cymg = .61r + 1.21g + 1.38b 
  2584.       cyg  = .22r + 1.78g + .83b 
  2585.  
  2586.     g = .86*cyg + .12*yemg - .57*cymg
  2587. **/
  2588.  
  2589. inline int
  2590. g_cyg_cymg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2591. {
  2592.     return color_eqn(86, entrycyg, 12, entryyemg, -57, entrycymg);
  2593. }
  2594.  
  2595. /** this sub does a mathmatical calculation to derive the green.  it is
  2596. * designed to be an equation based alternative to adding the 4 pixels used
  2597. * to make calculate the red and blue.  it takes 4 pixels to derive the red
  2598. * and blue, and they are on opposite scan lines.  but it only takes three
  2599. * pixels (with three different color filters) to solve for a given color. 
  2600. * this routine uses all 4 by solving opposite corners and checking for a
  2601. * deviation.  the deviation is range checked and a flag set if it's too
  2602. * high.  **/
  2603.  
  2604. /** the cells are arranged as follows:
  2605.     cyg  yemg cyg  yemg cyg  yemg
  2606.     cymg yeg  cymg yeg  cymg yeg
  2607.     cyg  yemg cyg  yemg cyg  yemg
  2608.     cymg yeg  cymg yeg  cymg yeg
  2609. **/
  2610.  
  2611.  
  2612. int
  2613. greensub(int entrycyg, int entrycymg, int entryyeg, int entryyemg, int centraltype )
  2614. {
  2615.  
  2616.     /**  average them but leave it as *2. **/
  2617.  
  2618.     if (centraltype == YEG) {
  2619.     /** solution for yeg cell.  add lower right, upper left **/
  2620.     return g_cymg_yeg_yemg(E) + g_cyg_cymg_yemg(E);
  2621.     } else if (centraltype == CYMG) {
  2622.     /** solution for cymg cell.  add lower left, upper right **/
  2623.     return g_cyg_cymg_yeg(E) + g_cyg_yeg_yemg(E);
  2624.     } else if (centraltype == YEMG) {
  2625.     /** solution for yemg cell.  add upper right, lower right **/
  2626.     return g_cyg_yeg_yemg(E) + g_cyg_cymg_yeg(E);
  2627.     } else {
  2628.     /** solution for cyg cell.  add upper left, lower right **/
  2629.     return g_cyg_cymg_yemg(E) + g_cymg_yeg_yemg(E);
  2630.     }
  2631. }
  2632.  
  2633.  
  2634. /** these subs solve for red for any combination of three color filters.  the 
  2635. values should be in entrycymg, entryyeg, entryyemg, and entrycyg.  on 
  2636. return, the solution is in ax.    only dx is changed.  the names give the 
  2637. color filters in alphabetical order seperated by _ and all preceeded by 
  2638. r. **/
  2639.  
  2640. /** cymg, yeg, and yemg. 
  2641.      cymg = .61r +  1.21g + 1.38b 
  2642.      yeg  = .92r +  1.84g + .16b 
  2643.      yemg = 1.31r + 1.27g + .59b     
  2644.  
  2645.     r = 1.49*yemg - .56*cymg - .66*yeg
  2646. **/
  2647.  
  2648. inline int
  2649. r_cymg_yeg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2650. {
  2651.     return color_eqn(149, entryyemg, -56, entrycymg, -66, entryyeg);
  2652. }
  2653.  
  2654.  
  2655. /** cyg, cymg and yeg 
  2656.       cymg = .61r + 1.21g + 1.38b 
  2657.       cyg  = .22r + 1.78g + .83b 
  2658.       yeg  = .92r + 1.84g + .16b 
  2659.  
  2660.     r = .92*yeg + .79*cymg - 1.49*cyg **/
  2661.  
  2662. inline int
  2663. r_cyg_cymg_yeg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2664. {
  2665.     return color_eqn(92, entryyeg, 79, entrycymg, -149, entrycyg);
  2666. }
  2667.  
  2668. /** cyg, yeg, and yemg 
  2669.       yemg = 1.31r + 1.27g + .59b    
  2670.       cyg = .22r +  1.78g + .83b 
  2671.       yeg  = .92r + 1.84g + .16b 
  2672.  
  2673.     sharp formula (assume redfactor=115) 
  2674.     r = .868*yemg -.0027*yeg - .617*cyg
  2675. **/
  2676.  
  2677. inline int
  2678. r_cyg_yeg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2679. {
  2680.     return color_eqn(87, entryyemg, 0, entryyeg, -62, entrycyg);
  2681. }
  2682.  
  2683. /** cyg, cymg and yemg 
  2684.       cymg = .61r + 1.21g + 1.38b 
  2685.       cyg  = .22r + 1.78g + .83b 
  2686.       yemg = 1.31r + 1.27g + .59b    
  2687.  
  2688.     same as sharp formula 
  2689.     r = .866*yemg + .0023*cymg - .619*cyg
  2690. **/
  2691.  
  2692. inline int
  2693. r_cyg_cymg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2694. {
  2695.     return color_eqn(87, entryyemg, 0, entrycymg, -62, entrycyg);
  2696. }
  2697.  
  2698. /** this sub does a mathmatical calculation to derive the red.    it is
  2699. * designed to be an equation based alternative to the sharp 2 pixel
  2700. * formula.  it works similar to greensub.  **/
  2701.  
  2702. int
  2703. redsub(int entrycyg, int entrycymg, int entryyeg, int entryyemg, int centraltype )
  2704. {
  2705.  
  2706.     /**  average them but leave it as *2. **/
  2707.  
  2708.     if (centraltype == YEG) {
  2709.     /** solution for yeg cell.  add lower right, upper left **/
  2710.     return r_cymg_yeg_yemg(E) + r_cyg_cymg_yemg(E);
  2711.     } else if (centraltype == CYMG) {
  2712.     /** solution for cymg cell.  add lower left, upper right **/
  2713.     return r_cyg_cymg_yeg(E) + r_cyg_yeg_yemg(E);
  2714.     } else if (centraltype == YEMG) {
  2715.     /** solution for yemg cell.  add upper right, lower right **/
  2716.     return r_cyg_yeg_yemg(E) + r_cyg_cymg_yeg(E);
  2717.     } else {
  2718.     /** solution for cyg cell.  add upper left, lower right **/
  2719.     return r_cyg_cymg_yemg(E) + r_cymg_yeg_yemg(E);
  2720.     }
  2721. }
  2722.  
  2723. /** these subs solve for blue for any combination of three color filters. 
  2724. * the values should be in entrycymg, entryyeg, entryyemg, and entrycyg.  on
  2725. * return, the solution is in ax.  only dx is changed.  the names give the
  2726. * color filters in alphabetical order seperated by _ and all preceeded by
  2727. * b.  **/
  2728.  
  2729. /** cymg, yeg, and yemg. 
  2730.      cymg = .61r +  1.21g + 1.38b 
  2731.      yeg  = .92r +  1.84g + .16b 
  2732.      yemg = 1.31r + 1.27g + .59b     
  2733.  
  2734.     b = .786*cymg - .513*yeg - .0058*yemg
  2735. **/
  2736.  
  2737. inline int
  2738. b_cymg_yeg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2739. {
  2740.     return color_eqn(79, entrycymg, -51, entryyeg, -1, entryyemg);
  2741. }
  2742.  
  2743.  
  2744. /** cyg, cymg and yeg 
  2745.       cymg = .61r + 1.21g + 1.38b 
  2746.       yeg  = .92r + 1.84g + .16b 
  2747.       cyg  = .22r + 1.78g + .83b 
  2748.  
  2749.     b = .781*cymg +.0058*cyg - .519*yeg
  2750. **/
  2751.  
  2752. inline int
  2753. b_cyg_cymg_yeg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2754. {
  2755.     return color_eqn(78, entrycymg, 1, entrycyg, -52, entryyeg);
  2756. }
  2757.  
  2758. /** cyg, yeg, and yemg 
  2759.       yemg = 1.31r + 1.27g + .59b    
  2760.       yeg  = .92r + 1.84g + .16b 
  2761.       cyg = .22r +  1.78g + .83b 
  2762.  
  2763.     b = .868*cyg + .862*yemg - 1.435*yeg
  2764. **/
  2765.  
  2766. inline int
  2767. b_cyg_yeg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2768. {
  2769.     return color_eqn(87, entrycyg, 86, entryyemg, -144, entryyeg);
  2770. }
  2771.  
  2772.  
  2773. /** cyg, cymg and yemg 
  2774.       yemg = 1.31r + 1.27g + .59b    
  2775.       cymg = .61r + 1.21g + 1.38b 
  2776.       cyg  = .22r + 1.78g + .83b 
  2777.  
  2778.     b = 1.224*cymg -.489*yemg - .483*cyg
  2779. **/
  2780.  
  2781. inline int
  2782. b_cyg_cymg_yemg(int entrycyg, int entrycymg, int entryyeg, int entryyemg )
  2783. {
  2784.     return color_eqn(122, entrycymg, -49, entryyemg, -48, entrycyg);
  2785. }
  2786.  
  2787. /** this sub does a mathmatical calculation to derive the blue.  it is
  2788. * designed to be an equation based alternative to the sharp 2 pixel
  2789. * formula.  it works similar to greensub.  **/
  2790.  
  2791. int
  2792. bluesub(int entrycyg, int entrycymg, int entryyeg, int entryyemg, int centraltype )
  2793. {
  2794.  
  2795.     /**  average them but leave it as *2. **/
  2796.  
  2797.     if (centraltype == YEG) {
  2798.     /** solution for yeg cell.  add lower right, upper left **/
  2799.     return b_cymg_yeg_yemg(E) + b_cyg_cymg_yemg(E);
  2800.     } else if (centraltype == CYMG) {
  2801.     /** solution for cymg cell.  add lower left, upper right **/
  2802.     return b_cyg_cymg_yeg(E) + b_cyg_yeg_yemg(E);
  2803.     } else if (centraltype == YEMG) {
  2804.     /** solution for yemg cell.  add upper right, lower right **/
  2805.     return b_cyg_yeg_yemg(E) + b_cyg_cymg_yeg(E);
  2806.     } else {
  2807.     /** solution for cyg cell.  add upper left, lower right **/
  2808.     return b_cyg_cymg_yemg(E) + b_cymg_yeg_yemg(E);
  2809.     }
  2810. }
  2811.  
  2812.  
  2813. #ifdef COLOR_FILTER_DOCUMENTATION
  2814. /* 
  2815.  
  2816.     ;    color filter documentation
  2817.  
  2818.     ;this table shows that each cell has a certain sensitivity to
  2819.     ;different frequencies of light.  if you assume that all frequencies
  2820.     ;can be represented by a red, green, and blue component, you can
  2821.     ;specify the percentage sensitivity of each photocell type to
  2822.     ;each color of light.  for instance, yellow registers 81% of the
  2823.     ;red light falling on it, 98% of the green, but only 8% of the blue.
  2824.     ;
  2825.     ;the sensitivities were designed by sharp so that when you combine
  2826.     ;cells in the correct manner, you can multiply adjacent combinations
  2827.     ;by a factor and subtract to get the pure color of red or blue.
  2828.     ;the cell combination happens when you scan in interleave mode.
  2829.     ;the cells are electrically combined.  then a given scan line
  2830.     ;will have the correct adjacent cells to use their formula to get
  2831.     ;a specific color.    on one scan line you can derive the red, but
  2832.     ;you have to derive the blue from the next scan line.  the result
  2833.     ;is a tricky resolution that is really closer to 1/4 what is specced.
  2834.     ;
  2835.     ;their explanation of how to derive green was fuzzy.  we do it
  2836.     ;by solving 3 adjacent cells (3 equations, 3 variables) for green.
  2837.     ;if you do that for red and blue you find yourself coming up with
  2838.     ;sharp's formula in 2 of the cases, so the reasoning is good.
  2839.     ;unfortunately, at the end green seems to be twice as bright as
  2840.     ;it should be for no known reason.    but it is proportionately correct.
  2841.  
  2842.     ;odd and even interlace fields have the same pixel combinations of:
  2843.     ;    cyg  yemg cyg  yemg cyg  yemg ... repeat for 512 total.
  2844.     ;    cymg yeg  cymg yeg  cymg yeg  ... repeat for 512 total.
  2845.     ;    cyg  yemg cyg  yemg cyg  yemg ... repeat for 512 total.
  2846.     ;    cymg yeg  cymg yeg  cymg yeg  ... repeat for 512 total.
  2847.     ;    |
  2848.     ;    |
  2849.     ;    repeat for 246 total
  2850.     ;
  2851.     ;non-interlace pixels are arranged like this:
  2852.     ;
  2853.     ;    cy ye cy ye cy ye ... repeat for 512 total.
  2854.     ;    g mg g mg g mg g  ... repeat for 512 total.
  2855.     ;    cy ye cy ye cy ye ... repeat for 512 total.
  2856.     ;    mg g mg g mg g mg ... repeat for 512 total.
  2857.     ;    |
  2858.     ;    |
  2859.     ;    repeat for 492 total
  2860.     ;
  2861.     ;a chart showing the relative percentage sensitivity of each cell type,
  2862.     ;plus their combinations and some formulas used to derive color information
  2863.     ;is present in the sharp book, "Designing with CCDs".  the important
  2864.     ;table is shown here:
  2865.  
  2866.     ;               red     green   blue
  2867.     ;---------------------------------------------------------
  2868.     ;   ye          81      98      8
  2869.     ;   cy          11      92      75
  2870.     ;   mg          50      29      51
  2871.     ;   g           11      86      8
  2872.     ;---------------------------------------------------------
  2873.     ;   ye+mg       131     127     59
  2874.     ;   cy+g        22      178     83
  2875.     ;   alpha       0.71    0.71    0.71
  2876.     ;   Subtraction 115     0.16    -0.15
  2877.     ;---------------------------------------------------------
  2878.     ;   cy+mg       61      121     138
  2879.     ;   ye+g        92      184     16
  2880.     ;   beta        0.66    0.66    0.66
  2881.     ;   Subtraction 0.33    -0.35   127
  2882.     ;---------------------------------------------------------
  2883.     ;
  2884.  
  2885.     ;here's the basic program that solves the 3 equation color combos.
  2886.     ;
  2887.     ;1 rem this program takes real world red, green, blue levels plus the value
  2888.     ;2 rem measured on a ccd cell and uses three of these combinations to come
  2889.     ;3 rem up with the factors for red, green, and blue for that type of cell.
  2890.     ;5 print
  2891.     ;6 print
  2892.     ;10 input "filter1 (cyg, cymg, yeg, yemg, etc.)";f1$
  2893.     ;15 f1=1
  2894.     ;20 input "red factor";rf1
  2895.     ;30 input "green factor";gf1
  2896.     ;40 input "blue factor";bf1
  2897.     ;60 print
  2898.     ;110 input "filter2 (cyg, cymg, yeg, yemg, etc.)";f2$
  2899.     ;115 f2=1
  2900.     ;120 input "red factor";rf2
  2901.     ;130 input "green factor";gf2
  2902.     ;140 input "blue factor";bf2
  2903.     ;150 print
  2904.     ;210 input "filter3 (cyg, cymg, yeg, yemg, etc.)";f3$
  2905.     ;215 f3=1
  2906.     ;220 input "red factor";rf3
  2907.     ;230 input "green factor";gf3
  2908.     ;240 input "blue factor";bf3
  2909.     ;250 print
  2910.     ;400 rem here's what we have inputted:
  2911.     ;402 rem f1*f1$ = rf1*r+gf1*g+bf1*b
  2912.     ;404 rem f2*f2$ = rf2*r+gf2*g+bf2*b
  2913.     ;406 rem f3*f3$ = rf3*r+gf3*g+bf3*b
  2914.     ;407 rem f1$, f2$, f3$ are the names of the filters read but in the final
  2915.     ;408 rem equation you will multiply the value read by the factors f1, f2, f3.
  2916.     ;409 rem
  2917.     ;410 rem now a normal solution to a 3 equation, 3 variable situation.
  2918.     ;415 rem
  2919.     ;420 rem first get rid of the blue and make 2 equations
  2920.     ;430 rf4=rf3*bf1/bf3
  2921.     ;431 gf4=gf3*bf1/bf3
  2922.     ;433 f4=f3*bf1/bf3
  2923.     ;435 rf4=rf1-rf4:gf4=gf1-gf4
  2924.     ;436 rem
  2925.     ;437 rem now: f1*f1$-f4*f3$ = rf4*r+gf4*g
  2926.     ;438 rem
  2927.     ;440 rf5=rf3*bf2/bf3
  2928.     ;441 gf5=gf3*bf2/bf3
  2929.     ;443 f5=f3*bf2/bf3
  2930.     ;445 rf5=rf2-rf5:gf5=gf2-gf5
  2931.     ;446 rem
  2932.     ;447 rem now: f2*f2$-f5*f3$ = rf5*r+gf5*g
  2933.     ;448 rem
  2934.     ;450 rem so now we have only 2 equations to worry about:
  2935.     ;451 rem f1*f1$-f4*f3$ = rf4*r+gf4*g
  2936.     ;452 rem f2*f2$-f5*f3$ = rf5*r+gf5*g
  2937.     ;453 rem
  2938.     ;454 rem solve them to get rid of green.
  2939.     ;460 rf6=rf4-rf5*gf4/gf5
  2940.     ;462 f6=f2*gf4/gf5
  2941.     ;464 f7=f4-f5*gf4/gf5
  2942.     ;468 rem now: f1*f1$-f6*f2$-f7*f3$ = rf6*r
  2943.     ;470 rem
  2944.     ;472 rem solve to get the three factors to deduce red
  2945.     ;474 redf1=f1/rf6:redf2=-f6/rf6:redf3=-f7/rf6
  2946.     ;476 rem
  2947.     ;480 rem now do the green. solve to get rid of red.
  2948.     ;481 gf6=gf4-gf5*rf4/rf5
  2949.     ;482 f6=f2*rf4/rf5
  2950.     ;484 f7=f4-f5*rf4/rf5
  2951.     ;488 rem now: f1*f1$-f6*f2$-f7*f3$ = gf6*g
  2952.     ;490 rem
  2953.     ;500 greenf1=f1/gf6:greenf2=-f6/gf6:greenf3=-f7/gf6
  2954.     ;501 rem
  2955.     ;1400 rem now back to the beginning to solve for blue
  2956.     ;1401 rem
  2957.     ;1402 rem f1*f1$ = rf1*r+gf1*g+bf1*b
  2958.     ;1404 rem f2*f2$ = rf2*r+gf2*g+bf2*b
  2959.     ;1406 rem f3*f3$ = rf3*r+gf3*g+bf3*b
  2960.     ;1420 rem first get rid of the green and make 2 equations
  2961.     ;1430 rf4=rf3*gf1/gf3
  2962.     ;1431 bf4=bf3*gf1/gf3
  2963.     ;1433 f4=f3*gf1/gf3
  2964.     ;1435 rf4=rf1-rf4:bf4=bf1-bf4
  2965.     ;1436 rem
  2966.     ;1437 rem now: f1*f1$-f4*f3$ = rf4*r+bf4*b
  2967.     ;1438 rem
  2968.     ;1440 rf5=rf3*gf2/gf3
  2969.     ;1441 bf5=bf3*gf2/gf3
  2970.     ;1443 f5=f3*gf2/gf3
  2971.     ;1445 rf5=rf2-rf5:bf5=bf2-bf5
  2972.     ;1446 rem
  2973.     ;1447 rem now: f2*f2$-f5*f3$ = rf5*r+bf5*b
  2974.     ;1448 rem
  2975.     ;1450 rem so now we have only 2 equations to worry about:
  2976.     ;1451 rem f1*f1$-f4*f3$ = rf4*r+bf4*b
  2977.     ;1452 rem f2*f2$-f5*f3$ = rf5*r+bf5*b
  2978.     ;1453 rem
  2979.     ;1454 rem solve them to get rid of red.
  2980.     ;1460 bf6=bf4-bf5*rf4/rf5
  2981.     ;1462 f6=f2*rf4/rf5
  2982.     ;1464 f7=f4-f5*rf4/rf5
  2983.     ;1468 rem now: f1*f1$-f6*f2$-f7*f3$ = bf6*b
  2984.     ;1470 rem
  2985.     ;1474 bluef1=f1/bf6:bluef2=-f6/bf6:bluef3=-f7/bf6
  2986.     ;10000 print
  2987.     ;10010 print "red = ";redf1;f1$;",";redf2;f2$;",";redf3;f3$
  2988.     ;10020 print "green = ";greenf1;f1$;",";greenf2;f2$;",";greenf3;f3$
  2989.     ;10030 print "blue = ";bluef1;f1$;",";bluef2;f2$;",";bluef3;f3$
  2990.     ;2000 goto 1
  2991.  
  2992. */
  2993. #endif /* COLOR_FILTER_DOCUMENTATION */
  2994.  
  2995.