[GPF Home Page]
NAME
M_color(3) - [M_color] a Fortran module that lets you convert between common color models (LICENSE:PD)
SYNOPSIS

   use M_color, only : &

      & hue, &
      & closest_color_name, &
      & color_name2rgb, &
      & rgbmono
DESCRIPTION

Fortran color module M_color

Highly accurate color conversions are a tricky business, and color is a complex topic; but these simplified conversions between common color models work quite well for basic conversions.

Typically the only user routine called is HUE(3f). HUE(3f) is a single routine that interfaces to all the private low-level color conversion routines to convert a color's components from one color model to another. HUE(3f) converts between the following color models:

  • RGB - Red, Green, Blue (color TV monitors)
  • HLS - Hue, Lightness, Saturation
  • CMY - Cyan, Magenta, Yellow (pigment-based printing devices)
  • HSV - Hue, Saturation, Value
  • YIQ - Broadcast TV color system

In addition to the reversible color model conversions there are a few other user-callable color-related procedures:

CLOSEST_COLOR_NAME:  given RGB values, try to find closest named color
COLOR_NAME2RGB:  given a color name, return RGB color values in range 0 to 100
RGBMONO:  convert RGB colors to a reasonable grayscale

2*N Design of the module

The rest of the library is composed of PRIVATE procedures. For each color model supported the general idea of the module is that there are two routines for each color model:

  • One converts that model to the RGB model
  • The other converts from RGB to that model

This allows conversions between all color models with only 2*N routines. That is, to go from model A to model B the module would internally make two calls:

    call modelA2rgb(...)
    call rgb2modelB(...)

The resulting internal routines that result are:

  • HLSRGB given hue, lightness, saturation calculate red, green, and blue components
    • RGBVAL ensure a value is in the appropriate range and quadrant
  • HVSRGB given hue, saturation, value calculate red, green, and blue components
  • CMYRGB given cyan, magenta, and yellow components calculate red, green, and blue components
  • YIQRGB given luma(gray scale), orange-blue chrominance, and purple-green chrominance components calculate red, green, and blue components
  • RGBHVS given red, green, blue values calculate hue, value, and saturation components
  • RGBHLS given red, green, blue values calculate hue, lightness, and saturation components
  • RGBCMY given red, green, blue values calculate cyan, magenta, yellow components
  • RGBYIQ given red, green, blue values calculate luma(gray scale), orange-blue chrominance, and purple-green chrominance components
EXAMPLE

Sample program:

