{Begin SubSec Color Graphics}
{Title Color Graphics}
{Text


{Begin Note}
Revised: 21 Dec. 1982 by Richard R. Burton (Burton.pa)
converted to IM format on Thu, 4 Aug 83 16:14 PDT by Sannella.pa
{End Note}


{it
Note:  This section describes the Interlisp-D facilities for using a color display.  To use these facilities you need to have a Xerox 1100 or Xerox 1132 with a color display attached, and you must load in the LispUsers files {lisp COLOR.DCOM} and {lisp LLCOLOR.DCOM} (automatically loaded by {lisp COLOR.DCOM}).
}



The color boards on the Xerox 1100 and the Xerox 1132 differ in design.  The Xerox 1100 board supports 4 bits per pixel color.  The Xerox 1132 supports 4 or 8 bits per pixel.  {note Actually the board supports 24 bpp also but Interlisp-D doesn't yet.}  All of the user's code should be written in higher level machine independent functions. 

Both color boards produce an image that is 640 pixels wide by 480 pixels high.   The image can be thought of as a paint-by-number painting where the number of a pixel is its value.  The number of bits per pixel (4 on the Xerox 1100, 4 or 8 on the Xerox 1132) determines the number of difference colors that can be displayed at one time.  When there are 4 bpp, 16 colors can be displayed at once.  When there are 8 bpp, 256 colors can be displayed at once.  A mapping table called a "color map" determines what color actually appears for each pixel value.   A color map gives the color in terms of how much of the three primary colors (red, green and blue) displayed on the screen for each possible pixel value.  In the following sections, the notions of "color map", and "color" are described.



{Begin SubSec Color Bitmaps}
{Title Color Bitmaps}
{Text

A "color bitmap"{index color bitmaps} is actually just a bitmap that allows more than one bit per pixel.  To test whether a bitmap {arg X} is a "color bitmap", use the following form:

{lispcode (NEQ (fetch (BITMAP BITMAPBITSPERPIXEL) of {arg X}) 1)}

{note In multiple bit per pixel bitmaps, the bits which represent a pixel are stored contiguously.}

Color bitmaps are created by calling {fn BITMAPCREATE} ({PageRef Fn BITMAPCREATE}) with a {arg BITSPERPIXEL} argument of anything other than 1 or {lisp NIL}.  Currently, any value of {arg BITSPERPIXEL} except 1, 4, 8 or {lisp NIL} (defaults to 1) will cause an error.


A 4 bit per pixel color screen bitmap uses approximately 76k of storage.  There is only one such bitmap.  The following function provides access to it:

{FnDef {Name COLORSCREENBITMAP} {Args }
{Text
Returns the color bitmap that is being or will be displayed on the color display.  This will be {lisp NIL} if the color display has never been turned on (see {fn COLORDISPLAY}, {PageRef Fn COLORDISPLAY}). 
}}


{VarDef {Name WHOLECOLORDISPLAY}
{Text
A global variable set to a {lisp REGION} that covers the entire color display screen.  Currently this is {lisp (CREATEREGION 0 0 640 480)}.
}}


{VarDef {Name COLORSCREENWIDTH}
{Text
The width of the color display.  Currently 640.
}}


{VarDef {Name COLORSCREENHEIGHT}
{Text
The height of the color display.  Currently 480.
}}


}{End SubSec Color Bitmaps}




{Begin SubSec Color Specifications}
{Title Color Specifications}
{Text



{Tag ColorSpecifications}


A color map maps a color number (from 0 to  2{super {arg BITSPERPIXEL}}-1) into the intensities of the three color guns (red, green and blue).  Each entry in the color map has 8 bits for each of the primary colors allowing 256 levels per primary or 2{super 24} possible colors (not all of which are distinct to the human eye).  Within Interlisp-D programs, colors can be manipulated as numbers, red-green-blue triples, names, or hue-lightness-saturation triples.  Any function that takes a color will accept any of the different specifications.

If a number is given, it will be the color number used in the operation.  It must be valid for the color bitmap used in the operation.  (Since all of the routines that use a color need to determine its number, it is fastest to use numbers for colors.  {fn COLORNUMBERP} described below provides a way to translate into numbers from the other representations.)

A red-green-blue (RGB) triple is a list of three numbers between 0 and 255.  The first element gives the intensity for RED, the second for GREEN and the third for BLUE.  When an RGB triple is used, the current color map is searched to find the color with the correct intensities.  If none is found, an error is generated. (That is, no attempt is made by the system to assign color numbers to intensities automatically.)  Example of an RGB triple is (255 255 255) which gives the color white.  The record {lisp RGB} with fields {lisp RED}, {lisp GREEN}, and {lisp BLUE} is provided to manipulate RGB triples.

A color name is an atom that is on the association-list {var COLORNAMES}.{index COLORNAMES Var}  The {lisp CDR} of the color name's entry will be used as the color corresponding to the color name.  This can be any of the other representations.  (Note:  It can even be another color name.  Loops in the name space such as would be caused by putting {lisp '(RED . CRIMSON)} and {lisp '(CRIMSON . RED)} on {var COLORNAMES} are {it not} checked for by the system.)  Several color names are available in the initial system and are intended to allow color programs written by different users to coexist.  These are:

{Begin Table color names}

{COLUMN}	{COLUMN}	{COLUMN}

{First name}	{Next RGB}		{Next number in default color map}

{First {lisp BLACK}}	{Next {lisp (0 0 0)}}	{Next 0}

{First {lisp BLUE}}	{Next {lisp (0 0 255)}}	{Next 1}

{First {lisp GREEN}}	{Next {lisp (0 255 0)}}	{Next 2}

{First {lisp CYAN}}	{Next {lisp (0 255 255)}}	{Next 3}

{First {lisp RED}}		{Next {lisp (255 0 0)}}	{Next 4}

{First {lisp MAGENTA}}	{Next {lisp (255 0 255)}}	{Next 5}

{First {lisp YELLOW}}	{Next {lisp (255 255 0)}}	{Next 6}

{First {lisp WHITE}}	{Next {lisp (255 255 255)}} {Next 7}

{End Table color names}


A hue-lightness-saturation triple is a list of three numbers.  The first number (hue) is between 0 and 355 and indicates a position in degrees on a color wheel (blue at 0, red at 120 and green at 240).  The second (lightness) is a {lisp FLOATP} between 0 and 1 which indicates how much total intensity is in the color.  The third (saturation) is a {lisp FLOATP} between 0 and 1 which indicates how disparate the three primary levels are.  The record {lisp HLS} with fields {lisp HUE}, {lisp LIGHTNESS}, and {lisp SATURATION} is provided to manipulate HLS triples.  Example: the color blue is represented in HLS notation by (0 .5 1.0).


{FnDef {Name COLORNUMBERP} {Args COLOR BITSPERPIXEL NOERRFLG}
{Text
Returns the color number (offset into the screen color map) of {arg COLOR}.  {arg COLOR} should be either (1) a positive number less than the maximum number of colors, (2) a color name, (3) an RGB triple, or (4) an HLS triple.  If {arg COLOR} is one of the above and is found in the screen colormap, its color number in the screen color map is returned.  If not, an error is generated unless {arg NOERRFLG} is non-{lisp NIL}, in which case {lisp NIL} is returned.
}}



{FnDef {Name RGBP} {Args X}
{Text
Returns {arg X} if {arg X} is an RGB triple; {lisp NIL} otherwise.
}}


{FnDef {Name HLSP} {Args X}
{Text
Returns {arg X} if {arg X} is an HLS triple; {lisp NIL} otherwise.
}}



}{End SubSec Color Specifications}



{Begin SubSec Color Maps}
{Title Color Maps}
{Text

The screen color map holds the information about what color is displayed on the color screen for each pixel value in the color screen bitmap.  The values in the current screen color map may be changed and this change will be reflected in the colors being displayed at the next vertical retrace (approximately 1/30 of a second).  Changing the color map can be used to get dramatic effects.  


{FnDef {Name COLORMAPCREATE} {Args INTENSITIES BITSPERPIXEL}
{Text
Creates a color map for a screen that has {arg BITSPERPIXEL} bits per pixel.  If {arg BITSPERPIXEL} is {lisp NIL}, the number of bits per pixel is taken from the current color display setting.  {arg INTENSITIES} specifies the initial colors that should be in the map.  If {arg INTENSITIES} is not {lisp NIL}, it should be a list of color specifications (other than color numbers), e.g. the list of RGB triples returned by the function {fn INTENSITIESFROMCOLORMAP} (below).  If {arg INTENSITIES} is {lisp NIL}, the default is the value of {var \DEFAULTCOLORINTENSITIES}{index \DEFAULTCOLORINTENSITIES Var} (if {arg BITSPERPIXEL} is 4) or {var \DEFAULT8BITCOLORINTENSITIES}{index \DEFAULT8BITCOLORINTENSITIES Var} (if {arg BITSPERPIXEL} is 8). 
}}



{FnDef {Name COLORMAPP} {Args COLORMAP? BITSPERPIXEL}
{Text
Returns {arg COLORMAP?} if it is a color map that has {arg BITSPERPIXEL} bits per pixel; {lisp NIL} otherwise.  If {arg BITSPERPIXEL} is {lisp NIL}, it returns {arg COLORMAP?} if it is either a 4 bits per pixel or an 8 bits per pixel colormap.
}}



{FnDef {Name INTENSITIESFROMCOLORMAP} {Args COLORMAP}
{Text
Returns a list of the intensity levels of {arg COLORMAP} (default is {lisp (SCREENCOLORMAP)}) in a form accepted by {fn COLORMAPCREATE}.  This list can be written on file and thus provides a way of saving color map specifications.
}}



{FnDef {Name COLORMAPCOPY} {Args COLORMAP BITSPERPIXEL}
{Text
If {arg COLORMAP} is a color map, it returns a color map that contains the same color intensities as {arg COLORMAP}; otherwise it returns a color map with default color values.
}}



{FnDef {Name SCREENCOLORMAP} {Args NEWCOLORMAP}
{Text
Reads and sets the color map that is used by the color display.  If {arg NEWCOLORMAP} is non-{lisp NIL}, it should be a color map and {fn SCREENCOLORMAP} sets the system color map to be that color map.  Returns the previous value of the screen color map.  If {arg NEWCOLORMAP} is {lisp NIL}, the current screen color map is returned without change.
}}



{FnDef {Name MAPOFACOLOR} {Args PRIMARIES}
{Text
Returns a color map which is different shades of one or more of the primary colors.  For example, {lisp (MAPOFACOLOR '(RED GREEN BLUE))} gives a color map of different shades of gray; {lisp (MAPOFACOLOR 'RED)} gives different shades of red.
}}



The following functions are provided to access and change the intensity levels in a color map.


{FnDef {Name SETCOLORINTENSITY} {Args COLORMAP COLORNUMBER COLORSPEC}
{Text
Sets the primary intensities of color number {arg COLORNUMBER} in the color map {arg COLORMAP} to the ones specified by {arg COLORSPEC}.  {arg COLORSPEC} can be either an RGB triple, an HLS triple or a color name.  Returns {lisp NIL}.
}}



{FnDef {Name COLORLEVEL} {Args COLORMAP COLORNUMBER PRIMARYCOLOR NEWLEVEL}
{Text
Sets and reads the intensity level of the primary color {arg PRIMARYCOLOR} (either {lisp RED}, {lisp GREEN} or {lisp BLUE}) for the color number {arg COLORNUMBER} in the color map {arg COLORMAP}.  If {arg NEWLEVEL} is a number between 0 and 255, it is set.  The previous value of the intensity of {arg PRIMARYCOLOR} is returned.
}}



{FnDef {Name ADJUSTCOLORMAP} {Args PRIMARYCOLOR DELTA COLORMAP}
{Text
Adds {arg DELTA} to the intensity of the primary color {arg PRIMARYCOLOR} (either {lisp RED}, {lisp GREEN} or {lisp BLUE}) for every color number in {arg COLORMAP}.
}}



{FnDef {Name ROTATECOLORMAP} {Args COLORMAP STARTCOLOR THRUCOLOR}
{Text
Rotates a sequence of colors in {arg COLORMAP}.  The rotation moves the intensity values of color number {arg STARTCOLOR} into color number {arg STARTCOLOR}+1, the intensity values of color number {arg STARTCOLOR}+1 into color number {arg STARTCOLOR}+2, etc. and {arg THRUCOLOR}'s values into {arg STARTCOLOR}.
}}


{FnDef {Name EDITCOLORMAP} {Args VAR NOQFLG}
{Text
Allows interactive editing of a color map.  If {arg VAR} is an atom whose value is a color map, its value is edited.  Otherwise a new color map is created and edited.  The color map being edited is made the screen color map while the editing is taking place so that its effects can be observed.  The edited color map is returned as the value.

If {arg NOQFLG} is {lisp NIL} and the color display is on, the user is asked if they want a test pattern of colors.  A yes response will cause the function {fn SHOWCOLORTESTPATTERN} to be called which will display a test pattern with blocks of each of the possible colors.


The user is prompted for the location of a color control window to be placed on the black and white display.  This window allows the value of any of the colors to be changed.  The color number of the color being edited is in the upper left part of the window.  Six bars are displayed.  The right three bars give the color intensities for the three primary colors of the current color number.  The left three bars give the value of the color's Hue, Lightness and Saturation parameters. These levels can be changed by positioning the cursor in one of the bars and pressing the {lisp LEFT} button.  While the {lisp LEFT} button is down, the value of that parameter will track the Y position of the cursor.  When the {lisp LEFT} button is released, the color tracking stops.  The color being edited is changed by pressing the {lisp MIDDLE} button while the cursor is in the interior of the edit window.  This will bring up a menu of color numbers.  Selecting one sets the current color to the selected color.


The color being edited can also be changed by selecting the menu item "PickPt".  This will switch the cursor onto the color screen and allow the user to select a point from the color screen.  It will then edit the color of the selected point.

To stop the editing, move the cursor into the title of the editing window and press the {lisp MIDDLE} button.  This will bring up a menu.  Select {lisp STOP} to quit. 
}}



{Begin Note}

Format of the Xerox 1100 color maps

The form of a color map as desired by the hardware should be of no interest to users but is documented here because as far as I know it is documented no where else.

The hardware expects a pointer to a 60 word table whose base must be 16 word aligned.  The first two words must be 0.  Words 2 thru 49 give the color intensity levels.  Each word can be used to set any primary color of any color number but the Interlisp-D implementation (and all others that I know of) use words 2-4 for color 0, words 5-7 for color 1, etc.  The format of each word is as follows:
bits 0-3 (leftmost): color number indicating which color this sets.
bit 4: set if this entry is for RED gun.
bit 5: set if this entry is for GREEN gun.
bit 6: set if this entry is for BLUE gun.
bit 7: ignored
bits 8-15 (right byte):  Intensity level for the primary gun.
Words 50 thru 59 must be 0.

In Interlisp-D, 4 additional words are set aside in each color map to insure the 16 word alignment.
{End Note}



}{End SubSec Color Maps}




{Begin SubSec Turning the Color Display On and Off}
{Title Turning the Color Display On and Off}
{Text


The color display can be turned on and off.  While the color display is on, the memory used for the color display screen bitmap is locked down and a significant amount of processing time (35% on the Xerox 1100) is used to drive the color display.  


{FnDef {Name COLORDISPLAYP} {Args }
{Text
Returns the current color map if the color display is on; otherwise {lisp NIL}.
}}


{FnDef {Name COLORDISPLAY} {Args COLORMAP BITSPERPIXEL CLEARSCREENFLG}
{Text
If {arg COLORMAP} is {lisp NIL}, it turns off the color display.  If {arg COLORMAP} is non-{lisp NIL}, it turns on the color display allocating {arg BITSPERPIXEL} bits per pixel.  If {arg COLORMAP} is a color map, it is used as the screen color map.  If {arg CLEARSCREENFLG} is non-{lisp NIL}, all of the bits in the color screen are set to 0.

Turning on the color display requires allocating and locking down the memory necessary to hold the color display screen bitmap and the system color map.  Turning the color display off frees this memory.

{note if COLORMAP is of type COLORMAPP or 8BITCOLORMAP, it is used as the screen color map.}
}}



}{End SubSec Turning the Color Display On and Off}




{Begin SubSec Printing and Drawing in Color}
{Title Printing and Drawing in Color}
{Text

The current color implementation allows display streams to operate on color bitmaps.  The following two functions set the color in which a display stream prints or draws:


{FnDef {Name DSPCOLOR} {Args COLOR DISPLAYSTREAM}
{Text
Sets the foreground color of a display stream.  Returns the previous foreground color.  If {arg COLOR} is {lisp NIL}, it returns the current foreground color without changing anything.  The default foreground color is 7, which is white in the default color map.
}}


{FnDef {Name DSPBACKCOLOR} {Args COLOR DISPLAYSTREAM}
{Text
Sets the background color of a display stream.  Returns the previous background color.  If {arg COLOR} is {lisp NIL}, it returns the current background color without changing anything.  The default background color is 0 which is black in the default color map.
}}



{fn BITBLT}, the line and curve drawing routines and the printing routines know how to operate on a display stream that has a color bitmap as its destination.  Following are some notes about them.


{Begin LabeledList notes}

{Name {fn BITBLT} ({PageRef Fn BITBLT})}
{Text
When {fn BITBLT}ing from a color bitmap onto another color bitmap with the same bits per pixel, the operations {lisp PAINT}, {lisp INVERT} and {lisp ERASE} are done on a bit level; not on a pixel level.  Thus painting color 3 onto color 10 will result in color 11.

When {fn BITBLT}ing from a black and white bitmap onto a color bitmap, the 1 bits will appear in the {fn DSPCOLOR} and the 0 bits in {fn DSPBACKCOLOR}.  Currently, {lisp REPLACE} is the only operation that is supported {fn BITBLT}ing from black and white to color.  This operation is fairly expensive; if the same bitmap is going to be put up several times in the same color it is faster to create a color copy then blt the color copy.

If the {arg SOURCETYPE} is {lisp TEXTURE} and the {arg DESTINATIONBITMAP} is a color bitmap, the {arg TEXTURE} argument is taken to be a color.  Thus, to fill an area with the color {lisp BLUE}, do:

{lispcode
(BITBLT NIL NIL NIL {arg COLORBITMAP} 50 75 100 200
        'TEXTURE 'REPLACE 'BLUE)}
}


{Name Curve drawing ({PageRef Fn DRAWCIRCLE})}
{Text
For the functions {fn DRAWCIRCLE}, {fn DRAWELLIPSE} and {fn DRAWCURVE}, the notion of a brush has been extended to include a color.  A brush can be a list of the form {lisp ({arg SHAPE} {arg SIZE} {arg COLOR})}.  A brush can also be a bitmap, which can be color bitmap.
}


{Name Line drawing ({PageRef Fn DRAWTO})}
{Text
The line drawing functions have been extended to take another argument which is the color the line is to appear in if the destination of the display stream is a color bitmap.  If the {arg COLOR} argument is {lisp NIL}, the {fn DSPCOLOR} of the display stream is used.
}


{Name Printing}
{Text
Printing only works (currently) in {fn REPLACE} mode.  The characters will have a foreground color of {fn DSPCOLOR} and a background of {fn DSPBACKCOLOR}.  The first time a character is printed in a new color, the color images corresponding to the current font are calculated and cached.  Thus the first character may take a while to appear but succeeding characters print quickly.  
}

{End LabeledList notes}



}{End SubSec Printing and Drawing in Color}




{Begin SubSec Using the Cursor on the Color Screen}
{Title Using the Cursor on the Color Screen}
{Text

The cursor can be moved to the color screen.  While on the color screen, the cursor is placed using {lisp XOR} mode, thus with some color maps it may be hard to see.  It is automatically taken down whenever an operation is performed that changes any bits on the color screen.  While the cursor is on the color screen, the black and white cursor is cleared.

{fnDef {Name CHANGECURSORSCREEN} {Args SCREENBITMAP}
{Text
{arg SCREENBITMAP} must be either the value of {lisp (COLORSCREENBITMAP)} or the value of {lisp (SCREENBITMAP)}.  {fn CHANGECURSORSCREEN} moves the cursor onto the specified screen.  The value returned is the screen bitmap that the cursor was on before {fn CHANGECURSORSCREEN} was called.
}}


}{End SubSec Using the Cursor on the Color Screen}




{Begin SubSec Miscellaneous Color Functions}
{Title Miscellaneous Color Functions}
{Text

The following functions provide some common operations on color bitmaps and display streams.


{FnDef {Name COLORFILL}  {Args REGION COLORNUMBER COLORBITMAP OPERATION}
{Text
Fills the region {arg REGION} in {arg COLORBITMAP} with the color {arg COLORNUMBER}, using the operation {arg OPERATION}.
}}



{FnDef {Name COLORFILLAREA}  {Args LEFT BOTTOM WIDTH HEIGHT COLORNUMBER COLORBITMAP OPERATION}
{Text
Fills an area in the color bitmap with a color.
}}


{FnDef {Name COLORIZEBITMAP}  {Args BITMAP 0COLOR 1COLOR BITSPERPIXEL}
{Text
Creates and returns a color bitmap copying the black and white bitmap {arg BITMAP}.  The returned color bitmap will have color number {arg 1COLOR} in those pixels of {arg BITMAP} that were 1 and {arg 0COLOR} in those pixels of {arg BITMAP} that were 0.  This provides a way of producing a color bitmap from a black and white bitmap.  Note: this is a fairly expensive operation in terms of both time and space.
}}


}{End SubSec Miscellaneous Color Functions}




{Begin SubSec Demonstration programs}
{Title Demonstration programs}
{Text


{it
The following functions provide some demonstrations of the color display.  These are available in the Lispusers file {lisp COLORDEMO.DCOM}.  
}


{FnDef {Name COLORDEMO} {Args }
{Text
Brings up a menu of color demonstration programs.  The system will cycle through the entries on the menu automatically, allowing each to run for a small fixed amount of time (typically 40 seconds).  Selecting one of the entries in the menu will cause it to start that program.
}}



{FnDef {Name COLORDEMO1} {Args }
{Text
Runs the Interlisp-D logo demonstration until a button is pressed then adds {fn COLORKINETIC}.  The {lisp MIDDLE} button will bring up a menu that allows changing the speed of rotation or editting the color map.  The {lisp LEFT} button will rotate the color map in the kinetic area.
}}



{FnDef {Name COLORDEMO2} {Args SIZE}
{Text
Puts up a test pattern of size {arg SIZE}, then rotates the color map.  The speed of rotation of the color map is determined by the Y position of the cursor.  The {lisp MIDDLE} button will bring up a menu that allows editing of the color map or changing the color map to a map of different shades of one color.
}}



{FnDef {Name COLORKINETIC} {Args REGION FIRSTCOLOR LASTCOLOR}
{Text
Runs color kinetic in a region {arg REGION} of the color display using colors {arg FIRSTCOLOR} through {arg LASTCOLOR}.
}}



{FnDef {Name TUNNEL} {Args SPEED}
{Text
Draws a series of concentric rectangles of increasing size in increasing color numbers.  {arg SPEED} determines the size of the rectangles.  This can then be "run" by calling {fn ROTATEIT} described below.
}}



{FnDef {Name MINESHAFT} {Args N OUTFLG}
{Text
Draws a series of concentric rectangles of size {arg N} in increasing color numbers.  {arg OUTFLG} determines whether the color numbers increase or decrease.  This can then be "run" by calling {fn ROTATEIT} described below.
}}



{FnDef {Name WELL} {Args N}
{Text
Draws a series of concentric circles on the color screen in increasing color numbers.  The circles will be of size {arg N}.  This can then be "run" by calling {fn ROTATEIT} described below.
}}



{FnDef {Name SHOWCOLORTESTPATTERN} {Args BARSIZE}
{Text
Displays a pattern of colors on the color display.  This is useful when editing a color map.  The pattern has squares of the 16 possible colors layed out in two rows at the top of the screen.  Colors 0 through 7 in the top row.  Colors 8 through 15 in the next row.  The bottom part of the screen is then layered with bars of {arg BARSIZE} width with the consecutive color numbers.  The pattern is designed so that every color has a border with every other color (unless {arg BARSIZE} is too large to allow room for every color - about 20). 
}}



{FnDef {Name ROTATEIT} {Args BEGINCOLOR ENDCOLOR WAIT}
{Text
Goes into an infinite loop rotating the screen color map.  The colors between {arg BEGINCOLOR} (default 0) and {arg ENDCOLOR} (default maximum color) are rotated.  If {arg WAIT} is given, {lisp (DISMISS {arg WAIT})} is called each time the color map is changed.  This provides an easy way of "animating" screen images.
}}



{it
Note:  The following function is available in the Lispusers file {lisp COLORPOLYGONS.DCOM}.
}


{FnDef {Name COLORPOLYDEMO} {Args COLORDS}
{Text
Runs a version of the Polygons program on the color screen.
}}



}{End SubSec Demonstration programs}




}{End SubSec Color Graphics}