From hpfloat!marysue Wed Dec  2 13:37 MST 1987
Received: by hpfclw.HP.COM; Wed, 2 Dec 87 13:37:56 mst
Received: from hpfloat.HP.COM by hpfclw.HP.COM; Wed, 2 Dec 87 13:37:35 mst
Received: by hpfloat.HP.COM; Wed, 2 Dec 87 13:35:30 mst
Date: Wed, 2 Dec 87 13:35:30 mst
From: Mary Sue Rowan <hpfloat!marysue>
Return-Path: <hpfloat!marysue>
Message-Id: <8712022035.AA14402@hpfloat.HP.COM>
To: hpfloat!bayes
Status: R


                   PaintJet COLOR RASTER DUMP UTILITY
                    Internal Reference Specification
                             Mary Sue Rowan
                                12/1/87 

I.  General description

    A.  CSUB

        The utility is a CSUB.  See the ERS for information on how to use it.
         
    B.  PaintJet requirements

        For PaintJet to print in color, multiple color "planes" must be 
        enabled.  Because the data from the system color map comes in rgb 
        values, it was most convenient to have 3 "planes" for PaintJet, and 
        thus get 8 basic colors.  Dithering can provide the added colors.  
        A dotrow of data must be sent for each plane, before the carriage 
        can be advanced to the next dotrow.  See the PaintJet Manual for 
        more details.
           
    C.  Two algorithms

        PaintJet is capable of doing its own dithering at certain resolutions.  
        This capability was not utilized by the driver, however, because it is 
        only activated at certain resolutions, and it was desirable to permit 
        users to access the full scope of resolutions on this device.  There
        are two types of dither algorithms available to users, the "dithering
        algorithm" (da) and the "error diffusion algorithm" (eda).