program demo_M_color use M_color, only : hue use M_color, only : closest_color_name use M_color, only : color_name2rgb use M_color, only : rgbmono implicit none character(len=100) :: string ! at least 20 characters character(len=20) :: name character(len=20) :: echoname real :: red,green,blue real :: gray integer :: ierr ! find the names of colors given RGB values write(*,*)'Find names given values' call closest_color_name( 100.0, 0.0, 0.0, string) write(*,*)trim(string) call closest_color_name( 0.0, 100.0, 0.0, string) write(*,*)trim(string) call closest_color_name( 0.0, 0.0, 100.0, string) write(*,*)trim(string) ! list colors known to colorname2rgb(3f) & corresponding RGB values write(*,*)'given names find RGB values' ! get the RGB values and English name of the color call color_name2rgb('RED',red,green,blue,echoname) ! display the English name and RGB values for the name write(*,*)echoname,int([red,green,blue]) write(*,*)'Do some conversions between RGB, HLS, and HLS' write(*,*)'and check them against expected values' ! NAME RGB(0-255) HLS(0-100) call chk('hls','red', [100, 0, 0 ], [0, 50, 100]) call chk('hls','orange', [100, 65, 0 ], [39, 50, 100]) call chk('hls','yellow', [100, 100, 0 ], [60, 50, 100]) call chk('hls','green', [0, 100, 0 ], [120, 50, 100]) call chk('hls','cyan', [0, 100, 100], [180, 50, 100]) call chk('hls','blue', [0, 0, 100], [240, 50, 100]) call chk('hls','magenta', [100, 0, 100], [300, 50, 100]) call chk('hls','black', [0, 0, 0 ], [0, 0, 0 ]) call chk('hls','white', [100, 100, 100], [0, 100, 0 ]) ! NAME RGB(0-255) HSV(0-100) call chk('hsv','red', [100, 0, 0 ], [0, 100, 100]) call chk('hsv','yellow', [100, 100, 0 ], [60, 100, 100]) call chk('hsv','green', [0, 100, 0 ], [120, 100, 100]) call chk('hsv','cyan', [0, 100, 100], [180, 100, 100]) call chk('hsv','blue', [0, 0, 100], [240, 100, 100]) call chk('hsv','magenta', [100, 0, 100], [300, 100, 100]) call chk('hsv','white', [100, 100, 100], [0, 0, 100]) call chk('hsv','black', [0, 0, 0 ], [0, 0, 0 ]) call chk('hsv','gray50', [50, 50, 50 ], [0, 0, 50 ]) call chk('hsv','silver', [75, 75, 75 ], [0, 0, 75 ]) call chk('hsv','red4', [55, 0, 0 ], [0, 100, 55 ]) call chk('hsv','olive', [50, 50, 0 ], [60, 100, 50 ]) call chk('hsv','lime', [0, 100, 0 ], [120, 100, 100]) call chk('hsv','teal', [0, 50, 50 ], [180, 100, 50 ]) call chk('hsv','navy', [0, 0, 50 ], [240, 100, 50 ]) call chk('hsv','purple', [63, 13, 94 ], [277, 87, 94 ]) call chk('hsv','magenta4',[55, 0, 55 ], [300, 100, 55 ]) call chk('hsv','maroon', [69, 19, 38 ], [338, 73, 69 ]) write(*,*)'Get some grayscale values from RGB color values' call rgbmono(100.0, 0.0, 0.0,gray,ierr); write(*,*)'red ',gray call rgbmono( 0.0,100.0, 0.0,gray,ierr); write(*,*)'green ',gray call rgbmono( 0.0, 0.0,100.0,gray,ierr); write(*,*)'blue ',gray call rgbmono(100.0,100.0, 0.0,gray,ierr); write(*,*)'Yellow ',gray call rgbmono( 0.0,100.0,100.0,gray,ierr); write(*,*)'Cyan ',gray call rgbmono(100.0, 0.0,100.0,gray,ierr); write(*,*)'Magenta ',gray call rgbmono(100.0,100.0,100.0,gray,ierr); write(*,*)'White ',gray call rgbmono( 00.0, 0.0, 0.0,gray,ierr); write(*,*)'Black ',gray call rgbmono( 50.0, 0.0, 0.0,gray,ierr); write(*,*)'Maroon ',gray call rgbmono(100.0, 50.0, 50.0,gray,ierr); write(*,*)'Pink ',gray contains subroutine chk(modelout,name,rgb,other) ! given a color convert to MODELOUT and compare to expected values character(len=*),intent(in) :: name integer,intent(in) :: rgb(3), other(3) character(len=*),intent(in) :: modelout real :: val1,val2,val3 integer :: status ! convert RGB values to MODELOUT values call hue('rgb',REAL(rgb(1)),REAL(rgb(2)),REAL(rgb(3)),& & modelout,val1,val2,val3,status) ! left-justify name to 10 characters or more write(*,'(a,1x)',advance='no') & & [ character(len=max(10,len_trim(name))) ::' '//trim(name)] write(*,'(a,1x,3(i3,1x))',advance='no') & & modelout//' EXPECTED',other write(*,'(a,1x,3(i3,1x))',advance='no') & & 'GOT',int([val1+0.5,val2+0.5,val3+0.5]) write(*,'(a,i0)')'STATUS ',status end subroutine chk end program demo_M_color
SEE ALSO

A simple interactive javascript-based color selector lets you interactively select colors.

The color wheel below was generated using a M_draw(3f) graphics library program (huegif.f90) that uses the M_color module.

HLS circle
REFERENCES
The algorithms are based on chapter 17 of "Fundamentals of Interactive Computer Graphics"; J. D. Foley and A. Van Dam.
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
RGBHLS(3fp) - [M_color] Given red, green, and blue color components calculates the hue, lightness, and saturation for a color (LICENSE:PD)
SYNOPSIS

   subroutine rgbhls(r,g,b,h,l,s,status)

    ! red component as a value of 0 to 100
    real, intent(in)  :: r
    ! green component as a value of 0 to 100
    real, intent(in)  :: g
    ! blue component as a value of 0 to 100
    real, intent(in)  :: b
    ! hue value in the range of 0 to 360 degrees
    real, intent(out) :: h
    ! lightness as a percent value from 0 to 100
    real, intent(out) :: l
    ! saturation as a percent from 0 to 100
    real, intent(out) :: s
    integer           :: status
   
DESCRIPTION
RGB values are in the range 0-100; hue is 0-360 degrees; lightness and saturation have a range of 0-100.

ColorRGBHLSSample
Red100.00.00.0050.0100.0 
Yellow100.0100.00.06050.0100.0 
Green0.0100.00.012050.0100.0 
Cyan0.0100.0100.018050.0100.0 
Blue0.00.0100.024050.0100.0 
Magenta100.00.0100.030050.0100.0 
White100.0100.0100.0(any)100.0(any) 
Black0.00.00.0(any)0.0(any) 
Maroon50.00.00.0025.0100.0 
Pink100.050.050.0075.0100.0 
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
RGBHVS(3fp) - [M_color] calculates the hue, value, & saturation for a color given in red, green, & blue components values. (LICENSE:PD)
SYNOPSIS
   subroutine rgbhvs(r,g,b,h,v,s,status)

    ! the red component as a value of 0 to 100.
    real, intent(in)  :: r
    ! the green component as a value of 0 to 100.
    real, intent(in)  :: g
    ! the blue component as a value of 0 to 100.
    real, intent(in)  :: b
    ! the hue value in the range of 0 to 360 degrees
    real, intent(out) :: h
    ! the "value" as a percent value from 0 to 100.
    real, intent(out) :: v
    ! the saturation as a percent from 0 to 100.
    real, intent(out) :: s
    integer           :: status
   
DESCRIPTION
RGBHVS() calculates the hue, value, & saturation for a color given in red, green, & blue components values.

Color Color
name
Hex (R,G,B) (H,S,V)
  Black #000000 (0,0,0) (0º,0%,0%)
  White #FFFFFF (100,100,100) (0º,0%,100%)
  Red #FF0000 (100,0,0) (0º,100%,100%)
  Lime #00FF00 (0,100,0) (120º,100%,100%)
  Blue #0000FF (0,0,100) (240º,100%,100%)
  Yellow #FFFF00 (100,100,0) (60º,100%,100%)
  Cyan #00FFFF (0,100,100) (180º,100%,100%)
  Magenta #FF00FF (100,0,100) (300º,100%,100%)
  Silver #C0C0C0 (75,75,75) (0º,0%,75%)
  Gray #808080 (50,50,50) (0º,0%,50%)
  Maroon #800000 (50,0,0) (0º,100%,50%)
  Olive #808000 (50,50,0) (60º,100%,50%)
  Green #008000 (0,50,0) (120º,100%,50%)
  Purple #800080 (50,0,50) (300º,100%,50%)
  Teal #008080 (0,50,50) (180º,100%,50%)
  Navy #000080 (0,0,50) (240º,100%,50%)
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
cmyrgb(3fp) - [M_color] calculates the cyan, magenta, and yellow components given the red, green, and blue component values. (LICENSE:PD)
SYNOPSIS
   subroutine cmyrgb(c,m,y,r,g,b,status)

    ! cyan component as a value in the range of 0 to 100
    real, intent(in)  :: c
    ! magenta component as a value in the range of 0 to 100
    real, intent(in)  :: m
    ! yellow component as a value in the range of 0 to 100
    real, intent(in)  :: y
    ! red component as a value in the range of 0 to 100
    real, intent(out) :: r
    ! green component as a value in the range of 0 to 100
    real, intent(out) :: g
    ! blue component as a value in the range of 0 to 100
    real, intent(out) :: b
    integer           :: status
   
DESCRIPTION
cmyrgb() calculates the cyan, magenta, and yellow components given the red, green, and blue component values.
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
rgbcmy(3fp) - [M_color] calculates the cyan, magenta, and yellow components given the red, green, and blue component values. (LICENSE:PD)
SYNOPSIS
   subroutine rgbcmy(r,g,b,c,m,y,status)

    ! the red component as a value in the range of 0 to 100
    real, intent(in)  :: r
    ! the green component as a value in the range of 0 to 100
    real, intent(in)  :: g
    ! the blue component as a value in the range of 0 to 100
    real, intent(in)  :: b
    ! the cyan component as a value in the range of 0 to 100
    real, intent(out) :: c
    ! the magenta component as a value in the range of 0 to 100
    real, intent(out) :: m
    ! the yellow component as a value in the range of 0 to 100
    real, intent(out) :: y
    integer           :: status
   
DESCRIPTION
Table ...

Color Color

name

(C,M,Y) ( R, G, B) Hex
  Black (100,100,100) ( 0, 0, 0) #000000
  White ( 0, 0, 0) (100,100,100) #FFFFFF
  Red ( 0,100,100) (100, 0, 0) #FF0000
  Green (100, 0,100) ( 0,100, 0) #00FF00
  Blue (100,100, 0) ( 0, 0,100) #0000FF
  Yellow ( 0, 0,100) (100,100, 0) #FFFF00
  Cyan (100, 0, 0) ( 0,100,100) #00FFFF
  Magenta ( 0,100, 0) (100, 0,100) #FF00FF
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
RGBVAL(3fp) - [M_color] is an internal private function used by hlsrgb(3fp). (LICENSE:PD)
SYNOPSIS
   subroutine rgbval(clr1,clr2,h)

    integer, intent(in) :: h ! H is the hue value in degrees
    real, intent(in) :: clr1 !
    real, intent(in) :: clr2 !
   
DESCRIPTION
Function RGBVAL(3f) is an internal private function used by hlsrgb().
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
HLSRGB(3fp) - [M_color] calculates the red, green, & blue components for a color given in hue, lightness, & saturation values. (LICENSE:PD)
SYNOPSIS
   subroutine hlsrgb (h,l,s,r,g,b,status)

    ! hue value in the range of 0 to 360 degrees
    real, intent(in)  :: h
    ! lightness as a percent value from 0 to 100.
    real, intent(in)  :: l
    ! saturation as a percent from 0 to 100.
    real, intent(in)  :: s
    ! red component as a value of 0 to 100.
    real, intent(out) :: r
    ! green component as a value of 0 to 100.
    real, intent(out) :: g
    ! blue component as a value of 0 to 100.
    real, intent(out) :: b
    integer           :: status
   
DESCRIPTION
HLSRGB() calculates the red, green, & blue components for a color given in hue, lightness, & saturation values.
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
HVSRGB(3fp) - [M_color] calculates the red, green, & blue components for a color given in hue, value, & saturation values. (LICENSE:PD)
SYNOPSIS
   subroutine hvsrgb(h,v,s,r,g,b,status)

    ! H is the hue value in the range of 0 to 360 degrees
    real, intent(in)  :: h
    ! V is the "value" as a percent value from 0 to 100.
    real, intent(in)  :: v
    ! S is the saturation as a percent from 0 to 100.
    real, intent(in)  :: s
    ! R is the red component as a value of 0 to 100.
    real, intent(out) :: r
    ! G is the green component as a value of 0 to 100.
    real, intent(out) :: g
    ! B is the blue component as a value of 0 to 100.
    real, intent(out) :: b
    integer           :: status
   
DESCRIPTION
HVSRGB() calculates the red, green, & blue components for a color given in hue, value, & saturation values.
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
YIQRGB(3fp) - [M_color] Convert luma, orange-blue chrominance, and purple-green chrominance to RGB values. (LICENSE:PD)
SYNOPSIS
   subroutine yiqrgb(y,i,q,r,g,b,status)

    real,intent(in)  :: y,i,q
    real,intent(out) :: r,g,b
    integer          :: status
   
DESCRIPTION
Convert luma, orange-blue chrominance, and purple-green chrominance to RGB values.
AUTHOR
John S. Urban
LICENSE
Public Domain
NAME
RGBYIQ(3fp) - [M_color] Convert RGB values to luma, orange-blue chrominance, and purple-green chrominance. (LICENSE:PD)
SYNOPSIS
   subroutine rgbyiq(r,g,b,y,i,q,status)

    real,intent(in)  :: r,g,b
    real,intent(out) :: y,i,q
    integer          :: status
   
DESCRIPTION
Convert RGB values to luma, orange-blue chrominance, and purple-green chrominance.
AUTHOR
John S. Urban
LICENSE
Public Domain