II. Dithering Algorithm
             
    A.  A 2x2 dither cell was selected for implementation, because with it, 
        a total of 125 colors is possible, and that seemed sufficient for most 
        applications.  Dither algorithms for 2x2 cells are inherently simpler 
        than for larger cells, also it was more practical for size purposes.  
        With a 2x2 dither cell, a rotated dump of a high resolution monitor 
        (1024 x 768) will almost fit on the printed page for the PaintJet. 
           
    B.  12 bits per pixel!

        Expanding each pixel to four dots, and having 3 color planes requires 
        that 12 bits of information be sent per pixel.  It means that bytes in 
        the buffer must be packed so that the top half of a dither cell (2 bits) 
        for four pixels fits into a byte in one buffer, and another buffer has 
        the lower half of the dither cell for each of those four pixels.  So, 
        for every row of pixels on the screen, six buffers of information are
        sent to the printer (2 dotrows with 3 color planes each).
         
    C.  Algorithm

        1.  The CSUB consists of a shell written in MODCAL.  This shell
            determines the type of device, and does the color map 
            transformation if necessary.  If a color device is present, the 
            system color map is examined, and a mapping of the colors in the 
            color map to the 125 possible squirt colors is performed.  Note 
            that this mapping may be many to one. 

        2.  The main work of the utility is done by a 4 assembler routines.  
            The only parameter is a pointer to the temporary graphics control
            block.
            a.  gdump_c(addr(tempgcb) -- color rotated
            b.  gdump_red_c(addr(tempgcb) -- color unrotated
            c.  gdump(addr(tempgcb) -- b&w rotated
            d.  gdump_red(addr(tempgcb) -- b&w unrotated

        3.  Each invocation of a color routine does the processing for one 
            row of pixels. Each invocation of a monochromatic routine does 
            the processing for two rows of pixels. 
       
        4.  When the device is identified and the color map is examined,
            then the dump begins.  For the normal (unrotated) dump, the 
            gdump_red_c routine is called for each row of pixels in the frame
            buffer, beginning with the top row.  This routine examines each 
            pixel, from left to right.  A pixel is examined, the color map 
            index extracted, and the mapping to the PaintJet color map is made.  
            For each four pixels that are examined, six bytes of information 
            are generated, one for each of the six buffers sent per row of 
            pixels (see # B above). 
           
        5.  For the rotated dump, the gdump_c routine is called for each 
            column of pixels in the frame buffer, beginning with the left side 
            of the screen.  
       
        6.  For dumps from monochromatic display devices, the color map 
            transformation is not done, and the driver calls the assembler 
            routines that are essentially identical to the ones used by 
            DUMP GRAPHICS and GDUMP_ROTATED (a CSUB) statements.  The main
            difference is that 4 dots per pixel are printed, so that the 
            monochromatic dumps will be the same size as the color dumps
            from displays of comparable resolution. 
        
    D.  Data structures (peculiar to the CSUB; it does use important system
        data structures such as rom_stolen and the gcb)

        1.   pixrow : array [1..2,1..3] of bigbufstrtype
             The six buffers which get filled for every pixel row.
             This is for color only.  

        2.   dgbuff : dblbufstrtype
             This is essentially the equivalent of pixrow for the mono
             dump, except it is a double length buffer because the mono
             dump routines put out two rows of information with each 
             invocation.  It is not an array of buffers, but a single
             buffer. 
       
        3.   xmap : array [0..255] of 1..125
             Each entry correlates to the entry of the same index in the
             system color map.  xmap[i] contains the index into sqtcmap,
             which would contain the dither patterns for red, green and blue 
             that will match as closely as possible syscmap[i].  
           
        4.   sqtcmap : array [1..125,1..3] of 0..15
             An array that contains the 125 colors of PaintJet for the
             2x2 dither cell.  The column index refers to rgb values.
             The 0..15 value refers to the 4 bits/pixel or the 2x2 dither
             cell.  The msb and next bit refer to the first dot row, and
             the third bit and lsb refer to the second dot row. Possible
             values are 0,7,8,9,15. 

III.  Error Diffusion Algorithm

    A.  This algorithm produces one dot per pixel.  The color of a dot 
        depends partially on the colors of dots around it, not solely on 
        its absolute DAC value.  By "diffusion", it is meant that some 
        fractional DAC value is propagated to neighboring dots.  For more 
        information on the theory, see references to the Floyd-Steinberg 
        error distribution algoritm in _Procedural Elements for Computer 
        Graphics_, by David F. Rogers, McGraw-Hill, 1975.  The original 
        algorithm referred to black and white anti-aliasing techniques, 
        but Glen Robinson has modified it for color.

    B.  This algorithm requires only 3 bits of information per pixel
        to be output to the printer, one bit for each plane (rgb).

    C.  Algorithm
 
        1.  The CSUB consists of a shell written in MODCAL.  This is the
            same shell used for the da discussed above.  No color map 
            transformation is necessary for the eda, as the color map
            DAC values are used directly.  

        2.  The main work of the utility is done by 4 assembler routines.  
            All have the parameter of a pointer to the graphics control
            block.  The color routines have a parameter that is a pointer 
            to the system color map.
            a.  gdump_edc(addr(syscmap[0]),addr(tempgcb) -- color rotated
            b.  gdump_red_edc(addr(syscmap[0]),addr(tempgcb) -- color unrotated
            c.  gdump_ed(addr(tempgcb) -- b&w rotated
            d.  gdump_red_ed(addr(tempgcb) -- b&w unrotated

        3.  For all of the routines, one invocation of the assembler routine
            processes one row (or column) of the frame buffer.  The order of
            rows (columns) processed is the same as for the da, discussed
            above.

        4.  Work with two dot rows of information at a time.  For every pixel,
            check the color map entry for the red plane.  Add the DAC value
            to any existing error value that may have been previously 
            propagated to this pixel.  If the combined DAC value
            is greater than 127 (half the maximum DAC value), then turn on
            the dot, and propagate the error as follows : 
            a.  delta := DAC value - 255
            b.  neighbor to right value:= neighbor to right value +  3/8 delta
            c.  neighbor below value := neighbor below value + 3/8 delta
            d.  neighbor below and left value := neighbor below and left value +
                                                 1/4 delta
          
        5.  If the combined DAC value mentioned above is less than 127,
            do not turn on the dot, but propagate the error as follows:
            a.  neighbor to right value:= neighbor to right value +  3/8 delta
            b.  neighbor below value := neighbor below value + 3/8 delta
            c.  neighbor below and left value := neighbor below and left value +
                                                 1/4 delta
  
        6.  Repeat above steps for the green and blue DAC components.

        7.  When a row has been completed, throw out the accumulated error values
            for the row just completed, move the accumulated error for the
            second row to the first row, and reinitialize the new second row. 
            Call the routine again.    
            
        8.  Call the routine until there are no more rows to be processed
            (return to step #4).

        9.  Certain variations on the theme have been introduced to reduce
            artifacts in the image rendered by the eda.  

            a.  If the DAC value for a certain rgb component is 0 or 255, don't
                propagate the error.  Just turn the dot on if 255, or off if 0.
                This ameliorates the effect of washing out single-pixel-wide 
                lines.
            b.  Initialize the accumulated error arrays with random numbers evenly
                distributed between -8 and 8.  This is to reduce any patterning 
                effects that could occur due to the predictable nature of the 
                propagation.  The assembler routine, init_err(xval,addr(tempgcb))
                accomplishes this.  Its parameters are an integer and a pointer 
                to the graphics control block.  
                            

     D. Data Structures  

        1.  The eda uses the pixrow and dgbuff structures discussed above.
            However, instead of all six buffers of pixrow, it uses the first
            three, holding the first index constant (pixrow[1,*]).

        2.  accum_err_one,accum_err_two,
                 temp_err : pack array[1..3,0..(biggest_xval+1)] of word

            These structures store the accumulated error values that get
            propagated.  Note that the second array index ranges from
            0..biggest_xval+1.  The 0th and last elements are not really
            used; they are just there to hold the address space.  They act
            as a buffer against address errors when accessing the lower left 
            neighbor at the beginning of the row, and the right neighbor at 
            the end of the row.  This saves from having to do range checking 
            to avoid accessing those extreme locations.


IV.  The GCB
 
     The gcb is used heavily.  It is a graphics subsystem global that stores
     display-specific constants as well as pointers to system data structures.
     It also reserves space for temporary addresses and data used by the
     utility.  Below is a mapping of how these temporaries are used.

     A.  For both algorithms:
         rgltemp1 = # chars in buffers before calling the assembler routines
                      (the initial escape sequences)
         rgltemp2 = row offset for pixrow buffers
         rgltemp3 = plane offset for pixrow buffers

         addr1 = location of black + white buffers (dgbuff) (specifically 
                  points to the location after the escape sequence)
         addr2 = location of pixrow[1,1].c[1]
         

     B.  For da:
         rgltemp4 = running count in the pixrow buffers, aliased as 
                     count_gdrc(a6) in assembler routines
         rgltemp5 = switch in rotated dither routine  
          
         addr3 = location of sqtcmap[1,1]
         addr4 = location of xmap[0]


     C.  For eda:

         rgltemp4 = row offset for the accumulated error arrays
         rgltemp5 = indicates if prtbackground is on or off         

         addr3 = location of accum_err_one[1,1]
         addr4 = location of accum_err_two[1,1]

      


